第四章:控制执行流程
本章介绍了大多数编程语言都具有的基本特性:运算、操作符优先级、类型以及选择和循环等。例如布尔表达式、循环如while、do-While、for、分支判断如if-else以及选择语句switch-case-break等。由于本章的内容都是非常基础的语法知识,这里不再赘述。
第五章:初始化和清理
在Java中,通过提供构造器,类得设计者可以确保每个对象都会得到初始化。创建对象时,如果其类具有构造器,Java就会在用户有能力操作对象之前自动调用相应的构造器,从而保证了初始化的进行。对于不再使用的内存资源,Java提供了垃圾回收器机制,垃圾回收器会自动地将其释放。
为什么不能以返回值区分重载方法?
比如下面两个 方法,虽然他们有同样的方法名称和形参列表,但却很容易区分它们:
public void f(int i);
public int f(int i) { return i; }
只要编译器可以根据语境明确判断出语义,比如在 int x = f(1)中,那么的确可以据此区分重载方法。不过,有时我们并不关心方法的返回值,我们想要的是方法调用的其它效果(这通常被称为“为了副作用而调用”),这时你可能会调用方法而忽略其返回值,如这样调用方法:f(1),此使Java如何才能判断你调用的哪一个f(int i)方法呢?因此,根据方法的返回值来区分重载是行不通的。
静态数据的初始化
无论你创建多少个对象,静态数据都只占用一份存储区域。static关键字不能应用于局部变量,因此它只能作用于域。如果一个域是静态的基本类型域,且没有对他进行初始化,那么它就会获得基本类型的标准初始值,如果它是一个对象引用,那么它的默认初始值就是null。
静态数据初始化示例如下:
public class StaticInitialization {
public static void main(String[] args) {
System.out.println("Creating new Cupboard() in main");
new Cupboard();
System.out.println("Creating new Cupboard in main");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table = new Table();
static Cupboard cupboard = new Cupboard();
}
class Bowl {
Bowl(int marker) {
System.out.println("Bowl(" + marker + ")");
}
void f1(int marker) {
System.out.println("f1(" + marker + ")");
}
}
class Table {
static Bowl bowl1 = new Bowl(1);
Table() {
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int marker) {
System.out.println("f2(" + marker + ")");
}
static Bowl bowl2 = new Bowl(2);
}
class Cupboard {
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
Cupboard() {
System.out.println("Cupboard");
bowl4.f1(2);
}
void f3(int marker) {
System.out.println("f3(" + marker + ")");
}
static Bowl bowl5 = new Bowl(5);
}
/* Output:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard
f1(2)
Creating new Cupboard in main
Bowl(3)
Cupboard
f1(2)
f2(1)
f3(1)
*/
总结一下对象的创建过程,假设有个名为Dog的类:
即使没有显示地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog的对象时(构造器可以看成静态方法),或者Dog类得静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
然后载入Dog.class,有关静态初始化的所有动作都会执行,因此,静态初始化只在Class对象首次被加载的时候进行一次。
当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值,而引用则被设置成了null
执行所有出现于字段定义处的初始化动作
执行构造器
3.finalize()的用途何在?
无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存,这将对finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间,但Java中一切皆为对象,那这种特殊情况是怎么回事呢?
看来之所以要有finalize()方法,是由于在分配内存时可能采用了类似C语言中的做法,而非Java中的通常做法,这种情况主要发生在“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式,本地方法目前只支持C和C++,但它们可以调用其他语言写的代码,所以实际上可以调用任何代码。在非Java代码中,也许会调用C的malloc()函数系列来分配存储空间,而且除非调用了free()函数,否则存储空间将永远得不到释放,从而造成内存泄漏,当然,free()是C和C++中的函数,所以需要在finalize()中用本地方法调用它。
记住,无论是“垃圾回收”还是“终结”,都不保证一定会发生,如果Java虚拟机(JVM)并未面临内存耗尽的情形,它是不会浪费时间去执行垃圾回收以恢复内存的。
如下例,示范了finalize()可能的使用方式:
public class TerminationCondition {
public static void main(String[] args) {
Book novel = new Book(true);
// proper cleanup
novel.checkIn();
// Drop the reference, forget to clean up
new Book(true);
// 强制进行终结动作,并调用finalize()
System.gc();
}
}
class Book {
boolean checkOut = false;
Book(boolean checkOut) {
this.checkOut = checkOut;
}
void checkIn() {
checkOut = false;
}
@Override
protected void finalize() {
if (checkOut) {
System.out.println("Error: checked out");
// 你应该总是假设基类的finalize()也要做某些重要的事情,因此要用super来调用它
// super.finalize();
}
}
}
本例的总结条件是:所有的Book对象在被当作垃圾回收前都应该被签入(check in),但在main()方法中,由于程序员的错误,有一本书未被签入,要是没有finalize()来验证终结条件,将很难发现这种缺陷。
标签:Cupboard,思想,编程,Bowl,System,static,new,Java From: https://www.cnblogs.com/LvJinshuai/p/16998352.html