Java编程思想 第五章 初始化与清理

本文介绍了Java中的构造器用于确保对象初始化,方法的重载依赖于参数列表,而非返回值。讲解了`this`关键字的应用,特别是在构造器中调用构造器的场景。此外,还详细阐述了Java的垃圾回收机制,包括其工作原理和不同策略。同时,讨论了成员变量的初始化顺序,数组的初始化方式,可变参数列表的使用,以及枚举类型的创建和常用方法。这些内容涵盖了Java编程基础的重要知识点。
摘要由CSDN通过智能技术生成

5.1 用构造器确保初始化

Java中构造器采用与类相同的名称,防止构造器与类中的方法名冲突,同时方便编译器自动调用每个方法小写的编码风格不适用于构造器

构造器没有返回值,这与返回值为空(void)是不同的。

Java提供默认的无参构造器,也可以自己编写有参数的构造器。如果已经定义了 一个构造器,编译器就不会提供默认的无参构造器。

5.2 方法的重载

通过参数类型列表可以区分方法,参数的顺序不同也会用于区分
根据方法的返回值来区分重载方法是行不通的

5.4 this关键字

如果你希望在方法的内部获得对当前对象的引用,由于这个引用是由编译器偷偷传进来的,所以没有标识符可用。可以使用this关键字,this关键字只能在方法内部使用,表示对“调用方法的那个对象”的引用。在方法内部调用同一个类的另一个方法,直接调用即可,不用this

public class Person {
	int a = 1;
	public Person getPerson() {
		return this;     // 返回对象的引用
	} 
	public int f() {
		int a = 10;
		return this.a;   // 用于区分【成员变量】和【局部变量】
	}
}

5.4.1 在构造器中调用构造器

public class Person { 
	int a;
	Perosn() {
		this(10);  // 构造器调用置于起始位置
		// this("bbb");   // 不能调用两个构造器
	}
	Person(int a) {
	}
	Person(String b) {
	}
	void print() {
		// this(10);  // 除构造器之外,禁止在其他任何方法中调用构造器
	}
}

5.4.2 static方法

static方法就是没有this的方法。因此在static方法内部不能调用非静态方法,反过来可以。可以在没有创建任何对象的前提下,通过类来调用static方法。

5.5 终极处理和垃圾回收

一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用finalize()方法。

public class Person {
	protected void finalize() {
		System.out.println("我被清理了");
	}
}

Person person = new Person();
person = null;  // 对象不再被引用
System.gc();    // 强制终止

垃圾回收器如何工作

Java从堆分配空间的速度,可以和其他语言从堆栈上分配空间的速度相媲美。

在某些Java虚拟机中,堆的实现更像是一个传送带,每分配一个对象,堆指针就往前移动一格。这意味着对象存储空间的分配空间很快。虽然薄记工作需要少量开销,但是没有查找可用空间的开销大。同时垃圾回收器对对象重新排列,实现了一种高速的、有无线空间可供分配的堆模型。

引用计数法:简单但速度很慢的垃圾回收技术,从未用于Java虚拟机的实现中
——每个对象含有一个引用计时器,当有引用连接时加1,当引用离开作用域或被置为null时减1。管理引用的开销不大,但是会在整个程序生命周期持续。垃圾回收器会遍历列表,释放引用数为0的对象空间。
——很难发现循环引用。

自适应:
从堆栈和静态存储区开始,遍历所有的引用。对于发现的每个引用,必须追踪它所引用的对象,然后是此对象包含的所有引用,如此反复,直到根源于堆栈和静态存储区的引用所形成的网络全部被访问为止。这就解决了循环引用的问题。
处理存活对象:
(1)停止-复制
暂停程序的运行,将所有存活的对象从当前堆复制到另一个堆,没有被复制的全部都是垃圾。对象在复制到新堆时是一个挨着一个的。
缺点:需要修改堆栈的引用。还需要维护两个堆,在两个堆之间互相倒腾。可能产生的垃圾很少但仍然需要复制。
(2)标记-清扫
在寻找存活对象时给对象设一个标记。没有标记的对象不会被清理。所以剩下的堆空间是不连续的。

5.6 成员的初始化

对于方法的局部变量,程序员必须初始化,否则编译器会报错。
如果类的字段是基本类型,会有一个初始值,对象引用会是null。

初始化顺序

变量定义的先后顺序决定了初始化的顺序。即使变量定义散布在方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。先初始化静态对象,然后初始化非静态对象,然后调用构造方法。

静态初始化、非静态初始化

public class Person {
	static int a;
	static int b;
	static {
		a = 10;
		b = 20;
	}
	
	int c;
	int d;
	{
		c = 30;
		d = 40;
	}
}

5.8 数组初始化

数组只是相同类型的、用一个标识符名称封装到一起的一个对象序列或基本类型数据序列。数组通过方括号下标操作符定义和使用。

/** 数组的定义 */
int[] a1;   // 更常用,一个int类型数组
int a1[];
/** 数组的初始化 */
int[] a1 = { 1, 2, 3, 4 };  // 只能在数组被定义时使用
int[] a2;
a2 = new int[10];
int[] a3;
a3 = new int[] { 1, 2, 3, 4 };   
/** 数组的长度 */
a1[0];
a1[a1.length-1];   // 数组的length成员
/** 打印一维数组 */
Arrays.toString(a1);

可变参数列表

/** 将多个参数以Object类型数组的形式传入 */
public class  A {
	static void printArray(Object[] args) {
		for (Object obj : args) {
			System.out.println(args + " ");
		}
	}
	
	public static void main(String[] args) {
		printArray(new Object[] { new Integer(47), new String("aa") })
	} 
}
/** Java SE5新特性,不用显式编写数组语法了,编译器会填充数组,因此获取到的仍然是数组*/
public class  A {
	static void printArray(Object... args) {
		for (Object obj : args) {
			System.out.println(args + " ");
		}
	}
	
	public static void main(String[] args) {
		printArray(new Integer(47), new String("aa"))
		printArray((Object[])new int[] { 1, 2 })
	} 
}

5.9 枚举类型

/** 枚举类的创建 */
public enum A {
	NOT, MILD, HOT_HOT   // 实例是常量,使用大写
}
/** 常用方法 */
A[] values = A.values() // 以声明顺序产生一个数组
for (A a: values) {
	System.out.println(a);
	System.out.println(a.ordinal()); // 声明的顺序
}

由于switch是要在有限的集合中进行选择,因此它与enum正是绝佳的组合。

A a = A.NOT;
switch (a) {
	case NOT: 
		xxx;
		break;
	case MILD:
		xxx;
		break;
	default:
		xxx; 
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值