• <acronym id="danlv"><form id="danlv"></form></acronym>
  • <dd id="danlv"><rt id="danlv"></rt></dd>
      <var id="danlv"><rt id="danlv"><big id="danlv"></big></rt></var>
      1. <code id="danlv"><ol id="danlv"></ol></code>
        <var id="danlv"><rt id="danlv"></rt></var>
          1. <code id="danlv"></code>
            返回首頁
            當前位置: 主頁 > 網絡編程 > Jsp實例教程 >

            Java中的數據比較(再談==與equals的區別)

            時間:2012-10-22 00:38來源:知行網www.n1979.com 編輯:麥田守望者

            Java中的變量與對象有區別嗎?

            引子:變量與對象
            變量是Java中最基本的存儲單元,為變量賦值可以使用賦值表達式。如:

            int i = 10;
            int i = 10;

            該表達式的含義是將一個字面量(literal)10賦值給一個類型為int型的變量,變量名為i。這是一個為基本數據類型的變量賦值的例子,它表達了一個非常樸素的信息,那就是變量i的值為10。
            那么這種賦值表達式引申到引用類型的變量時,其含義又有什么變化呢?再看一個賦值表達式:

            String str = null;
            String str = null;

            該表達式的含義是將空內存地址(null)賦值給String類型的變量,變量名為str。樸素的說法是變量str的值為null。對于引用類型的變量而言,賦值操作只是將對象的內存地址保存到變量中。也就是說引用類型的變量值是對象的內存地址而不是對象的內容。如下例:

            String str1 = "abc";
            String str2 = new String("abc");
            String str1 = "abc";
            String str2 = new String("abc");

            上述兩種賦值操作本質上沒有任何區別,最大的區別是生成對象的方法不同(這一點與賦值操作無關)。對于變量而言,其值仍然是所指對象的內存地址。

            相對于變量,對象也是存儲單元的一種。對象有自己的屬性與方法,其內容的表現形式由實例化該對象所用的類決定。如:

            new java.sql.Time(0L);
            new java.sql.Time(0L);

            要使用對象,必須將對象的內存地址指定到一個引用類型的變量中(也就是變量的賦值操作)。該變量的類型可以與對象的類型一致,也可以是對象類型的父類,或者是對象類型實現的接口。后兩種是典型的多態應用。如:

            java.util.Date date = new java.sql.Time(0L);
            java.util.Date date = new java.sql.Time(0L);

            當然,我們只能通過變量去調用對象的方法或者設置對象的屬性,其作用無非是取得或者修改對象的內容。如:

            java.util.Date date = new java.sql.Time(0L);
            date.setTime(3600000L);
            System.out.println(date.toString());
            java.util.Date date = new java.sql.Time(0L);
            date.setTime(3600000L);
            System.out.println(date.toString());

            注意,變量的內涵只有一個,就是它的值。我們通過變量調用對象的方法時,可以改變的也只是對象的內容。區分變量與對象是很有必要的,當我們討論變量時總是與它們的值有關;當我們討論對象時更多的是在討論如何取得或修改它們的內容。記住:

            變量的值只能通過賦值表達式來改變;對象的內容只能通過自身的方法或屬性來改變。

            變量值的比較
            當我們討論變量之間是否相等時,通常使用“==”關系運算符。如:

            int i = 10;
            int j = 20;
            if (i == j) {
            System.out.println("兩個變量的值相等");
            }
            int i = 10;
            int j = 20;
            if (i == j) {
            System.out.println("兩個變量的值相等");
            }

            上例是基本數據類型之間的比較,本質上是變量之間值的比較。對于兩個引用變量的比較,如:

            String str1 = "abc";
            String str2 = new String("abc");
            if (str1 == str2) {
            // 判斷無法成立,因為兩個變量所指對象的內存地址不同。
            System.out.println("兩個變量的值相等");
            }
            String str1 = "abc";
            String str2 = new String("abc");
            if (str1 == str2) {
            // 判斷無法成立,因為兩個變量所指對象的內存地址不同。
            System.out.println("兩個變量的值相等");
            }

            本質上引用類型的變量之間的比較也是值的比較,也就是內存地址的比較。上例不會打印出“兩個變量的值相等”,因為兩個變量指向了不同內存地址的對象。

            對象內容的比較
            對于引用變量而言,如果我們不想僅限于對內存地址的比較,而是想做更深層次的(比如對象的內容)比較。如何實現呢?Java的Object類提供了equals方法,此方法實現了對象之間內容上的比較。由于Object類是所有Java類的父類,所以我們只要在自己的類中改寫equals方法,就可實現該類對象之間的內容比較。如:

            String str1 = "abc";
            String str2 = new String("abc");
            if (str1.equals(str2)) {
            // 判斷成立,因為兩個對象的內容都是"abc"。
            System.out.println("兩個對象的內容相等");
            }
            String str1 = "abc";
            String str2 = new String("abc");
            if (str1.equals(str2)) {
            // 判斷成立,因為兩個對象的內容都是"abc"。
            System.out.println("兩個對象的內容相等");
            }

            關于如何改寫equals方法以及與之相關的hashCode方法,可以參考潘愛民翻譯的《Effective Java中文版》一文中第7條:在改寫equals的時候請遵守通用約定 以及 第8條:改寫equals時總是要改寫hashCode。

            老生常談:==與equals的區別
            對于Java初學者而言,==與equals是容易混淆的。當然區分它們也是簡單的,只要記住:

            ==只針對變量的值;equals只針對對象的內容。

            記住上句話的同時,請記住下面的一句話:

            引用類型的變量值是所指對象的內存地址。

            附1:Java函數調用中,參數的傳遞方式只有一種:值傳遞
            關于值傳遞的定論,網上有許多許多例子可以證明。這里也舉個例子:

            view plaincopy to clipboardprint?
            public class Test {

            public static void main(String[] args){
            java.util.Date date = new java.util.Date(0);

            System.out.println(date);
            change(date);
            System.out.println(date);
            }

            public static void change(java.util.Date date) {
            // 此處改變了參數(變量)的值
            date = new java.util.Date(3600000L);
            System.out.println(date);
            }
            }
            public class Test {

            public static void main(String[] args){
            java.util.Date date = new java.util.Date(0);

            System.out.println(date);
            change(date);
            System.out.println(date);
            }

            public static void change(java.util.Date date) {
            // 此處改變了參數(變量)的值
            date = new java.util.Date(3600000L);
            System.out.println(date);
            }
            }

            上例的輸出結果是:

            Thu Jan 01 08:00:00 CST 1970
            Thu Jan 01 09:00:00 CST 1970
            Thu Jan 01 08:00:00 CST 1970
            我們稍微改動一下內容:

            view plaincopy to clipboardprint?
            public class Test {

            public static void main(String[] args){
            java.util.Date date = new java.util.Date(0L);

            System.out.println(date);
            change(date);
            System.out.println(date);
            }

            public static void change(java.util.Date date) {
            // 此處改變了對象的內容
            date.setTime(3600000L);
            System.out.println(date);
            }
            }
            public class Test {

            public static void main(String[] args){
            java.util.Date date = new java.util.Date(0L);

            System.out.println(date);
            change(date);
            System.out.println(date);
            }

            public static void change(java.util.Date date) {
            // 此處改變了對象的內容
            date.setTime(3600000L);
            System.out.println(date);
            }
            }

            上例的輸出結果是:

            Thu Jan 01 08:00:00 CST 1970
            Thu Jan 01 09:00:00 CST 1970
            Thu Jan 01 09:00:00 CST 1970
            通過這兩個例子可以證明什么呢?
            當函數調用時,JVM會生成第二個引用類型的變量,并將原始引用變量的值(對象的內存地址)復制給第二個引用變量。 注意,值傳遞的本質是變量值的復制而不是對象內容的復制。
            第一個例子中,函數內部改變的是第二個引用變量的值,原始引用變量的值沒有改變。第二個例子中,函數內部改變的是引用變量所指對象的內容,由于原始引用變量與第二個引用變量的值相等(指向同一個對象),所以導致了函數調用后對象的內容已經改變的事實。

            附2:關鍵字final只作用于變量的值,不作用于對象的內容。
            關鍵字final的作用是變量只能賦值一次。舉個例子:

            final int i = 10;
            i = 20; // 編譯時報錯
            final int i = 10;
            i = 20; // 編譯時報錯

            但只能賦值一次的限制只作用于變量的值,而不是對象的內容。如:

            final java.util.Date date = new java.util.Date(0L);
            date.setTime(3600000L); // 編譯可以通過,并且運行正常。
            final java.util.Date date = new java.util.Date(0L);
            date.setTime(3600000L); // 編譯可以通過,并且運行正常。

            如此引來了另一個問題,如何定義常量。
            定義一個常量,首先要做到使用關鍵字final對變量進行限制。但這樣做只限制了變量的值,如果變量的類型是引用類型時,還必須保證該對象是一個值對象(value objects)。換言之值對象的類必須是一個不可變類(immutable classes)。
            String類就是一個不可變類,我們可以用String類直接定義常量。而java.util.Date類可以通過自身的方法改變其內容,所以不能用這種類型定義常量。如:

            ------分隔線----------------------------
            標簽(Tag):Java JAVA實例教程 JAVA基礎教程 Java源代碼 Java技巧
            ------分隔線----------------------------
            推薦內容
            猜你感興趣
            日韩在线av免费视久久