伊莉討論區

標題: 一些Java(Android)問題請益 [打印本頁]

作者: RainieYang    時間: 2018-10-24 09:21 AM     標題: 一些Java(Android)問題請益

本帖最後由 RainieYang 於 2018-10-24 05:56 PM 編輯

1.關於 String ,小弟知道他實作了 CharSequence介面, 但toString並沒有實作,去看CharSequence原始碼看到下面這段:
  1. /**
  2.      * Returns a string containing the characters in this sequence in the same
  3.      * order as this sequence.  The length of the string will be the length of
  4.      * this sequence.
  5.      *
  6.      * @return  a string consisting of exactly this sequence of characters
  7.      */
  8.     public String toString();
複製代碼

這樣我不知道算是有實作還是沒實作?
但如果有實作,卻看不到進一步的實作程式碼,這讓小弟有點困惑。
String的toString method(), 或應該說, CharSequence的 toString method() 到底被實作在哪呢?
---------------------------------------------------------------------------------------------------------
補充及更正,小弟自己繼續研究的發現及推測:
String 實作了 CharSequence, 然後String 是有自己實作toString的,小弟的問題說toString沒有在String被實作說錯了,他是有的,方法內直接返回本身 (return this)

但繼續實驗觀察會發現一些有趣的現象:
小弟自己建一個class去實作 CharSequence,結果發現,他強迫你實作的method 一共只有3個(不含toString),他沒有強制要求你實作toString,可是這就奇怪啦,因為CharSequence裡toString並沒有實作,所以應該要被implent他的class實作出來才對,為什麼你不實作是可以被接受的呢?
最後小弟自己做了一些實驗,得出一個推測,因為任何class均繼承Object,所以就算你沒定義toString,你的class依然有toString方法(來自Object),所以他就當作你已經實作toString了... 不會再強迫要求你要實作toString...
這是小弟經過實驗得出的推測。
但這其中還有奇怪的地方是,既然任何class都一定有toString方法,也就是任何class必然已實作toString,那CharSequence的toString介面豈不是形同虛設?  反正一定會被實作出來...

對此有人有任何看法嗎?  小弟猜測這是一個失誤?  Java官方那時實作此介面,希望開發者必須實作toString來將字符串轉成等價的String,但卻沒想到任何class因為已繼承Object,所以必然有toString方法,也就是可以根本不用甩CharSequence提供的toString介面。

此外還有個神奇的小現象,就是當我自己繼承CharSequence後,還是去覆寫toString(當然不覆寫也行,會沿用Object.toString),結果上方跳提醒,希望我加上@NonNull,但是我去檢查不論CharSequence還是Object的toString都沒有@NonNull字樣,那為什麼繼承後卻建議我加上呢?







作者: kwj    時間: 2018-10-24 11:46 PM

本帖最後由 kwj 於 2018-10-25 12:04 AM 編輯

不認為那是一個失誤,個人認為比較正確的說法應該是「那是一個提示」。Interface 需要被實作時,跑出來要求三個 method 被實作,那是 IDE 幫你產生的。至於為什麼他要跑出本來其實不需要跑出的 toString(),從另一個角度來思考,如果他沒有跑出來的話,那會有多少開發者沒有意識到他可以實作或者覆寫 toString() 呢?

「提示」對供人使用的函式庫是很重要的,讓使用者知道他可以選擇實作或者不實作,然後他再依照自己的狀況去決定。如果沒有任何提示,在像 Java 這麼龐大的架構底下,使用者很有可能沒有能力發現他其實有選擇的權力。

雖然你現在可以認真去看 CharSequence 和 String 的原始碼,但你花了多少時間看呢?你要花多少時間能看完所有 Java 原生的 class 呢?如果你用到 Spring Framework,你又要繼續把 Spring Framework 的原始碼全部讀完嗎?那得花掉你多少時間?那 Java EE 呢?Android 呢?實務上你不可能讀完所有的原始碼,最終你總會進入在非必要的時候(實際上是你職涯裡至少 9 成以上的狀況)僅依靠 IDE 的提示和官方文件來寫程式碼的狀況,這時這些「提示」有沒有出現來告訴你你能做哪些選擇,對你就很重要了。

@NonNull 的問題應該要討論 Android 設置這個的目的為何。Object、CharSequence 和 String 都是 Java 原生的 class,但 @NonNull 是 Android 專屬的。Android 的函式庫是在基於 Java 既有函式庫之上,再追加其他 Android 使用的東西的,所以理所當然不會在 Object 等處找到後來才被加上的 @NonNull,因為他們根本不是同個來源。
作者: RainieYang    時間: 2018-10-25 09:17 AM

kwj 發表於 2018-10-24 11:46 PM
不認為那是一個失誤,個人認為比較正確的說法應該是「那是一個提示」。Interface 需要被實作時,跑出來要求 ...

恩恩,謝謝大大的回答,不過IDE其實沒有跑出toString,但是原本CharSequence的確有toString的介面,我猜測IDE沒有主動跑出toString是因為任何class都有toString(來自Object),所以自動實作了,但這樣CharSequence提供這個介面要求開發者去實作就沒意義了(因為沒有約束力,甚至不會有提示)
另外@NonNull 是Android才有的東西這我沒有研究~ 這樣一來就說得通了,Android對原生java library有動什麼手腳我就不知道了呢~
作者: kwj    時間: 2018-10-25 09:44 AM

本帖最後由 kwj 於 2018-10-25 09:45 AM 編輯

個人的想法還是一樣,在 CharSequence 上有 toString() 是為了提示開發者有可能有必要實作它。

如果 IDE 沒有自動跑出來,那我認為問題應該是問「為什麼 IDE 沒有跑出提示」,而不是問「為什麼 CharSequence 需要提供 toString() 介面」。

另外,從 CharSequence 的文件中也可以看到以下的描述:
This interface does not refine the general contracts of the equals and hashCode methods. The result of comparing two objects that implement CharSequence is therefore, in general, undefined. Each object may be implemented by a different class, and there is no guarantee that each class will be capable of testing its instances for equality with those of the other. It is therefore inappropriate to use arbitrary CharSequence instances as elements in a set or as keys in a map.

在介面上寫了 toString(),理論上 IDE 會自動跑出需要實作的 method,javadoc 上也可以看到這個介面需要實作 toString(),對於要實作這個介面的開發者來說,就能夠了解到他的選擇;而對於要使用別人開發的實作的人,則會了解到實作有可能有自己的 toString() 的獨特作法。反之,對於 CharSequence 沒有特別寫出的 equals() 和 hashCode(),就會如文件所說,因為介面本身並不提示開發者進行實作,因此很有可能對於實作的 class 來說,equals() 和 hashCode() 並不能有如預期的反應。

PS. 這裡指的預期並非是預期繼承 Object 的行為,而是根據實作該有的預期。例如對於 StringBuilder 來說,equals() 預期應該是比較兩個 StringBuilder 物件是否在記憶體上是同一個,還是預期應該是比較兩個 StringBuilder 目前的字串內容相等呢?
作者: kwj    時間: 2018-10-25 09:56 AM

另外修正一下前面的錯誤,本來 @NonNull 這樣的 Annotation 是出現在包含 Android、Spring 等非原生 Java 的函式庫中,不過在 Java 8 中已經被引入成為標準函式庫的一部分了(https://blogs.oracle.com/java-pl ... ew-type-annotations)。

不過因為這個玩意兒的出現,是基於 Java 8 以前的一大段關於 Null 的亂戰,所以即使出現了也沒有去把過去所有的 class 都更新,個人認為應該還算是可以接受。畢竟因為 Java 8 為了 Null 的問題做了幾個重大的概念變更,這些概念如果完全落實到所有的 class 的話,極有可能會導致世界上眾多老舊的 Java 系統或程式都無法升級 Java 8。
作者: RainieYang    時間: 2018-10-25 11:22 AM

本帖最後由 RainieYang 於 2018-10-25 11:23 AM 編輯
kwj 發表於 2018-10-25 09:56 AM
另外修正一下前面的錯誤,本來 @NonNull 這樣的 Annotation 是出現在包含 Android、Spring 等非原生 Java  ...

嗯嗯,感謝大大的解答~  
作者: codewice    時間: 2018-10-26 01:34 AM

在 Object 的 toString 敘述是「取得一個能夠描述這個物件的、人類看得懂的字串」

    Returns a string containing a concise, human-readable description of this object.

在 CharSequence 的 toString 敘述是「取得一個字串,其中字元的排列順序跟原來的 CharSequence 相同」

    Returns a string with the same characters in the same order as in this sequence.

從語法的角度來看,的確不用改寫就能夠編譯通過並且執行。但是從語義的角度來看,不改寫 toString() 而沿用 Object.toString() 的話,這樣的程式有 bug

也就是說,CharSequence interface 不但定義了方法的介面,同時還規定了實作者該要有的責任。這個責任,編譯器沒有辦法幫你完成。
作者: RainieYang    時間: 2018-10-30 09:30 PM

codewice 發表於 2018-10-26 01:34 AM
在 Object 的 toString 敘述是「取得一個能夠描述這個物件的、人類看得懂的字串」

    Returns a string c ...

這位大大一語點醒夢中人啊,其實我看到後來也隱隱有這種想法,我想假設我的推測沒錯的話,那個interface的確只剩這個作用了,但看到有人也提出相同的看法更是堅定了我的信心啊~




歡迎光臨 伊莉討論區 (http://a401.file-static.com/) Powered by Discuz!