作者:金良

1.引用类型和基本类型

Java中数据类型分为两大类,是基本类型和对象类型。相应的,变量也就有两种类型:基本类型和引用类型。

基本类型的值就是一个数字,一个字符或一个布尔值。引用类型,是一个对象类型的啊,它的值是指向内存空间的引用,就是地址,所指向的内存中保存着变量所表示的一个值或一组值。

Java的基本数据类型如下表所示,其余的都是对象类型,如String类型、Integer类型、数组类型等。


java引用传值 java值传递与引用类型传递_赋值

变量的基本类型和引用类型的区别:

基本数据类型在声明时系统就给它分配空间。

举个例子:

1. int a;  
2. a=10;//正确,因为声明a时就分配了空间

而引用与之不同,它声明时只给变量分配了引用空间,而不分配数据空间。

举个例子:

1. MyDate today;  
2. today.day = 4; //发生错误,因为today对象的数据空间未分配。

 那我们怎么给它赋值啊?引用类型变量在声明后必须通过实例化开辟数据空间,才能对变量所指向的对象进行访问。举个例子:

1. MyDate today;            //将变量分配一个保存引用的空间  
2. today = new MyDate();     //执行new MyDate(),给today变量开辟数据空间,然后把空间的首地址传给today变量  
3. today.day = 4;//正确,执行赋值操作,

引用类型变量的赋值过程图解如下:

这是赋值过程的代码:

1. MyDate a,b;        //在内存开辟两个引用空间  
2. a  =  new MyDate();//开辟MyDate对象的数据空间,并把该空间的首地址赋给a  
3. b  =  a;           //将a存储空间中的地址写到b的存储空间中

这是赋值过程的图示:


java引用传值 java值传递与引用类型传递_java_02


2.引用传递 和 值传递

引用类型:除了在函数传值的时候是"引用传递",在任何用"="向对象变量赋值的时候都是"引用传递"。

值传递:基本类型的传递都属于值传递,和C语言一样,当把Java的基本数据类型(如int,char,double等)作为入口参数传给函数体的时候,传入的参数在函数体内部变成了局部变量,这个局部变量是输入参数的一个拷贝,所有的函数体内部的操作都是针对这个拷贝的操作,函数执行结束后,这个局部变量也就完成了它的使命,它影响不到作为输入参数的变量。这种方式的参数传递被称为"值传递"。

引用传递举例(注释有分析):

    1. package bupt.xujinliang.mydatatest;  
    2. /**
    3.  * 
    4.  * @author jin
    5.  *
    6.  */  
    7. class MyDate {  
    8.     String  Year;  
    9.     String  Month;  
    10.     String  Day;  
    11.     String  Date;  
    12. public MyDate(){  
    13. "2014";  
    14. "06";  
    15. "14";  
    16. "." + Month + "."+ Day;  
    17.     }  
    18. public String toString(){  
    19. return Date;  
    20.     }      
    21. }  
    22. public class MyDateTest {  
    23. new MyDate();//new一个对象,开辟数据空间  
    24. // 赋值语句,使 mydate1和 mydate2将指向同一内存空间   
    25. new MyDate();//重新new一个对象,则mydate3和mydate1是指向不同的内存空间的:  
    26.          
    27. public void changeDate(MyDate mydate){   
    28. "2014.09.26";  
    29.         }  
    30.              
    31. public static void main(String[] args) {  
    32. new MyDateTest();  
    33. "Before call changeDate() method: ");  
    34. "\tmydate1: " + mydatetest.mydate1);  
    35. "\tmydate2: " + mydatetest.mydate2);  
    36. "\tmydate3: " + mydatetest.mydate3);  
    37.               
    38.             mydatetest.changeDate(mydatetest.mydate1);  
    39.               
    40. "After call changeDate() method: ");  
    41. "\tmydate1: " + mydatetest.mydate1);  
    42. "\tmydate2: " + mydatetest.mydate2);//赋值语句,二者将指向同一内存空间  
    43. "\tmydate2: " + mydatetest.mydate3);//与前者不指向同一内存空间  
    44.         }  
    45. }

    上述程序的输出:

    java引用传值 java值传递与引用类型传递_java_03


    3.“==”和equals()

    了解了前边所讲的基本数据类型和引用类型的概念,下面讲下Java中“==”和equals的区别。

    二者对比如下:

    java引用传值 java值传递与引用类型传递_赋值_04

    上面的列表中的引用数据类型需要注意一下,引用数据类型可以指8种基本数据类型以外的所有类,所以它是无限的,在Java API中出现的类中的绝大部分都重写了equals()方法,都满足表中引用数据类型的要求;不过当你写了一个自己的类,默认情况下是没有重写equals()方法的,这种情况稍后会讲到。

    代码:

      1. package bupt.xujinliang.equalsexample;  
      2. /**
      3.  * 
      4.  * @author jin
      5.  *
      6.  */  
      7. public class EqualsExample {  
      8. public static void main(String[] args) {  
      9. new Integer(5);  
      10. new Integer(15);  
      11. new Integer(5);  
      12.         Integer obj4 = obj2;  
      13. "obj1.equals(obj1):\t"+obj1.equals(obj1));//true  
      14. "obj1.equals(obj2):\t"+obj1.equals(obj2));//false  
      15. "obj1.equals(obj3):\t"+obj1.equals(obj3));//true  
      16. "obj2.equals(obj4):\t"+obj2.equals(obj4));//true  
      17. "----------------------------------");  
      18. "obj1==obj1:\t"+(obj1==obj1));//true  
      19. "obj1==obj2:\t"+(obj1==obj2));//false  
      20. "obj1==obj3:\t"+(obj1==obj3));//false  
      21. "obj2==obj4:\t"+(obj2==obj4));//true  
      22.     }  
      23. }

      运行效果:

      java引用传值 java值传递与引用类型传递_java引用传值_05

      但是,对于一般的Object类,或者用户自己写的Java类,默认其equals()方法就是采用==进行比较的,所以二者等效为同一个对象为真,否则为假。那么为什么上述的引用变量类型Integer的equals()方法和==不等效呢,因为它重写了equals方法,所以才有上述代码的运行结果。

      这面的类没有重写equals()方法:

      1. package bupt.xujinliang.equalsobject;  
      2. /**
      3.  * 
      4.  * @author jin
      5.  *
      6.  */  
      7. class MyObject {  
      8. int num;  
      9. int num) {  
      10. this.num = num;  
      11.     }  
      12. }  
      13.   
      14. public class EqualsObject {   
      15. public static void main(String[] args) {  
      16. new MyObject(5);  
      17. new MyObject(15);  
      18. new MyObject(5);  
      19.         MyObject myobj4 = myobj1;  
      20.         MyObject myobj5 = myobj2;  
      21.         MyObject myobj6 = myobj3;  
      22.           
      23. "myobj1.equals(myobj1):\t"+myobj1.equals(myobj1));//true  
      24. "myobj1.equals(myobj2):\t"+myobj1.equals(myobj2));//false  
      25. "myobj1.equals(myobj3):\t"+myobj1.equals(myobj3));//false  
      26. "myobj2.equals(myobj4):\t"+myobj2.equals(myobj4));//false  
      27. "----------------------------------");  
      28. "myobj1==myobj1:\t"+(myobj1==myobj1));//true  
      29. "myobj1==myobj2:\t"+(myobj1==myobj2));//false  
      30. "myobj1==myobj3:\t"+(myobj1==myobj3));//false  
      31. "myobj2==myobj4:\t"+(myobj2==myobj4));//false  
      32.     }  
      33. }
      1.  

      上述代码的运行结果如下图所示,可以看到用equals()方法和==是等效的。

      java引用传值 java值传递与引用类型传递_java引用传值_06

      下面我们对MyObject类的equals()方法做如下重写:

        1. public boolean equals(Object obj) {  
        2. if(this == obj)//如果是同一个实例,则相等  
        3. return true;  
        4. if(null == obj) //如果obj为空,则不相等  
        5. return false;  
        6. if(getClass() != obj.getClass()) //如果类型不同,则不相等  
        7. return false;  
        8.     MyObject other = (MyObject)obj;  
        9. if(num == other.num) //当类仅有的整型成员变量相等时,相等  
        10. return true;  
        11. return false;  
        12.       
        13. }

        重新运行程序,则结果如下所示:

        java引用传值 java值传递与引用类型传递_java_07