从零学Java(2)——理解引用
本来这篇博客昨天就应该写出来,结果为了近期的一个志愿者交流会,做了整整一晚上ppt,直到12点才做完。今天把这篇博客补上,感觉学习的进度要比写博客的进度快很多。其实写博客能给我一个回顾与总结的过程,比如今天这篇,写的过程中发现昨天学习中的知识没有明白,反复研究后才有更深入的理解。
进入《Java编程思想》的第二章学习,刚开头作者就吐槽了一番C++:
尽管Java是基于C++的,但是相比之下,Java是一种更“纯粹”的面向对象程序设计语言。C++和Java都是混合/杂合型语言。但是,Java的设计者认为这种杂合性并不像在C++中那么重要。。。。因为C++是C的一个超集,所以势必包括许多C语言不具备的特性,这些特性使C++在某些方面显得过于复杂。
都说C++学习在于深度,Java学习在于广度。想要学好Java,路还长着嘞。
这里要重点说“用引用操作对象”,C++中碰到过引用,一直就没搞明白,看看Java的怎么样。尽管一切都看做对象,但标识符实际上是对象的一个“引用”。作者还做了个比喻,“引用”就像遥控器,“对象”就像电视机,我们对电视机调节音量等操作,实际上是通过遥控器来实现的。恩,看到这里感觉还挺好懂的,我们继续往下看。
你拥有一个引用,并不一定需要有一个对象与它关联。这是什么意思?来看看举例:
String s; // String s = "asd"
这里只是创建了一个引用,并不是对象,这里s并没有与任何对象关联(使用这个引用需要初始化,否则报错)。如果创建了一个引用,要关联某个对象就需要new操作符来实现,它的意思是“给我一个新的对象”(下例还是初始化过的):
String s = new String("asd");
看到这个new操作符,有没有想到C++中的动态分配?有点像。看到这里,你一定和我一样有疑问:为什么要“引用”这种操作?
其实我是真的真的想把这个“引用”看作“指针”,谁知道书里已经否定了这个想法(书中说:与C++中的指针还是有重要的区别),不过我还是先用指针简单理解一下引用这个概念。new在这里动态创建了String类型并分配空间,我们需要一个东西来“指向”它,就是引用了。之所以要String s来创建这个引用,一方面,静态语言都要事先明确给出变量的类型,另一方面,就像指针一样,你要说明你的指针变量是指向哪种类型的数据,这里既是说明引用的哪种类型的对象。
咳咳咳,这里感觉有点把大家引到歧路了,这里只是我的猜测和不成熟的比喻,请原谅我这个新手。也许你会反对我说这部分说:根本没有提及“动态分配”,其实本书的第一章就说明了Java完全采用动态内存分配方式(基本类型是个特例)。new将对象存储在“堆”中。
堆。一种通用的内存池(位于RAM中),用于存放所有的Java对象。编译器不需要知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当需要一个对象时,只需要new写一行简单的代码,当执行这些代码时,会自动在堆里进行存储分配。
作用域大家都知道,看看下面这个例子:
{
String s = new String("a string");
}
学过C/C++的都知道,临时变量在作用域之外生命周期即停止。这里,尽管引用s在作用域外就消失了,但是s指向的String对象仍然继续占据内存空间,就是说,由new创建的对象,只要你需要,就会一直保留下去。那么这个留下来的对象还有什么用,怎么用?肯定是有用的,能用的,只是这章没有介绍(书中后面还会讲如何传递和复制对象引用)。
Java有一个垃圾回收器,用来监视new创建的所有对象,并辨别那些不会再被引用的对象。随后,释放这些对象的内存空间,以便提供给其他新的对象使用。
这个垃圾回收器是Java的一个特别的地方,它不用像C++那样delete或C那样free这些动态分配的内存了。
这里要说一个特例,就是基本类型,这些类型可以不使用动态分配内存机制。很多我们都在C/C++中见过:boolean,char,byte,short,int,long,float,double,float。有的时候我们需要创建一些小的,简单的变量,如果使用动态分配,比较消耗时间,这些变量基本都是这些基本类型,所以Java提供了创建一个并非是引用的“自动”变量,这个变量直接存储“值”,并置于堆栈中,因此更高效。堆栈也位于RAM中,需要知道所有在其中的变量的确切生命周期,Java对象不能存储在这里。这里要说两点:
1 所有数值类型都有正负号,所以不要去寻找无符号的数值类型那个。
2 每种基本类型所占的存储空间大小不随着机器硬件架构的变化而变化。由于Java是在虚拟机上实现,其实感觉就像虚拟机已经帮你解决了移植的问题,给你提供了一个统一的环境,故基本类型的大小都是固定的。所以也不需要sizeof这样的函数。这就是Java良好移植性的体现。
那么这些基本类型就不能被动态创建了?别急,基本类型都有包装器类,使得可以在堆中创建一个非基本对象,用来表示对应的基本类型:
char c = 'x';
Character ch = new Character(c);
说说很多语言都有的数组。Java提供了一种机制确保数组会被初始化,并且不能在它的范围之外被访问(太好了,妈妈再也不用担心我的数组越界了)。当创建一个数组对象时,实际上就是创建了一个引用数组,并且每个引用都会自动被初始化为一个特定值,该值拥有自己的关键字null。一旦Java看到null,就知道这个引用还没有指向某个对象。在使用任何引用前,必须为其指定一个对象。还可以创建用来存放基本数据类型的数组(全部被初始化为0)。
blog comments powered by Disqus