java编程思想笔记

第一章:对象导论

1.1伴随多态的可互换对象

  面向对象程序设计语言使用了后期绑定的概念。当向对象发送消息时,被调用的代码直到运行时才能确定。也叫作动态绑定

  编译器确保被调用的方法的存在,并对调用参数和返回值执行类型检查(java是强类型的语言,无法提供此类保证的语言称为弱类型的),但是并不知道将被执行的确切代码。

  在某些语言中,必须明确地生命希望某个方法预备后期绑定属性所带来的灵活性(C++使用virtual关键字实现的)。在这些语言中,方法默认不是动态绑定的。而java中,动态绑定是默认行为(java中除了使用static,final,private方法外,其他方法都是动态绑定的),不需要添加额外的关键字来实现多态。

  把导出来类看做是他的基类的过程称为向上转型(upcasting)

1.2单根继承结构

  在java中(事实上还包括除C++以外的所有OOP语言),所有的类最终都继承自单一的基类,这个终极基类的名字就是Object.

  单根继承结构的好处:

  • 在单根继承结构中所有对象都具有一个公用接口,所以他们归根到底都是相同的基本类型
  • 单根继承结构保证所有对象都具备某些功能
  • 单根继承结构使垃圾回收的实现变得容易,二垃圾回收正式相对C++的重要改进之一。由于所有对象都保证具有其类型信息,因此不会因无法确定对象的类型而陷入僵局。这对于系统级操作(如异常处理)显得尤其重要,并且给编程带来了更大的灵活性。

1.3对象的创建和生命周期

  • 对象的数据位于何处(作用域)
    • 将对象置于堆栈或静态存储区域来实现。这种方式将存储空间分配和释放置于优先考虑的位置,某些情况下这样控制非常有价值。但是,也牺牲了灵活性)
    • 第二种方式被称为堆(heap)的内存池中动态地创建对象。这种方式中,知道运行时才知道需要多少独享,他们的生命周期,以及他们的具体是什么。
    • java完全采用动态内存分配方式(基本类型是一种特例)。每当想要创建对象时,就要使用new关键字来构建对象的动态实例。
  • 对象生命周期
    • java的垃圾回收器被设计用来处理内存释放问题

第二章 一切都是对象

2.1特例:基本类型

  基本类型是一个并非是引用的“自动”变量。这个变量直接存储“值”,并置于堆栈中,因此使用更高效,java的基本类型所占存储空间大小不随机器硬件架构的变化而变化。这种所占存储空间大小的不变性是java程序比其他大多数语言编写的程序更具有可移植性的原因之一。

基本类型 大小 包装器类型
boolean - Boolean
byte 8bits Byte
char 16bits Character
short 16 bits Short
int 32 bits Integer
float 32 bits Float
long 64 bits Long
double 64 bits Double
void - Void

    所有数值类型都有正负号

    boolean类型所占存储空间的大小没有明确指定(要看具体虚拟机的实现),仅定义为能够取字面值true或false.

2.2java中的数组   

  java确保数组会被初始化。而且不能在它的范围之外被访问。这种范围查找,是以每个数组上少量的内存开销以及运行时的下标检查为代价的。

 

《深入理解Java虚拟机》:
Java 语言中对数组的访问比C/C++相对安全是因为:如有一维数组,其元素类型为 mypackage.MyClass,则虚拟机会自动生成一个直接继承于java.lang.Object的子类[Lmypackage.MyClass,创建动作由字节码指令newarray触发。这个类代表了一个元素类型为mypackage.MyClass的一维数组,数组中应有的属性和方法(用户可直接使用的只有被修饰为public的length属性和clone()方法)都实现在这个类里。Java语言中对数组的访问比C/C++相对安全就是因为这个类封装了数组元素的访问方法(准确地说,越界检查不是封装在数组元素访问的类中,而是封装在数组访问的xaload、xastore字节码中),而C/C++直接翻译为对数组指针的移动。

  • 数组对象,实际就是一个引用数组,每个元素会被初始化为null.
  • 基本数据类型的数组,编译器会将这种数组所占的内存全部置为零
  • 在java中,检查到数组越界是会抛出java.lang.ArrayIndexOutOfBoundsException异常。

 

第8章 多态(Polymorphism)

8.2 域与静态方法

  域是不具有多态性的,只有普通的方法调用是多态的。如果直接访问某个域,这个访问就将在编译期进行解析,即域是静态解析的。
  如下,当Sub对象转型为Super引用时,任何域访问操作都将由编译器解析,因此不是多态的。Super.field和Sub.field分配了不同的存储空间。这样,Sub实际上包含两个称为field的域:它自己的和它从Super处得到的。

  class Super{
  public int field = 0;
    public int getField(){return field;}
  }
  class Sub extends Super{
    public int field = 1;
    public int getField(){return field;}
    public int getSuperField(){return super.getField();}
  }
  public class FieldAccess{
    public static void main(String[] args){
      Super sup = new Sub(); // Upcast
      System.out.println("sup.field = " + sup.field + ". sup.getField() = " + sup.getField());
      Sub sub = new Sub();
      System.out.println("sub.field = " + sub.field + ". sub.getFiled() = " + sub.getField() + ". sub.getSuperField() = " +     sub.getSuperField());
  }
  }
/** Output:
* sup.field = 0. sup.getField() = 1
* sub.field = 1. sub.getFiled() = 1. sub.getSuperField() = 0
*/

 

  • 静态方法也是不具有多态性的,如前文所述,静态方法是与类,而非与单个的对象相关联的。

8.3 构造器内部的多态方法的行为

  如果在构造器内部调用正在构造的对象的某个动态绑定方法,由于动态绑定是在运行时才决定的,而此时,该对象还正在构造中,所以它不知道自己属于哪个类(父类还是自己),并且方法所操纵的成员可能还未进行初始化,这可能会产生一引起难于发现的隐藏错误。

  

public class PolyConstructors {
public static void main(String[] args){
new RoundGlyph(5);
}
}
class Glyph{
void draw(){
System.out.println("Glyph.draw()");
}
Glyph(){
System.out.println("Glyph() before draw()");
draw();
System.out.println("Glyph() after draw()");
}
}
class RoundGlyph extends Glyph{

RoundGlyph(int r){
draw();
radius = r;
System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
}
private int radius = 1;
void draw(){
System.out.println("RoundGlyph.draw(), radius = " + radius);
}
}

  

  Glyph() before draw()
  RoundGlyph.draw(), radius = 0
  Glyph() after draw()
  RoundGlyph.draw(), radius = 1
  RoundGlyph.RoundGlyph(), radius = 5

 

posted @ 2018-11-05 10:34  沈友慧  阅读(250)  评论(0编辑  收藏  举报