在这一章,讲Java的初始化和清除。
- 不同的初始化位置
public class Constructor_ex2 {
String s = "123";
String ss;
private static String static_s;
private static String static_ss = "static_ss_ss";
private static final String satic_ss_final = "static_ss_final_ss";
static {
static_s = "q2";
}
public Constructor_ex2() {
this.ss = "another";
}
public Constructor_ex2(int a) {
this.ss = "another + s";
}
public static void main() {
Constructor_ex2 instance = new Constructor_ex2();
}
}
例如在上面这段代码中,我们可以看到这个类中有五个变量。这里主要介绍前面四个变量初始化的位置。
s和ss都是在构造函数中初始化的,每一个构造函数都会初始化一次。这里我们可以使用javap -verbose方式查看。
![](https://img-my.csdn.net/uploads/201303/23/1363971031_8670.jpg)
这里我们可以看到,在两个构造函数中,都有对s和ss的初始化。
static_s和static_ss的初始化是在一个static方法里面的。我们同样可以使用javap -verbose查看。
![](https://img-my.csdn.net/uploads/201303/23/1363971139_3320.jpg)
- 对于基础类型在重载函数中的转化问题
这个问题很简单,就是在我们使用重构函数的时候,如果我们传入的参数没有和这个函数有完全匹配的,怎么处理?一般都是线上转型,就是一直往大的转,转到最接近的。
大小顺序如下:
char byte short int long float double.
但是在这里注意一下,char是特殊的,如果没有完全符合char的函数,就会直接跳到int去找,而不会找byte和short.
- 为什么不能使用返回值来进行重载
在面试的时候,我们经常会被问道,Java中根据什么进行重载的,这里是根据参数表。那为什么不能根据返回值呢?因为我们在调用有返回值的函数时,我们也可以不用变量接否这个函数的返回值。如下:
public void fi() {
}
public int f1() {
return 1;
}
f1();
想上面这样,编译器就不能知道我们具体要调用哪个函数了。
- finalize() 和 System.gc()
在Java中,没有析构函数的概念。当对象被JVM消除的时候,会自动调用finalize()的方法。我们也可以使用System.gc()强制调用一些可以被消除对象的finalize()方法。
public class temp {
int a;
@Override
protected void finalize() {
System.out.println("clean up");
}
public static void main(String args[]) {
temp instance = new temp();
instance=null;
System.gc();
}
}
- Java内存回收机制 Reference Counting
Reference Counting是每一个对象都有一个Reference Counting,当有新的reference指向这个对象的时候,Reference Counting就会增加。当这个对象的引用退出了作用域,或者被置为null后,Reference Counting就会减少。当Reference Counting是0的时候,这个对象就会被回收掉。但是如果存在对象之间的循环引用,那这样即使Reference Counting不为0,某些对象仍然要被消除。这就需要GC做一些额外的工作了。这种机制似乎没有被使用到任何的JVM中。
- Java内存回收机制 寻找能到达的对象。
这种方法是,我们从stack或者在stack storage中开始,因为对象的引用都是放在这里。然后我们顺着引用,就能找出所有通着这些引用能达到的对象。那这些能达到的对象都是不能被回收的,其他的就是可以的。所以就算是循环引用,也能通过这种方法gc掉。
有关JVM中对内存分配更加详细的内容,在可以看看我的另外的一篇文章。
- 一个类中的field的初始化
field的初始化可以在定义的时候初始化,也可以使用默认的初始值,或者在构造函数中进行初始化。但是这里,我们在构造函数进行初始化的前,会先进行前两部的初始化。下面的例子会让我们看到这样的过程。
public class temp {
int a = 2;
int b;
public temp() {
System.out.println("a = " + a);
System.out.println("b = " + b);
this.a = 1;
}
public static void main(String args[]) {
temp instance = new temp();
}
}
- 初始化的整理过程
- 这类使用书上的方式,我们使用Dog作为例子进行说明。当我们第一次创建Dog或者使用到Dog类的时候,我们需要找到Dog.class。
- 在我们找到找到Dog.class后,我们载入Dog.class,在这过程中,这个类中的全部的静态变量将会被初始化。
- 当我们使用new来创建一个Dog对象的时候,我们会在Heap上找到一块空间来创建这个对象。
- 我们选择的这个空间会被初始化为0,所以我们在这个空间上创建Dog对象,初始值都是为0的。
- 然手是执行我们在field定义时做的初始化。
- 执行构造函数。
- 初始化的顺序
- 静态变量初始化,包括static模块,执行的循序和定义的顺序是一样的
- 非晶态的初始化,包括 instance 模块,顺序和定义顺序一样。
- 构造函数。
- 使用...来定义变长变量
当我们不知道一个函数接收的变量有多少个的时候,我们可以使用数组作为参数,我们也可以使用...。如下:
void cal(int... b) {
for (int i=0 ; i<b.length ; i++) {
System.out.println(b[i]);
}
}
public static void main(String args[]) {
temp instance = new temp();
instance.cal(1 , 2 , 3);
}
但是我们不能利用这个进行函数的重载,会发生错误。如:
void cal(Character... c) {
for (int i=0 ; i<c.length ; i++) {
System.out.println(c[i]);
}
}
void cal(int... b) {
for (int i=0 ; i<b.length ; i++) {
System.out.println(b[i]);
}
}
public static void main(String args[]) {
temp instance = new temp();
instance.cal(1 , 2 , 3);
instance.cal('1' , '2' , '3');
}
下面是显示的错误:
![](https://img-my.csdn.net/uploads/201303/24/1364133172_5759.jpg)
如果我们需要两个变长参数的函数,我们需要在两个函数中每个函数中添加一个特有的变量,一定要在每一个函数中都添加,如下:
void cal(char c , char... b) {
for (int i=0 ; i<b.length ; i++) {
System.out.println(b[i]);
}
}
void cal(int a , char...b) {
for (int i=0 ; i<b.length ; i++) {
System.out.println(b[i]);
}
}
public static void main(String args[]) {
temp instance = new temp();
instance.cal(1 , '2' , '3');
instance.cal('1' , '2' , '3');
}
但是下面的程序中,会发生编译错误,但是我不知道怎么解释,请大神们帮忙看看为什么会出错。。。
![微笑](http://static.blog.csdn.net/xheditor/xheditor_emot/default/smile.gif)
void cal(char c , char... b) {
for (int i=0 ; i<b.length ; i++) {
System.out.println(b[i]);
}
}
void cal(int a , int...b) {
for (int i=0 ; i<b.length ; i++) {
System.out.println(b[i]);
}
}
public static void main(String args[]) {
temp instance = new temp();
instance.cal(1 , 2 , 3);
instance.cal('1' , '2' , '3');
}
上面的程序会出现编译错误,如下:
![](https://img-my.csdn.net/uploads/201303/24/1364137339_1859.jpg)