摘要:,變量里存的是什么在規范中,對于有這么一句話一個可以是一個類的實例或者是一個數組一個數組其實是一個,不過這是另一個話題了。由于的設計是不可變的,在一個實例上的任何增刪操作都會產生一個新的實例,效果與重新為變量設定新的引用值是一樣的。
考慮下面這個例子:
Long l1 = 1L; Long l2 = 2L; Long l3 = 3L; long l4 = 3L; Long l5 = 1 + 2L; System.out.println(l3 == 3); System.out.println(l4 == 3); System.out.println(l3.equals(3)); System.out.println(l3.equals(l4)); System.out.println(l3.equals(l5));
輸出的結果是
true true false true true
相信這個例子很多初學者都犯過迷糊:l3、l4 不都是 3 嗎,怎么 l3.equals(3) 是 false 呢。
這里面有很多點可以講的,我們一個一個來看:
Long 和 long在 Java 里只有兩種類型: primitive types 原始類型 和 reference types 引用類型。
null 是一種特殊的類型
規范說明:4.1. The Kinds of Types and Values
原始類型里包括:boolean、byte、short、int、long、char、float、double;
引用類型有四種:class、interface、type、array (其中 type 我們平時遇到過的就是泛型 T,詳細內容可以查閱規范 4.4. Type Variables)
所以這里,long 是原始類型,Long 是引用類型,這很重要,是接下來討論的基礎。
Boxing Conversion 和 Unboxing Conversion其實這個就是拆箱裝箱,這個知識點應該不陌生吧,就是 Java 會自動幫你把原始數值類型和原始浮點類型轉換為對應的引用類型,如 long 轉換為 Long。
舉個栗子:
public void func(Long l) { System.out.println(l); } func(1L);
這段代碼是可以跑起來的,但是如果調用時是這樣的 func(1),那么就會報錯,因為 1 是整數型,它即便自動裝箱也是 Integer 而不是 Long。
Objects,變量里存的是什么在規范中,對于 Obejct 有這么一句話:
An object is a class instance or an array.
一個 Object 可以是一個類的實例或者是一個數組 (一個數組其實是一個 Object,不過這是另一個話題了。)
The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object.
引用值(通常是引用)是指向這些對象的指針和一個特殊的null引用,它不引用任何對象。
有些學過 C++ 的或是有 引用 這個概念的其他語言的同學,可能在這里要犯迷糊了:不是說 Java 里沒有引用嗎,怎么規范里又提到這個詞了。
注意,C 里面沒有引用只有指針,它跟 Java 一樣是值傳遞的。
其實可以這么不嚴謹地認為:C++ 里的 引用 是動詞,Java 里的 引用 是名詞。
C++ 里的引用是對一個變量定義一個別名:
int a = 2, int &ra = a; // a為目標原名稱,ra為目標引用名。給ra賦值:ra = 1; 等價于 a = 1;
C++ 引用
Java 里的引用就是一個值,一個指向 對象 的值。
public static void func(String s) { s = "bar"; } String s1 = "foo"; func(s1); System.out.println(s1); // "foo"
在這里,s1 的值并不是 foo,而是一個指向 其字段value值為 ["f", "o", "o"]的 String 實例 的引用。
比如說,再聲明一個 String s2 = "foo";,然后在 func(s1); 處下斷點,可以看到:
可以看到,String{@xxx} 和 value:byte[]{@xxx} 都是一樣的,因為它們就是同一個對象,s1 和 s2 這兩個變量的值是 指向了同一個對象(String{@674})的引用。
如果我們在 func(String s) 里打斷點,會發現在 func(s1) 的情況下,s 和 s1 的 引用值 是一樣的。
因為 Java 是值傳遞,只不過在引用類型的情況下,傳遞的這個值,就是 引用值。
當 func 內部對這個 s 進行操作后,我們再來看看func內部斷點的情況:
public static void func(String s) { s = "bar"; // 斷點處,此時 s 的引用值已經變為 String{@674} // 即此時的 s 的引用值已經不再是 s1 的引用值,自此它們已經指向的是不同的對象了。 }
由于 String 的設計是不可變的,在一個 String 實例上的任何增刪操作都會產生一個新的 String 實例,效果與重新為變量設定新的引用值是一樣的。
我們再看看一個原始類型的斷點情況:
int i = 0;
對于原始類型的變量而言,它們的值就是本身。
==和 equals== 操作符在規范里其實分了三種情況:
15.21.1. Numerical Equality Operators == and !=
15.21.2. Boolean Equality Operators == and !=
15.21.3. Reference Equality Operators == and !=
equals 是 Object 的方法,但是任何類都可以覆寫這個方法來實現自定義的實例間判斷,比如 Long.equals 就改成了這個樣子:
/** * Compares this object to the specified object. The result is * {@code true} if and only if the argument is not * {@code null} and is a {@code Long} object that * contains the same {@code long} value as this object. * * @param obj the object to compare with. * @return {@code true} if the objects are the same; * {@code false} otherwise. */ public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue(); } return false; }
也就是說,只要待判定對象不是 Long 或其子類,那么就直接返回 false。
結合前邊講的 int 在方法調用時會被自動裝箱成 Integer(如果參數不顯式要求 int 類型),很顯然,l3.equals(3) 會直接因為 Integer 3 不是 Long 而返回 false。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68602.html
摘要:如線程執行后,線程執行,相當于線程向線程發送了消息。我們可以利用這種互斥性來進行線程間通信。 你是否真正理解并會用volatile, synchronized, final進行線程間通信呢,如果你不能回答下面的幾個問題,那就說明你并沒有真正的理解: 對volatile變量的操作一定具有原子性嗎? synchronized所謂的加鎖,鎖住的是什么? final定義的變量不變的到底是什么...
摘要:文章目錄一數據類型二整型在內存中的存儲原碼反碼補碼大小端三例題練習一數據類型在語言中有整型浮點型構造類型指針類型等。正數的原反補碼都相同對于整形來說數據在內存中存放的都是補碼。 ...
摘要:入門的導語廢話最近兩年你要說函數式編程不火的話那是不可能的是人都知道函數式編程很火為什么函數式編程會火呢在于它的思想很強大很強勢尤其是前端的更是在上完全使用純函數函數式的好處漸漸被發掘出來筆者最近看了一些函數式方面的東東現在發出來給大家學習 0x00 入門的導語(廢話) 最近兩年你要說函數式編程不火的話, 那是不可能的, 是人都知道函數式編程很火.為什么函數式編程會火呢, 在于它的思想...
閱讀 2976·2023-04-26 02:25
閱讀 2249·2023-04-25 18:05
閱讀 647·2021-09-30 09:57
閱讀 2943·2021-09-27 14:10
閱讀 1652·2019-08-30 15:44
閱讀 1003·2019-08-29 15:28
閱讀 2524·2019-08-29 14:10
閱讀 2263·2019-08-29 13:30