深入理解Java基础类型与引用类型

一,引入对象与引用

《Java编程思想》说到:不同于C++这种混合式语言(即支持C的面向过程,同时又支持面向对象),Java从一开始就是纯粹的面向对象的编程编程语言。Java中的一切元素都是对象。

那么Java是如何控制对象的呢?是直接控制对象本身呢?还是通过引用来间接控制对象呢?Java采用的是后者。这种方式好比电视机(对象本身)与遥控器(对象名)的关系,我们通过遥控器来控制电视机。只要我们拿着遥控器,我们就可以随意控制电视机。但是我们还要明白,电视机和遥控器二者都是可以独立存在的,并不是说有电视机(对象)就一定要有遥控器(对象名),也不是说有遥控器(对象名)就一定要有电视机(对象)。这里我有一个字符串的例子来说明:

String s;

这句话,我们定义了一个对象名(遥控器),可是并没有创建字符串对象(电视机)。一般来说,只有使用了new关键字,我们才真正创建了对象:

String s= new String("adfdsf");

通过new String(),我们创建了一个字符串对象,然后指定了名称“s”来关联这个对象。

二,对象与引用在存储上也有本质的不同

Java在运行过程中,内存中会“堆(heap)”和“栈(stack)”两个截然不同的存储空间。栈有处理器栈指针(stack pointer)的直接支持,速度非常快,同时对使用的要求也更严格,要使用栈中的空间,JAVA必须准确知道这个空间的创建和释放时间;堆的效率则相对较低,但同时要求也宽松很多,使用堆JAVA不需要知道这个空间的声明周期。

当我们在程序中执行new语句的时候,Java会在堆中开辟一个空间来存储这个对象。对象不会存储到栈空间中去,相反对象的引用则被添加到了栈空间里。比如上面的语句String s= new String("adfdsf"), new String()会在堆中开辟空间存入对象本身,String 会在栈中开辟空间存入引用名’s‘,“=”则把二者关联了起来。

对象的实现依靠了堆和栈中各自一个容器。

三,基本类型的引入

上面创建字符串的例子,帮助我们理解了JAVA面向对象的实质。可以说,对于一个纯粹的面向对象的语言设计,任务已经完成了。可是这种创建字符串的方式,几乎没有人会用,一些初学者甚至会觉得很奇怪。我们更常用的创建字符串语句应该是这样的:

扫描二维码关注公众号,回复: 3693012 查看本文章
String s="adfsdf"

这是为何呢?因为Java为Sting对象专门设计了快捷方式,大致上有两个原因:一是其他所有语言中都有字符串类型,Java语言设计时不能太标新立异,独创一种字符串类型的使用方式;二是字符串类型使用频率太高了,需要一个更高效的快捷方式。

于是,这里就引入了一个新的话题:对于几乎所有语言都支持,并且使用频率更高的整形,字符型,布尔型,如果完全用原生的面向对象的方法来实现,是不是会使得JAVA语言格格不入呢?为了解决这样的问题,JAVA设计者在这个纯粹的面向对象语言中,设计出了基本类型(primitive types)来缓和这中间的矛盾。

不同于引用类型,基本类型是栈中的一个容器来实现的。变量名与变量值都只存在于栈里,并且二者直接关联。 

  基本类型 应用类型
存储区域 类型名,类型值都存在栈中 类型名存在栈中,类型值(对象)存在堆中
名与值关联方式 直接关联 间接关联
执行效率

至此我们就清楚基本类型与引用类型本质上的不同。  

四,更好的理解我们的代码

学的最终目的还是用。我们深入研究基本类型与引用类型的差异,还是为了帮我我们更好的理解代码和写代码。下面举例数组的例子说明:

        int num=1;
        int num2=num;
        System.out.println(num);   //输出1
        num2=2;
        System.out.println(num);  //输出1
        int[] num_array={1,2,3,4,5};
        int[] num2_array=num_array;
        System.out.println(num_array[0]);    //输出1
        num2_array[0]=5;
        System.out.println(num_array[0]);    //输出5

由于num和num2都是基本类型,因此前两句的意思是,创建一个值为1的容器num,然后在创建一个容器num2,然后把num容器中的值1也给了容器num2。

由于num_array和num_array2都是数组,而数组是引用类型,情况就完全不同了。{1,2,3,4,5}是容器本身,只有这一个容器,num_array和num2_array则是两个同时指向这个容器的引用名。不管用任何一个引用去改变这个容器中的内容,另一引用中的内容也会跟着变,因为它也指向这个容器,这显然与我们的初衷不同。如果理解了这二者本质上的,就能帮助我们去避免这样的失误。

五,延伸内容:自动装箱与拆箱机制

基本类型的引入,虽然使得Java对初学者更友好,并能更高效处理基本数据类型了;但它同时也使Java偏离了面向对象的基本思想。对于习惯了面向对象编程的开发者,很多时候,把基本类型转变成对象反倒更有助于程序设计,甚至这种需求在一些情况下是必需。因此Java在SE5中引入了自动装箱与拆箱的机制。

这个非常好理解,装箱:就是把一个基本类型封装成了对象。用创建基本类型的方式,完成了创建引用类型的操作。

Integer i = 100; (注意:不是 int i = 100; )
实际上,执行上面那句代码的时候,系统为我们执行了:Integer i = Integer.valueOf(100); 
这就是装箱机制的实现。

拆箱也是同样的道理:

1 Integer i = 10; //装箱 
2  int t = i; //拆箱,实际上执行了 int t = i.intValue();

这个有什么用呢?我举例例子,在JavaWeb开发中,Mybatis的动态映射文件的判断中,对于一个输入值是否存在只能用是否为null来判断。我们都知道,只有引用类型才能被判断是否为null,基本数据类型是无法这样判断。因此这就要求我们在bean中使用int的封装类型Integer。  

到这里内容基本讲完了。《Java编程思想》真的是一本经典书,推荐给诸位学Java的朋友。

猜你喜欢

转载自blog.csdn.net/illikang/article/details/83051584