《Java编程思想》整理——对象和引用

其实已经快两周没读《Thinking in Java》了,不过在开始读的时候就想把书上的内容整理一下的,终于抽出整块的时间来写东西了。很多东西大概已经忘了,毕竟距离读第一章已经过去一个月了。下面的内容主要是根据当时看书的时候搜到的其他 blog 上的一些记录,加上我自己的理解总结出来的。希望在以后重看这篇笔记的时候依旧能够有所收获吧。现在手边没有书。。。过后(或者读第二遍的时候?)再根据书的编排内容整理下吧。

第一张的面向对象导论我并没有读,我是打算在了解了 Java 面向对象之后再看,在净土的这篇 blog 中有介绍。

对象和引用

按照通俗的说法,每个对象都是某个类(class)的一个实例(instance),这里,‘类’就是‘类型’的同义词。

尽管一切都看做对象,但是操纵的标识符实际上是对象的一个“引用”(reference)。String s; 这里创建的只是一个引用。

对象存储:

Java 程序的内存分为以下五个部分,来分别存储不同的内容。

  • 寄存器:处理器内部,最快的存储区,数量极其有限
  • 堆栈:位于通用RAM,速度仅次于寄存器,灵活性受限制,对象的引用,基本类型存于此处
  • 堆:通用内存池,也位于RAM,灵活性大,分配与清理耗时,对象存储于此
  • 常量存储:static、常量、不可变的 String 等,似乎经常被称为常量池
  • 非RAM存储:两个基本的例子是流对象和持久化对象。

下面引用一个例子:

参数传递:

《Thinking in Java》:When you’re passing primitives into a method,you get a distinct copy of the primitive. When you’re passing a reference into a method, you get a copy of the reference.

各种编程语言中,参数传递到底是传值还是传参(引用)。其实仔细想想,都是传的值,基本类型则直接把数值传给了函数(方法);而对象(C 中的指针)本身存的其实就是对象的引用,于是传的还是对象的值——引用。

基本类型和包装类

最初听说 Java 和 C++对比的时候,说 Java 是纯面向对象的语言,而C++为了兼容 C 而包括有面向过程的内容。但是 Java 中的基本类型却不是对象!他们就是基本的。不过Java中针对每一个基本数据类型,都有一个对应的类,称为包装类(Wrapper Class),通过装箱和拆箱(Boxing)来实现转换。同时提供了两个用于高精度计算的类:BigInteger(任意精度的整数)和BigDecimal(任意精度的定点数)。如下图

Java中的包装器类有两个主要的目的:

  1. 提供一种机制,将基本值“包装”到对象中,从而使基本值能够包含在针对对象的操作中,比如添加到Collections 中,或者从返回值为对象的方法中返回。注意,java5增加了自动装箱和拆箱,程序员过去需手工执行的许多包装操作,现在可以由java自动处理了。
  2. 为基本值提供分类功能。这些功能大多数于各种转换有关:在基本值和String对象间相互转换,在基本值和String对象之间按不同基数转换,如二进制、八进制和十六进制。

包装类共同的方法:

  • 带有基本值参数并创建包装类对象的构造函数。如利用Integer包装类创建对象,Integer obj=new Integer(145);
  • 带有字符串参数并创建包装类对象的构造函数.如:new Integer(“-45.36”);
  • 生成对象基本值的typeValue方法,如:obj.intValue();
  • 字符串转换为基本值的parseType方法,如:Integer.parseInt(args[0]);
  • 生成哈稀表代码的hashCode方法,如:obj.hasCode();
  • 对同一个类的两个对象进行比较的equals()方法,如:obj1.eauqls(obj2);
  • 生成字符串表示法的toString()方法,如:obj.toString().

自动装箱和拆箱(以下内容多数摘自AlexYoung 的 Blog):

装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。通过反编译Class 字节码文件可以得知(其实是看的 blog……):

在装箱的时候,自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。其他的也类似,比如Double、Character,不相信的朋友可以自己手动尝试一下。

用一句话总结装箱和拆箱的实现过程:

装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的xxxValue方法实现的。(xxx代表对应的基本数据类型)。

在AlexYoung 的 Blog 中解释了一个面试中问到的自动装箱和拆箱问题,在上面给出链接的博文最后有对几种情况的解析,总结如下:

  • 在通过valueOf方法创建Integer对象的时候,如果数值在 [-128,127] 之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。
  • Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的,Double、Float的valueOf方法的实现是类似的。
  • Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别:1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。
  • 当 “==” 运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。另外,对于包装器类型,equals方法并不会进行类型转换。

参考链接:

净土CSDN的iaitiAlexYoung以及似乎不更新的 cnblog的Danie广

发表评论

电子邮件地址不会被公开。 必填项已用*标注