您的位置:首页 > 编程语言 > Java开发

初始化与清理

2016-12-02 15:28 134 查看
# 初始化和清理

这是个涉及安全的两个问题,许多c程序的错误都源于程序员忘记初始化变量,c++中引入了构造器,java也采用了构造器,并额外提供垃圾回收器,对不再使用的内存资源,垃圾回收器自动将其释放掉.

用构造器确保初始化

构造器的命名,第一,不能和成员名称冲突;第二,调用构造器是编译器的责任.所以采用与类名相同的名称.延用c++的.

如果你的类里不写构造函数,java默认加上无参的构造函数.如果你写了构造函数,java就不会给你自动加了.构造函数无返回值.

练习2:一个在定义时就被初始化的String,以及另一个通过构造函数初始化的String,有什么差异?

1.构造函数灵活,可以根据需要赋值,而定义时的一直是那个值.

2.定义时初始化先于构造函数初始化.

方法的重载

构造器的名字确定,那如果想要使用多种方法创建一个对象,那只能通过方法的重载了.

基本类型的重载:较小的会自动提升成一个”较大”的类型,比如int->double或float,char->int;如果传入的类型”较大”,必须强制窄化处理了.

区分重载函数:

1. 规则很简单,每个重载的方法都必须有一个独一无二的参数类型列表.甚至参数的顺序不同也可以!一般别这样,很难维护.

2. 不能通过返回值来重载方法,比如代码:

void f(){}

int f(){return 1;}


有时候我并不关心返回值是什么,我只是想要方法调用的过程效果,使用f();编译器无法分辨我想要哪个方法.

this关键字

在构造函数里可以调用另一个构造函数,比如

class Dog{
private int age;
private String name;
Dog(int age){
this.age = age;
}
Dog(int age,String name){
Dog(age);
this.name = name;
}
}


在参数和数据成员名称重复时候也可以使用this关键字.

除了构造函数之外,编译器禁止在其他任何方法中调用构造函数.

终结处理和垃圾回收

对象可能不被垃圾回收

垃圾回收并不等于”析构”

垃圾回收只与内存有关

甚至可以肤浅的认为,正是由于垃圾回收器的存在,使得java没有析构函数,随着学习的深入,你会明白垃圾回收器并不能完全代替析构函数.

如果JVM并未面临内存耗尽的情况,它是不会浪费时间去执行垃圾回收以恢复内存的.

System.gc()用于强制进行终结动作.

垃圾回收器如何工作

以前的语言中,在堆上分配对象代价很大,但是java所有对象(除了基本类型)都是在堆上分配的方式也非常高昂,然而,垃圾回收器对于提高对象的创建速度,却有着明显的效果,存储空间的释放竟然影响存储空间的分配,但这确实是java虚拟机的工作方式.

在它工作时,一面回收空间,一面使堆中的对象紧凑排列,这样堆指针就可以很容易地移动到更靠近传送带的开始处,避免了页面错误,通过对对象的重新排列,实现了一种高速的,有无限空间可分配的堆模型.

引用计数模式

这是一种简单但速度很慢的垃圾回收技术,但引用离开作用域或被置为null时,引用计数减1,有引用连接对象时,引用加1,虽然管理计数开销不大,但是在整个程序的生命周期中都持续发生,垃圾回收器会在含有全部对象的列表上遍历,发现某个对象的引用计数为0时候.就释放(通常是立即释放).但是如果对象之间存在循环引用,可能出现’对象应该被回收,但是引用计数却不为零’,对垃圾回收器而言,定位对象组工作量大.所有它经常被用来说明垃圾收集的工作方式,但似乎未被应用于任何一种java虚拟机中.

在一些更快的模式中,并非基于引用计数,从堆栈和静态存储区开始,遍历所有的引用,找到所有活的对象,然后是此对象包含的所有引用,直到全部被访问完为止,你所访问的对象必须是活动的,这就解决了交互自引用的对象组.

java虚拟机采用一种自适应的垃圾回收技术,如何处理活动的对象,每个虚拟机做法不同,有一种叫stop-and-copy,显然这意味这先暂停,(它不属于后台回收模式),将所有活动的对象从当前堆复制到另一个堆,没被复制的都是垃圾,到了新堆,就是一个挨着一个,保持紧凑.

这种方式需要更新引用指向,位于堆或者静态存储区的可以直接修正,但其他指向对象的引用,在遍历时候才能被找到(可以想象成有个表格,将旧地址映射至新地址).

复制式回收器,效率降低,首先要有两个堆,然后在两个堆来回倒腾,维护比实际多一倍的空间.某些虚拟机处理方式是,按需从堆中分配几块较大的内存,复制动作发生在这些大块内存之间.

然后是复制的问题,程序稳定后,垃圾很少,甚至没有,尽管这样,回收器仍然会将内存从一处复制到另一处,这很浪费;为了避免,一些虚拟机会检查,要是没垃圾产生,转换到另一种模式(自适应),标记-清扫.sun公司早期版本的java虚拟机使用这种技术.

标记-清扫的思路是从堆栈和静态存储区出发,遍历所有的引用,每次找到一个对象设置标记,全部标记完成后,没有标记的释放,所以剩下的堆是不连续的,回收器要是希望得到连续空间的话,就得重新整理剩下的对象.也是程序暂停执行.

垃圾回收器根据情况进行切换技术,stop-and-copy和mark-and-sweep.

成员初始化

方法的局部变量,会在编译时得到错误消息.

类的数据成员是基本类型,都会有默认值.

类的数据成员是对象引用,不初始化就会得到null;

指定初始化

类的数据成员是基本类型,直接赋值就行.

但是引用顺序要正确,比如下面的就不对了:

int j = g(i);
int i = f();
int f(){return 1;}
int g(int n){return n*10;}


你会得到非法向前引用的编译错误!

初始化的顺序

变量定义的先后顺序决定了初始化的顺序,即使变量定义散布于方法定义之间,它们仍旧会在任何方法被调用之前初始化!

静态成员的初始化

先看代码示例:

/**
* Created by samp on 16-12-2.
*/

import static java.lang.System.out;

class Bowl {
Bowl(int m) {
out.println("bowl
4000
:" + m);
}

void f1(int m) {
out.println("f1 " + m);
}
}

class Table{
Bowl bowl3 = new Bowl(3);
static Bowl bowl1 = new Bowl(1);
Table(){
out.println("table");
bowl2.f1(1);
}
void f2(int m){
out.println("f2 " + m);
}
static Bowl bowl2 = new Bowl(2);
}

public class StaticInitialization {
public static void main(String[] args) {
out.println("creating new table");
new Table();
}
static Table table = new Table();
}
/*
bowl:1
bowl:2
bowl:3
table
f1 1
creating new table
bowl:3
table
f1 1
*/


静态成员初始化在必要时刻才会被执行,如果不创建该类的对象,或者引用对象静态成员,静态对象不会被创建,在第一个Table对象或者第一次访问静态成员时候,它们会被初始化,此后都不会再被初始化.

初始化顺序是先静态对象(第一次”访问”),然后是非静态成员变量,最后是构造函数.在Class对象首次加载的时候进行一次.

static代码块也是相同与静态变量.假如不带static修饰,那就和普通成员变量一样执行.

static Bowl bowl4;
static {
bowl4 = new Bowl(4);
}
```

## 可变参数列表
看代码示例:
```java
public class Varargs {
static void printArray(Object[] args) {
for (Object obj : args) {
System.out.print(obj + " ");
}
System.out.println();
}
static void printArray2(Object... args) {
for (Object obj : args) {
System.out.print(obj + " ");
}
System.out.println();
}
public static void main(String[] args) {
printArray(new Object[]{new Integer(12), new String("a"), new Float(0.5)});
printArray2(new Integer(12), new String("sad"), null);
printArray2();
}
}
/*
12 a 0.5
12 sad null
//注意这里是空行,就是无参的那个输出的,第一种方式不支持无参
*/


可变参数是Java SE5引进的,原理上好像和第一种差不多,但是省去写数组的麻烦,而且第一种不支持无参.可变参数列表可以是任意类型.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息