《Head First Java》读书笔记(贰)

构造器

① 当new出一个对象时,便调用了该类的构造函数

② 如果没有自己写构造函数,编译器会帮我们写一个(这样没有参数的构造函数):

public Dog(){
	// 构造函数体为空
}

可以看出构造函数的特点是:构造函数没有返回类型和类同名

public class Loli{
	int age;										// 实例变量

	public age(){									// 自己写的不含参的构造函数(用于赋予默认值)
		age = 12;
	}
	public age(int theAge){							// 带参数的构造函数,new对象时传入参数
		age = theAge;
	}
	public age(int theAge, boolean isGothic){		// 构造函数同样可以重载
		age = theAge;
		System.out.println("Saikou!")
	}
}

※ 注:

  1. 当你自己写了任何一个构造函数时,不管有参无参,编译器都不会再生成那个不带参、函数体为空的默认构造函数
  2. 构造函数可以是共有私有、或者不指定
  3. 抽象的类也有构造函数:虽然抽象类本身不能new出对象,但它的子类在构造时会调用到它的构造函数

③ 关于构造函数与父类继承的关系(即子类构造函数和父类构造函数的关系),

首先要明确的是:在新建对象时,整个构造函数链都会被执行

④ (★☆★)这个构造函数链的执行顺序是:

  首先最末端的构造函数开始执行,而这个构造函数在执行的时候,第一件事是去执行它的父类的构造函数(这是通过编译器在每个构造函数的第一行自动加上的super()实现的),父类的构造函数执行时,又立即去执行它的父类的构造函数…如此向上,一路到Object。

下面的图生动清晰展现了这个在栈上进行的过程:
在这里插入图片描述
为什么是以这样的次序进行构造呢?这涉及到对象的本质结构;

对象也是有层次的,这个洋葱似的层次结构是它在构造时的次序的真正原因:

在这里插入图片描述
☀ 注:

  1. super()必须在构造函数的第一行;编译器默认添加的super()也是默认在第一行的
  2. 位于构造函数链末端的构造函数(自身的构造函数)最早被调用,但最后一个执行完毕
  3. 一个极其重要的思想:对象的父类必须先完备,子类才能创建
  4. 如果父类的构造函数带有参数,则子类在调用它时在super()中也传入参数就可以了:诸如:super(age);super(age, size);

使用this()从某个构造函数调用同一个类的另外一个构造函数

⑥ this()只能用在构造函数的第一行,因此this()与super()不能兼得

 
 

【垃圾收集器(Garbage Collector, GC)】

① 先弄清楚局部变量和实例变量的生存周期:

  局部变量只会存活在声明该变量的方法中。当方法中调用另一个方法时,另一个方法压入栈并成为栈顶,原先的第一个方法的局部变量被暂存等待,并且此时栈顶的方法不在其范围中(也就是说,局部变量的范围仅仅在一层方法中);

这个方法运行结束后,弹出栈顶,原先等待的局部变量重新有效。这个方法也结束后,弹出栈顶,其内部的局部变量被释放

   实例变量的寿命与对象相同。只要对象活着,实例变量就是活的;

② 而对象的生命周期呢?完全依赖于指向这个对象的引用。当最后一个指向它的引用消失时,对象就会变成可回收的。

我们有三种方法“杀死”一个对象:

  1. 引用永久的离开它的范围(引用也是个变量,当它是在方法中声明的,它就是一个局部变量,其生命周期与方法一致)。在方法中new出一个对象,随着方法结束,从栈顶弹出,其局部变量包括指向这个对象的引用被释放,这就预示着这个对象的生命随着引用的释放而走到了终点(被标记为可回收);
  2. 引用被赋值到其他对象上。如果这个被移开的引用是指向这个对象的唯一引用,那么该对象变为可回收;
  3. 直接将引用设定为null。原理和上边两条一样,没了引用,对象无法以任何方法被触碰到,所以"死了"
     
     

【静态】

非静态是对象的,通过对象名称进行调用;静态是类的,通过类名直接调用。

静态方法不依赖于堆上的实例对象

静态变量是被同类的所有实例对象共享的

④ 实例变量:每个实例(对象)一个;

   静态变量:每个类一个

在静态方法中调用非静态的变量的方法是不合法的

☀ ☀ ☀ 机制解析 :

静态变量在类第一次被加载时完成初始化JVM何时会加载某个类呢

有两种情况:一是第一次有人尝试创建该类的实例二是使用该类的静态变量或方法

因此,“类被加载”和“类被创建”的逻辑关系是:类被创建时会去加载类;但类被加载不能说明类正在被实例化,还有可能是调用了该类的静态变量或方法;

而且,就算是第一次在实例化类的过程中,静态变量的初始化也是要比实例变量的初始化要超前的;
 

明确一个基本原理,可以帮助记忆:

静态的变量和方法提前初始化了,因而你可以放心地在非静态方法中调用它们

反之则不行:因为此时非静态变量可能还没被初始化

(静态方法不仅不能调用非静态变量,非静态方法也不行,即使该方法压根没有调用非静态变量)

⑥ 两个保证:

  1. 静态变量会在该类的任何对象创建之前就完成初始化
  2. 静态变量会在该类的任何静态方法执行之前就完成初始化

⑦ 静态变量默认值(0, 0.0, flase, null)

⑧ 请再一次回答这个问题:为什么不能再静态方法中调用非静态的变量和方法?

Answer:类的加载发生在调用静态变量和方法,以及尝试new出对象时。 在第一种情况下,类被加载,静态初始化程序被触发;但是构造函数未被触发,非静态的变量和方法并未被初始化。在静态方法中可以调用静态变量,因为静态变量的初始化在静态方法之前;但是显然,在静态方法中不能调用还未初始化的非静态变量和方法。

 
 

【常数】

① 静态的final变量可以看作是常量:

static使它不依赖于对象就可使用;final防止它的值被修改

② 常量的命名惯例是全部大写

③ 什么是静态初始化程序?

  静态初始化程序(static initializer)是一段在加载类是会执行的程序代码(加载类new出对象是两回事)

final的静态变量没有默认值必须声明时或在静态初始化中被被赋值

class Foo {
	final static int x;		// 声明final的静态变量(常量特征);没有在声明时赋值在,则必须在下面的静态初始化程序中被赋值
	static {				// 静态初始化程序
		x = 12;
	}
}

静态初始化程序会在构造函数之前执行

⑥ final的用法和效果:

class Foo {
	final int size = 3;			// final修饰实例变量
	final int age;				// final修饰实例变量
	
	Foo() {
		age = 12;
	}

	void func(final int x) {	// final修饰方法的参数
		// 方法体中不能改变 x 的值
		// 如果参数是引用,则这个引用的指向不能被修改
		final int y;			// final修饰局部变量
	}
}
// 另外:
// final修饰方法,则该方法无法被覆盖
// final修饰类,则该类无法被继承

 
 

【auto-boxing/unboxing机制】

① 8个primative主数据类型有对应的8个包装类

  Boolean, Character, Byte, Short, Integer, Long, Float, Double

int n = 12;
Integer wrap = new Integer(n);		// 包装
int unWrap = wrap.intValue();		// 解包装

③ 由于自动包装-解包装机制(auto-boxing/unboxing)的存在,primitive主数据类型和其对应的包装类在一般情况下,完全可以混用

通常需要注意两个地方:

  1. 一是generic类型(泛型)的规则是只能指定类或接口,诸如ArrayList<int>无法通过编译;
  2. 二是基本数据类型及其包装类的默认值是不同的,比如int默认值为0,Integer默认值为null

④ 包装类的几个静态方法十分常用 :

String s = "233";
int n = Integer.parseInt(s);			// "2" 被解析成 2

String s = "12.345f";
double d = Double.parseDouble(s);		// "12.345f" 被解析成 12.345

// 作用显而易见:将String参数解析成对应的包装类类型
// 不要自作聪明!参数只能是String!

另外,值得一提的是:

boolean b1 = new Boolean(true);			// 传入boolean进行包装当然可以
boolean b2 = new Boolean("true");		// 传入String也会被包装成Boolean

↑ 均合法。这是因为Boolean的构造函数有个String参数的重载方法

 
 

【格式化】

① format是String的一个静态方法 :

System.out.println(String.format("%s and %d", "loli", 233));

也可以这样:

System.out.format("%s and %d", "loli", 233);

 

 

 

 
 

 

 

 

 

 

 

 

 

 

 
☀ 《Head First Java》Kathy Sierra & Bert Bates

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值