第六章 初始化和清理

利用构造器保证初始化

在 Java 中,类的设计者通过构造器保证每个对象的初始化。

构造器名称与类名相同。

在 Java 中,对象的创建与初始化是统一的概念,二者不可分割。

方法重载

区分重载方法

Java 中以参数列表区分重载方法。

重载与基本类型

基本类型可以自动从较小的类型转型为较大的类型。

如果传入的参数类型大于方法期望接收的参数类型,你必须首先做下转换,如果你不做的话,编译器就会报错。

自动转换顺序:

char,byte,short,int,long,float,double

char不会转byte和short,而是直接转int。

无参构造器

如果你创建一个类,类中没有构造器,那么编译器就会自动为你创建一个无参构造器。

但是,一旦你显式地定义了构造器(无论有参还是无参),编译器就不会自动为你创建无参构造器。

this关键字

this 关键字只能在非静态方法内部使用。

当你调用一个对象的方法时,this 生成了一个对象引用。你可以像对待其他引用一样对待这个引用。如果你在一个类的方法里调用其他该类中的方法,不要使用 this,直接调用即可,this 自动地应用于其他方法上了。

this 关键字只用在一些必须显式使用当前对象引用的特殊场合。

    // 方法定义
Leaf increment() {
i++;
return this;
} // 调用
Leaf x = new Leaf();
x.increment().increment().increment();

this 关键字在向其他方法传递当前对象时也很有用:

Peeler.peel(this);

在构造器中调用构造器

在一个构造器中,当你给 this 一个参数列表时,它是另一层意思。它通过最直接的方式显式地调用匹配参数列表的构造器。

能通过 this 调用一次构造器。另外,必须在方法的第一行使用 this 关键字调用构造器,否则编译器会报错。

参数列表中的变量名 s 和成员变量名 s 相同,会引起混淆。你可以通过 this.s 表明你指的是成员变量 s,从而避免重复。

编译器不允许在一个构造器之外的方法里调用构造器。

static 的含义

static 方法中不会存在 this。你不能在静态方法中调用非静态方法(反之可以)。静态方法是为类而创建的,不需要任何对象。一个类中的静态方法可以被其他的静态方法和静态属性访问。

垃圾回收器

finalize() 方法的工作原理"假定"是这样的:当垃圾回收器准备回收对象的内存时,首先会调用其 finalize() 方法,并在下一轮的垃圾回收动作发生时,才会真正回收对象占用的内存。

finalize() 是一个潜在的编程陷阱。

在 Java 中,对象并非总是被垃圾回收

  1. 对象可能不被垃圾回收。
  2. 垃圾回收不等同于析构。
  3. 垃圾回收只与内存有关。

将对 finalize() 的需求限制到一种特殊情况,即通过某种创建对象方式之外的方式为对象分配了存储空间。

看起来之所以有 finalize() 方法,是因为在分配内存时可能采用了类似 C 语言中的做法,而非 Java 中的通常做法。这种情况主要发生在使用"本地方法"的情况下,本地方法是一种用 Java 语言调用非 Java 语言代码的形式。

本地方法目前只支持 C 和 C++,但是它们可以调用其他语言写的代码,所以实际上可以调用任何代码。在非 Java 代码中,也许会调用 C 的 malloc() 函数系列来分配存储空间,而且除非调用 free() 函数,不然存储空间永远得不到释放,造成内存泄露。但是,free() 是 C 和 C++ 中的函数,所以你需要在 finalize() 方法里用本地方法调用它。

绝对不能直接调用 finalize()方法。

在不需要类似析构器行为的时候,Java 的垃圾回收器极大地简化了编程,并加强了内存管理上的安全性。一些垃圾回收器甚至能清理其他资源,如图形和文件句柄。然而,垃圾回收器确实增加了运行时开销,由于 Java 解释器从一开始就很慢,所以这种开销到底造成多大的影响很难看出来。随着时间的推移,Java 在性能方面提升了很多,但是速度问题仍然是它涉足某些特定编程领域的障碍。

构造器初始化

自动初始化的进行,会在构造器被调用之前发生。

编译器不会强制你一定要在构造器的某个地方或在使用它们之前初始化元素——初始化早已得到了保证。

初始化的顺序

在类中变量定义的顺序决定了它们初始化的顺序。即使变量定义散布在方法定义之间,它们仍会在任何方法(包括构造器)被调用之前得到初始化。

静态数据的初始化

初始化的顺序先是静态对象(如果它们之前没有被初始化的话),然后是非静态对象。

初始化顺序:

  1. 静态初始化
  2. 对象中的所有基本类型数据设置为默认值,数字会被置为 0,布尔型和字符型也相同),引用被置为 null
  3. 字段定义处的初始化动作
  4. 构造器初始化

显式的静态初始化

    static {
i = 47;
}

静态初始化只会执行一次,在构造器之前调用。

非静态实例初始化

    {
mug1 = new Mug(1);
mug2 = new Mug(2);
System.out.println("mug1 & mug2 initialized");
}

多次初始化,在构造器之前调用,对于支持"匿名内部类"的初始化是必须的。

数组初始化

// 三种创建数组的方式
int[] a = {1, 2, 3, 4, 5};
int[] a = new int[rand.nextInt(20)];
int[] a = new int{1, 2, 3, 4, 5};

对于数组,初始化动作可以出现在代码的任何地方,但是第一种使用一种特殊的初始化表达式,它必须在创建数组的地方出现

可变参数列表

    // 定义
void printArray(Object... args) {
for (Object obj: args) {
System.out.print(obj + " ");
}
System.out.println();
} // 调用
printArray(47, (float) 3.14, 11.11);
printArray((Object[]) new Integer[] {1, 2, 3, 4});
printArray(); // Empty list is OK

可变参数实质上是一个数组。

如果你有一组事物,可以把它们当作列表传递,而如果你已经有了一个数组,该方法会把它们当作可变参数列表来接受。

可变参数的个数可以为 0。

可变参数列表使得方法重载更加复杂了,尽管乍看之下似乎足够安全。

    static void f(float i, Character... args) {
System.out.println("first");
} static void f(Character... args) {
System.out.println("second");
} public static void main(String[] args) {
f(1, 'a');
f('a', 'b'); // 会报错
}

可能需要通过在某个方法中增加一个非可变参数解决这个问题。

    static void f(float i, Character... args) {
System.out.println("first");
} static void f(char c, Character... args) {
System.out.println("second");
}

应该总是在重载方法的一个版本上使用可变参数列表,或者压根不用它。

枚举类型

Java 5 中添加了特性 enum 关键字。

由于枚举类型的实例是常量,因此按照命名惯例,都用大写字母表示(如果名称中含有多个单词,使用下划线分隔)。

在你创建 enum 时,编译器会自动添加一些有用的特性。例如,它会创建 toString() 方法,以便你方便地显示某个 enum 实例的名称,这从上面例子中的输出可以看出。编译器还会创建 ordinal() 方法表示某个特定 enum 常量的声明顺序,static values() 方法按照 enum 常量的声明顺序,生成这些常量值构成的数组。

由于 switch 是在有限的可能值集合中选择,因此它与 enum 是绝佳的组合

        switch(degree) {
case NOT:
System.out.println("not spicy at all.");
break;
case MILD:
case MEDIUM:
System.out.println("a little hot.");
break;
case HOT:
case FLAMING:
default:
System.out.println("maybe too hot");
}

20190816 On Java8 第六章 初始化和清理的更多相关文章

  1. 初读"Thinking in Java"读书笔记之第五章 --- 初始化与清理

    用构造器确保初始化 构造器可以确保每个对象都会得到初始化,Java毁在创建对象时自动调用构造器. 构造器采用与类名相同的名称,因此并不适合"每个方法首字母小写的风格". 构造器默认 ...

  2. 《Java编程思想》笔记 第五章 初始化与清理

    1.构造器 因为创建一个类的对象构造器就会自动执行,故初始化某些东西特好 2.方法重载 方法名相同,参数列表不同. 2.1 区分重载方法 方法重载后区别不同方法的就是方法签名 -->参数类型和个 ...

  3. java编程思想第五章初始化与清理

    5.1使用构造器确保初始化: 构造器与一般方法一样,但是没有返回值,且其方法名与类名完全相同. 不接受任何参数的构造器成为默认构造器,也叫无参构造器. 5.2 方法重载: 为什么会有方法重载? 构造器 ...

  4. 20190902 On Java8 第十六章 代码校验

    第十六章 代码校验 你永远不能保证你的代码是正确的,你只能证明它是错的. 测试 测试覆盖率的幻觉 测试覆盖率,同样也称为代码覆盖率,度量代码的测试百分比.百分比越高,测试的覆盖率越大. 当分析一个未知 ...

  5. [Effective Java]第六章 枚举和注解

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  6. 【windows核心编程】 第六章 线程基础

    Windows核心编程 第六章 线程基础 欢迎转载 转载请注明出处:http://www.cnblogs.com/cuish/p/3145214.html 1. 线程的组成 ①    一个是线程的内核 ...

  7. Android群英传》读书笔记 (3) 第六章 Android绘图机制与处理技巧 + 第七章 Android动画机制与使用技巧

    第六章 Android绘图机制与处理技巧 1.屏幕尺寸信息屏幕大小:屏幕对角线长度,单位“寸”:分辨率:手机屏幕像素点个数,例如720x1280分辨率:PPI(Pixels Per Inch):即DP ...

  8. 第六章SignalR的服务器广播

    第六章SignalR的服务器广播 1.概述: VS可以通过 Microsoft.AspNet.SignalR.Sample NuGet包来安装一个简单的模拟股票行情应用.在本教程的第一部分,您将从头开 ...

  9. ASP.NET2.0自定义控件组件开发 第六章 深入讲解控件的属性

    原文:ASP.NET2.0自定义控件组件开发 第六章 深入讲解控件的属性 深入讲解控件的属性持久化(一) 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开 ...

随机推荐

  1. jsp:include 通过变量作为路径动态引入

    语法:<jsp:include page="<%=整体是个变量%>" flush="true"/> 示例: <%@ page la ...

  2. TAB切换与内容伸展闭合的结合

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. Waiting for table flush 阻塞查询的问题

    1.此状态表示大量thread正在等待慢查询语句执行完成. 原因: The thread got a notification that the underlying structure for a ...

  4. latex算法步骤如何去掉序号

    想去掉latex算法步骤前面的序号,如下 我想去掉每个算法步骤前面的数字序号,1,2,3,因为我已经写了step.我们只需要引用a lgorithmic这个包就可以了,代码如下: \usepackag ...

  5. ][mybatis]MyBatis mapper文件中的变量引用方式#{}与${}的差别

    转自https://blog.csdn.net/szwangdf/article/details/26714603 MyBatis mapper文件中的变量引用方式#{}与${}的差别 默认情况下,使 ...

  6. swift实现线程安全的栈和队列

    实现一个线程安全的栈 这里使用数组来存储栈的数据.不足之处在于本例中的Stack可以无限扩容,更好的是初始化时候指定一个最大容量,防止不断扩容申请内存导致内存不够的问题.这里的线程安全使用一个串行队列 ...

  7. TS中补充的六个类型

    1.  元组 元组可以看做是数组的拓展,它表示已知元素数量和类型的数组.确切地说,是已知数组中每一个位置上的元素的类型 当我们为 元组 赋值时:各个位置上的元素类型都要对应,元素个数也要一致. let ...

  8. Oracle Internals Notes Redo Write Triggers

    There are four conditions that cause LGWR to perform a redo write. When LGWR is idle, it sleeps on a ...

  9. java 小数精确计算

    小数精确计算 System.out.println(2.00 -1.10);//0.8999999999999999 上面的计算出的结果不是 0.9,而是一连串的小数.问题在于1.1这个数字不能被精确 ...

  10. 给mongodb设置密码

    内容来自:https://segmentfault.com/a/1190000011554055 mongodb安装后是无需密码 Mongodb安装后自身是没有密码的,用户连接只需填写id地址,端口号 ...