有关java构造器的笔记

1. 不涉及继承和多态的构造器初始化过程

  当程序中出现new A a() , 或者使用了A类的静态方法等代码时(声明一个A类对象不算) java虚拟机会首先加载A类, 然后执行A的静态初始化, 静态初始化会先将所有的静态成员变量进行默认初始化, 也就是基本数据类型初始化为0, 引用数据类型初始化为null. 然后按照静态变量和静态区的初始化顺序和声明顺序一致这一准则进行初始化. 此时执行的静态初始化只执行这一次, 执行之后就再也不执行了.

  然后如果出现new A a() , 就会为对象分配存储空间, 然后对所有的非静态成员变量进行默认初始化, 然后加载Object类(如果没有加载的话), 然后对Object对象进行初始化. 然后回到A类的内部, 按照成员变量和非静态区的声明顺序对其进行初始化. 最后执行构造函数, 完成初始化过程.

2. 一旦涉及到继承和多态, 初始化就变得稍微复杂了一点点.

  涉及继承, 如果A类如果有一个或者多个父类的时候, 静态初始化的步骤不变, 但是当新建一个对象时 , 在默认初始化之后, 会一层一层地找父类, 直到Object类, 然后再向下依次初始化Object类和其他父类.

  涉及多态, 如果父类的非静态代码块或者父类的构造函数中调用了涉及到多态的函数, 那么这个函数是A类相应重写的函数.

class Glyph
{
	{
		draw() ; //会调用子类的
	}

	void draw()
	{
		System.out.println("Glyph draw()") ;
	}

	public Glyph()
	{
		System.out.println("Glyph() before draw()") ;
		draw();	//会调用子类的
		System.out.println("Glyph() after draw()") ;
	}
}

public class RoundGroph extends Glyph
{
	private int radius = 1 ;
	RoundGroph(int i)
	{
		radius = i ;
		System.out.println("RoundGroph.Grougph().radius= " + radius) ;
	}

	void draw()
	{
		System.out.println("RoundGroph.draw().radius= " + radius) ;
	}

	public static void main(String args[])
	{
		RoundGroph a  = new RoundGroph(22) ;
	}
}

  之所以会出现这种情况是因为 动态绑定 . java之所以有多态, 就是由于<a href="http://www.cnblogs.com/yyyyy5101/archive/2011/08/02/2125324.html">动态绑定</a>.

上述代码就是对《thinking in java》这段话的一个解释

如果构造器只是在构建对象的一个步骤,并且 该对象所属的类 是从 这个构造函数所属的类 导出的,那么导出部分在当前构造器正在被调用的时刻仍然是没有初始化的。然而一个动态绑定的方法调用却会深入到继承层次结构的内部,调用导出类的方法。如果我们在构造函数中这么做,那么就可能调用某个方法,而这个方法所使用的成员可能还尚未初始化--这肯定会招灾引祸。

  上面代码中的RoundGroph是Glyph的子类。按照上面对于有继承关系的初始化过程的描述,当遇到new RoundGroph(22),就会分配存储空间,并对RoundGroph的成员进行默认初始化,然后初始化他所持有的RoundGroph对象,在初始化Glyph的过程中会调用draw(),这个方法是动态绑定的,在RoundGroph还未完全初始化的情况下调用RoundGroph的draw(),如果此时draw()中使用了未初始化的子类成员变量,那么就会导致莫名的错误,也就是《thingking in java》中所说的招灾引祸。

//thinking in java笔记,如果有不对的地方,还望指正^_^

时间: 2024-10-25 21:56:56

有关java构造器的笔记的相关文章

java基础巩固笔记(6)-注解

java基础巩固笔记(6)-注解 java基础巩固笔记6-注解 注解的应用结构图 元注解 自定义注解 示例代码 参考资料 注解(Annotation),也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次.它可以声明在包.类.字段.方法.局部变量.方法参数等的前面,用来对这些元素进行说明,注释. API Package java.lang.annotation 注解的应用结构图 调用/结构关系:A<–B<–C A,B,C解释如下: A:注解类

Java内部类学习笔记

这是我学习Java内部类的笔记 1.为什么使用内部类?使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响1.1.使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,使用内部类还能够为我们带来如下特性:(1).内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独.(2).在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类.(3).创建内部类对象的时

java effective 读书笔记

java effective 读书笔记 [1]创建和销毁对象 1 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 2 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 3 枚举 singleton 不知道怎么操作,觉得意义不大 单例模式 4 私有化构造器不能实例化,也不可被子类继承 5 能用原生类的就尽量不用对象 [2]对于所有对象都通用的方法 reflexivity 自反性 symmetry 对称性 [3]类成员 降低可访问性 尽量把公有域 变成私有域,并提供

Java编程思想笔记(第二章)

第二章  一切都是对象 尽管Java是基于C++的,但相比之下,Java是一种更纯粹的面向对象程序设计语言. c++和Java都是杂合型语言(hybird language) 用引用(reference)操作对象 类似遥控器(引用)来操作电视(对象) 在Java中你可以创建一个引用,但是没有与任何对象关联,比如: String s; 这个时候如果用则会报错.安全的做法是: 创建一个引用的同时并进行初始化 String s="1111"; 必须由你创建所有对象 New关键字的意思是给我一

Java的一些笔记

1: 封装->类->对象使用   继承->代码复用(code reuse)->父类(超类,基类) 子类对父类的扩展   多态{ 对外一个接口 内部多种实现  就 可以理解为一个多态  } 属性 方法 构造器2:object  所有类的父类   一个类只有一个父类3:类的继承语法 pg: class zhangsan [extends zhanghu ]      {   < declaration>      } 4:getter方法  setter方法5:使用继承就用

Java——构造器

Java 构造器的由来:构造器是一个创建对象时被自动调用的特殊方法,为的是初始化. 当创建一个个对象时,系统会该对象的属性默认初始化,基本类型属性的值为0(数值类型),false(布尔类型),把所有的引用类型设置为null.构造器可以改变这种默认的初始化.构造器不是函数. 要求:构造器的名称应与类的名称一致.调用构造器是编译器的责任,所以必须让编译器知道调用的是哪一个方法.所以Java采取了与类同名的方法命名构造器. public class Person { public String nam

《深入Java虚拟机》笔记:指令集 (转)

<深入Java虚拟机>笔记:指令集 指令 含义 iconst_m1 把int型常量-1压入栈中 iconst_0 把int型常量压入栈中 fconst_1 把float型常量1压入栈中 lconst_2 把long型常量2压入栈中 dconst_3 把double型常量3压入栈中 bipush byte1 把byte1转换成int型压入栈中 sipush byte1,byte2 把byte1,byte2组成的short转换成int压入栈中 aconst_null 把空对象压入栈中 ldc in

java nio学习笔记(一)

位置保留,待用 java nio学习笔记(一),布布扣,bubuko.com

JAVA基础学习笔记(2)

看了几天的视频了,都没时间来写下学习笔记,今天来写下第二次的学习笔记,前几天看的给忘记了,就写最新看到的吧 主要内容:1.类的变量与函数(方法) 2.对象的存储方式 3.新建一个对象及对象的赋值与调用 4.空对象 5.匿名对象 1.类的变量与函数(方法) class Dog      //类名 { String name;  //变量的声明 int age; String color; void bark()   //方法的定义(返回值为空,不带参数) { System.out.println(