on java 8 学习笔记 2022.2.16
2022.2.16
問(wèn)題
其實(shí)我感覺引用計(jì)數(shù)的方法不只書中提到的這種問(wèn)題吧,難道不會(huì)有對(duì)象被誤刪的情況嗎?
答:不會(huì),因?yàn)檫@種方法就是參考了只要有引用,它就是有效對(duì)象的路子,而只要引用大于0,那它就是有效對(duì)象,
這種初始化方法簡(jiǎn)單明了,但有個(gè)限制:類InitialValues的每個(gè)對(duì)象都會(huì)有相同的初始值。有時(shí)候這正是你想要的,但有時(shí)你可能需要更大的靈活性。
看不懂,啥意思?我覺得已經(jīng)挺靈活的了
答:看了6.7,感覺用構(gòu)造器初始化不就是我們正常的操作嗎?秀了我一臉懵逼,這有啥好靈不靈活的
答:應(yīng)該是這么寫的話,就相當(dāng)于直接賦初始值,而構(gòu)造器靈活的地方可能在于它是方法賦值,可以多樣化賦值,雖然我還是很難說(shuō)服自己
getClass()方法是Object的一部分,將在第19章中進(jìn)行全面探討。它會(huì)生成一個(gè)對(duì)象的類,當(dāng)打印這個(gè)類時(shí),你會(huì)看到一個(gè)表示該類類型的編碼字符串。前導(dǎo)的[表示這是后面緊隨的類型的數(shù)組。I表示基本類型int。為了再次確認(rèn),我在最后一行創(chuàng)建了一個(gè)int數(shù)組并打印了它的類型。這證實(shí)了使用可變參數(shù)列表不依賴于自動(dòng)裝箱,這個(gè)示例實(shí)際上用的就是基本類型。
這最后我是沒看懂的,我覺得根本不會(huì)有這個(gè)誤區(qū),事實(shí)上,我都不知道為什么會(huì)有人認(rèn)為他會(huì)被包裝,因?yàn)槟銋?shù)列表都是int,你給我裝啥?
答:這里有點(diǎn)繞,其實(shí)是因?yàn)樽髡咛崆拜斄?,0到里面去,然后程序輸出的類型是I,可能有讀者腦子沒扭過(guò)來(lái),因?yàn)檫@里可能是包裝類,也可能是基本數(shù)據(jù)類型,所以作者又new了一個(gè)int數(shù)組進(jìn)去,這樣就可以確定了,因?yàn)閿?shù)組是基本數(shù)據(jù)類型的,又是列表的一種,所以它的數(shù)據(jù)類型不應(yīng)該變動(dòng)
以前,你需要?jiǎng)?chuàng)建一組整型常量值,但它并沒有自然地將取值范圍限制在這個(gè)集合中,因此風(fēng)險(xiǎn)更大且更難使用。
我……………這又是個(gè)啥意思,啥時(shí)候的枚舉類型,我從來(lái)沒用過(guò),沒經(jīng)驗(yàn)啊wc
第六章 初始化和清理
一些更快的方案并不使用引用計(jì)數(shù),而是基于這樣一個(gè)想法:對(duì)于任何沒有被廢棄的對(duì)象,最終都能追溯到它存活在棧或靜態(tài)存儲(chǔ)區(qū)中的引用。這個(gè)引用鏈可能會(huì)穿過(guò)多個(gè)對(duì)象層次。因此,如果從棧和靜態(tài)存儲(chǔ)區(qū)開始遍歷所有引用,就能找到所有存活的對(duì)象。對(duì)找到的每個(gè)引用,還要跟蹤它指向的對(duì)象,然后跟蹤那個(gè)對(duì)象中的所有引用,依次反復(fù)進(jìn)行,直到找到了源于這個(gè)(位于棧或靜態(tài)存儲(chǔ)區(qū)的)引用的所有對(duì)象。在這個(gè)過(guò)程中遍歷的每個(gè)對(duì)象都必須是“活”的。注意,這樣的話,廢棄的自引用對(duì)象組就不會(huì)產(chǎn)生問(wèn)題了——它們根本不會(huì)被找到,因此自動(dòng)成為垃圾。
我看了兩遍,然后這種方法其實(shí)就是一個(gè)引用指向的對(duì)象必然不可能是廢棄對(duì)象,那么我只需要找到所有的有效引用,然后把它們的對(duì)象復(fù)制到一個(gè)新區(qū)里,那么剩下的在原區(qū)里的就一定是廢棄對(duì)象,把他們?nèi)宄司屯晔铝?/p>
在想一個(gè)問(wèn)題,按這個(gè)道理的話,是不是有引用不是在棧或者靜態(tài)存儲(chǔ)區(qū)里?如果引用都是在棧或者靜態(tài)存儲(chǔ)區(qū)的話,那么不是應(yīng)該在遍歷完棧中所有的引用以后,就可以確定存活的對(duì)象.
那么按照這個(gè)邏輯考慮的話,應(yīng)該是有引用可能存儲(chǔ)在堆中的,這樣比較符合實(shí)際的情況,之所以堆中可能存在引用,是因?yàn)槎阎械膶?duì)象里可能有引用了其他的對(duì)象
那么按照這個(gè)方向思考下去,利用棧和靜態(tài)存儲(chǔ)區(qū)的思路,就是將原來(lái)遍歷一整個(gè)堆的操作數(shù)縮小到只是遍歷其中部分對(duì)象的操作數(shù),確實(shí)很奇妙
java垃圾回收是將龐大的內(nèi)存空間分解成一個(gè)個(gè)更小單元的塊,以此盡量減少內(nèi)存空間的使用
有了塊之后,垃圾收集器就可以將對(duì)象直接復(fù)制到廢棄的塊里。
不知道為什么,我感覺這里有點(diǎn)問(wèn)題,應(yīng)該是把對(duì)象復(fù)制到新的塊中,畢竟,這種算法標(biāo)記的是存活的對(duì)象,而且,把對(duì)象復(fù)制到廢棄的塊中不合理.那些廢棄塊中的對(duì)象本身不就是要?jiǎng)h除的,所以我個(gè)人比較認(rèn)同我在其他里貼出來(lái)的博客的說(shuō)法
注意下初始化對(duì)象時(shí),對(duì)象內(nèi)部的變量編譯是在構(gòu)造器前的,至于具體是編譯時(shí)完成的還是運(yùn)行時(shí)完成的,我個(gè)人感覺是運(yùn)行時(shí)完成的.
初始化的順序是從靜態(tài)字段開始(如果它們還沒有被先前的對(duì)象創(chuàng)建觸發(fā)初始化的話),然后是非靜態(tài)字段。
如果有加載靜態(tài)方法,或者使用靜態(tài)方法的話,那么本類中的靜態(tài)對(duì)象都會(huì)被全部激活并初始化,如果還有靜態(tài)對(duì)象,靜態(tài)對(duì)象也會(huì)被初始化
為了總結(jié)對(duì)象創(chuàng)建的過(guò)程,假設(shè)有一個(gè)名為Dog的類。
注意下創(chuàng)建和初始化是兩碼事,一定要牢記這一點(diǎn),而也正是這個(gè)原因才有了在構(gòu)造器前的自動(dòng)初始化.而構(gòu)造器初始化實(shí)際上可以理解成又一次的初始化
在執(zhí)行類中的非靜態(tài)方法時(shí),代碼塊中的語(yǔ)句會(huì)先被執(zhí)行
package example;public class two { } class three extends two{int i=0;{System.out.println("heool");}public void fun(){System.out.println(new three().i);}public static void main(String[] args) {three temp = new three();temp.fun();} }其實(shí)這里可以總結(jié)一下,實(shí)際上有關(guān)于方法和構(gòu)造器初始化,因?yàn)槎邔?shí)際上都是方法,就可以看作是類的內(nèi)部變量和塊總是要先進(jìn)行,然后才是方法的運(yùn)行
這種寫法是合法的
public class DynamicArray {public static void main(String[] args) {Other.main(new String[]{ "fiddle", "de", "dum" });} }class Other {public static void main(String[] args) {for(String s : args)System.out.print(s + " ");} }注意下,字符串都是引用,可以說(shuō)java里除了基本數(shù)據(jù)類型就都是引用了,一定要記得這一點(diǎn)
還有這里直接調(diào)用main真挺有意思的
如果沒有為自己的類定義toString()方法(這將在本書后面講解),可以看到默認(rèn)行為就是打印類名和對(duì)象的地址。
很有意思,一個(gè)什么都能塞的數(shù)組,里面東西還都不一樣
還有,把Object后的換成…也是一樣的效果,我這里就不粘貼了
然后還有如果你有數(shù)組不是Object[]這樣的,你要強(qiáng)制轉(zhuǎn)化一下
這里還有一個(gè),就是繼承后再運(yùn)行時(shí)的多態(tài)現(xiàn)象,即Object,表現(xiàn)出了A的性質(zhì)
然后,因?yàn)閷W(xué)藝不精,無(wú)法理解為什么這樣子無(wú)法通過(guò)編譯
public class VarArg {static void printArray(Object[] args) {for(Object obj : args)System.out.print(obj + " ");System.out.println();}public static void main(String[] args) {printArray(new Object[]{47, (float) 3.14, 11.11});printArray(new Object[]{"one", "two", "three" });printArray(new Object[]{new A(), new A(), new A()});}class A {@Overridepublic String toString() {return "hello";}} }看了很久,這個(gè)可變參數(shù)列表貌似就是傳一個(gè)數(shù)組進(jìn)去,不過(guò)就是從本來(lái)‘’類名[]’這樣的形式換了下而已
根據(jù)經(jīng)驗(yàn),你應(yīng)該只在其中一個(gè)重載方法上使用可變參數(shù)列表,或者壓根兒就不使用它。
我為什么要看這玩意,我吐了
好吧,可變參數(shù)列表還是有很奇妙的地方的,因?yàn)槲覀儸F(xiàn)在可以這么寫了
public class OptionalTrailingArguments {static void f(int required, String... trailing) {System.out.print("required: " + required + " ");for(String s : trailing)System.out.print(s + " ");System.out.println();}public static void main(String[] args) {f(1, "one");f(2, "two", "three");f(0);} }什么意思呢?就是我們輸進(jìn)去的參數(shù)現(xiàn)在理論上可以無(wú)限多了
{WillNotCompile}注釋標(biāo)簽會(huì)把該文件排除在本書的Gradle構(gòu)建之外。
如果你手動(dòng)編譯它,就會(huì)看到如下所示的錯(cuò)誤消息:
OverloadingVarargs2.java:14: error: reference to f is ambiguous f('a', 'b'); \^ both method f(float,Character...) in OverloadingVarargs2 and method f(Character...) in OverloadingVarargs2 match 1 error如果你給這兩個(gè)方法都添加一個(gè)非可變參數(shù),就沒有問(wèn)題了:
// housekeeping/OverloadingVarargs3.javapublic class OverloadingVarargs3 { static void f(float i, Character... args) {System.out.println("first"); } static void f(char c, Character... args) {System.out.println("second"); } public static void main(String[] args) {f(1, 'a');f('a', 'b'); } } /* 輸出: first second */根據(jù)經(jīng)驗(yàn),你應(yīng)該只在其中一個(gè)重載方法上使用可變參數(shù)列表,或者壓根兒就不使用它。
這里作者有一點(diǎn)沒說(shuō)清楚,他這么操作實(shí)際上就是f()找不到對(duì)應(yīng)的方法,實(shí)際上,改成了最后一種你也找不到對(duì)應(yīng)的方法,所以我想作者的意思是,不要偷懶,沒有參數(shù)的方法如果要有,你就乖乖的寫去,不要亂整些沒用的騷操作,我重新看了遍,確定了作者應(yīng)該是寫嗨了
反正總而言之,因?yàn)槿珜懣勺儏?shù)列表會(huì)導(dǎo)致缺少默認(rèn)方法,所以盡量少寫,不過(guò)我覺得倒沒什么,雖然我不用
對(duì)于枚舉類型,實(shí)際上它的作用就是跳過(guò)了字符串,直接將字符串和數(shù)字畫上等號(hào),不過(guò)我現(xiàn)在能想到的有意思的應(yīng)用就是在一些特殊情況下,將數(shù)組下標(biāo)轉(zhuǎn)化成枚舉類型的字符串形式
public enum Spiciness {NOT, MILD, MEDIUM, HOT, FLAMING } public class SimpleEnumUse {public static void main(String[] args) {Spiciness howHot = Spiciness.MEDIUM;System.out.println(howHot);} } /* 輸出: MEDIUM */然后,枚舉類型的使用,你可以聲明對(duì)象,然后初始化對(duì)象的方式使用枚舉類型,或者你直接類似靜態(tài)變量一樣對(duì)枚舉類型內(nèi)的值進(jìn)行操作,不需要new,這個(gè)應(yīng)該是牽扯到了單例模式
一個(gè)遍歷枚舉類型的思路,可以看看
其實(shí)感覺枚舉類型有點(diǎn)像接口的靜態(tài)變量,不過(guò)有一點(diǎn)不同吧,接口的靜態(tài)變量不能像這樣直接遍歷過(guò)去
怎么說(shuō)呢,有點(diǎn)雞肋的感覺.簡(jiǎn)而言之,這個(gè)你不能在類中作為字段使用,不能作為返回值使用,不能用來(lái)聲明變量(這聲明本身就沒什么意義,都不知道要分配多少空間)
類型推斷十分適合for循環(huán):
// housekeeping/ForTypeInference.java // {NewFeature} 從JDK 11開始public class ForTypeInference { public static void main(String[] args) {for(var s : Spiciness.values())System.out.println(s); } } /* 輸出: NOT MILD MEDIUM HOT FLAMING */將類型推斷作為基本概念而創(chuàng)建的語(yǔ)言——如Kotlin和Scala——允許在任何可能有意義的地方進(jìn)行類型推斷,而Java則受到向后兼容性問(wèn)題的限制。使用這個(gè)新功能的最佳方法,可能是在任何你認(rèn)為可以的地方嘗試它,并讓編譯器或你的IDE來(lái)提示是否可以這樣用。
簡(jiǎn)單說(shuō),我能不用就不用,即便他貌似還挺好用的,不過(guò)想了想算了
其他
總結(jié)
以上是生活随笔為你收集整理的on java 8 学习笔记 2022.2.16的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: on java 8学习笔记
- 下一篇: on java 8 学习笔记 2022.