3.初始化与清理(上)

3.初始化与清理(上)-四曲博客
3.初始化与清理(上)
此内容为免费阅读,请登录后查看
0
免费阅读

用构造器确保初始化

  • 为了保证对象被创建时进行初始化,因此在创建对象时,会自动调用相应的构造器,从而保证了初始化的进行
  • 构造器采用与类相同的名称
  • 不接受任何参数的构造器叫做默认构造器,java术语成为无参构造器,当然,也可以使用有参构造器
  • 从概念上讲,“初始化”与“创建”是彼此独立的,但是在java中两者是绑定在一起的
  • 构造器是一种特殊类型的方法,因为它没有返回值,这与返回空值不同,返回空值,尽管方法本身不会自动返回什么,但是仍然可以选择返回别的东西,构造器则不会返回任何东西
package charpter05;

public class InitClass {
    InitClass(){
        System.out.println("InitClass");
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new InitClass();
    }
}
//运行结果:
//InitClass

方法重载

  • 由于需要用不同方式来对对象进行初始化,因此需要多个相同类名的构造器,必须用到方法重载
  • 计算机可以按照参数列表的不同来区分相同名字的方法,因此,只要参数列表不同,那么就是不同的方法
  • 涉及基本类型的参数:如果传入的数据类型小于方法中声明的形式参数类型,实际的数据类型就会被提升;如果方法接受较小的基本类型作为参数。如果传入的实际参数较大,就得通过类型转换来执行窄化转换。如果不这样做,编译器就会报错
  • 不能以返回值来区分重载方法
package charpter05;

public class test5_2 {
    test5_2(int i){
        System.out.println(i);
    }

    test5_2(){
        System.out.println("init");
    }

    public static void main(String[] args) {
        new test5_2(5);
        new test5_2();
    }
}
//运行结果:
//5
//init

默认构造器

  • 如果你的类中没有构造器,则编译器会自动帮你创建一个默认构造器
  • 如果你写了一个构造器,则编译器就不会自动创建默认构造器,因此这个时候如果调用一个没有定义的构造器,则会出错
package charpter05;

public class test5_3 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new test5_3();  //使用默认构造器,正确
    //  new test5_3(i);   调用没有定义的构造器,错误
    }
}

this关键字

  • 如果你希望在方法的内部获得对当前对象的引用,就可以使用this关键字
  • this关键字只能在方法内部使用,表示对“调用方法的那个对象”的引用
  • 如果在方法内部调用同一个类的另一个方法,就不必使用this关键字
package charpter05;
 class Leaf{
    Leaf increament() {
        return this;
    }

    public void say() {
        System.out.println("你好");
    }
}

public class test5_4 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Leaf a=new Leaf();
        a.increament().say();
    }
}
//运行结果
//你好

在构造器中调用构造器

  • 利用this可以在构造器中调用另一个构造器,但是不能调用两个
  • 必须将构造器调用置于最起始处,否则编译器会报错
  • this的另一种用法,为了避免参数名称与数据成员名称的冲突,使用this关键字来解决
package charpter05;

public class test5_4_1 {
    String s="世界";

    test5_4_1(){
        this(2,"this");
    }
    test5_4_1(int i,String s){
        System.out.println("你好,"+this.s);
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        test5_4_1 a=new test5_4_1();
    }
}
//运行结果:
//你好,世界

static的含义

  • 在static方法的内部不能调用非静态方法,但是可以通过传入对象引用的方式来使用非静态方法
  • static方法就是没有this的方法

清理:终结处理和垃圾回收

如果一个对象不是经由new关键字进行创建的,java垃圾回收器可能不知道该如何去释放该对象的这块“特殊”区域

因此,java中定义一个名称为finalize()的方法,一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法

finalize()与C++中析构函数不同,在C++中,对象一定会被销毁,而java里的对象却并非总是被垃圾回收(对象可能不被垃圾回收;垃圾回收并不等于“析构”)

finalize()的用途何在

java具有垃圾回收机制,因此,finalize()函数主要用于某种创建对象方式以外的方式为对象分配的存储空间

之所以要使用finalize(),是由于在分配内存时采用了其他的方式

你必须实施清理

在java当中的的垃圾回收并不一定会发生,如果java虚拟机没有面临内存消耗的问题,那么它是不会浪费时间来进行垃圾清理的

终结条件

finalize()函数还可用于对终结条件的验证

package charpter05;

class Book {
    boolean checkedOut=false;

    Book(boolean checked){
        checkedOut=checked;
    }

    void checkedIn() {
        checkedOut=true;
    }

    protected void finalize() {
        if(checkedOut) {
            System.out.println("checkedIn error");
        }
    }
}

public class test5_4_3 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Book na=new Book(true); //第一次创建
        na.checkedIn();

        new Book(true);         //第二次创建
        System.gc();
    }
}
//运行结果
//checkedIn error

在上面的这个程序中,终结条件就是必须要执行checkedIn()函数,但是在第二次执行的时候,没有执行,因此在使用System.gc()调用垃圾回收时,就会检查出错误,对于有的时候,能够检查出程序的缺陷,从而能够正确的解决问题

垃圾回收器如何工作

以下解释了几种垃圾回收机制

引用计数,这是一种简单但速度很慢的垃圾回收,每个对象都含有一个引用计数器,当有引用连接至对象时,引用计数加1,当引用离开作用域时或者被设定为null时,引用计数器减1,引用为0时,就释放空间,但是,如果对象被循环引用,此时没有离开作用域,引用计数器不会减少,原本对象应该被回收,但是引用计数器却不为0,就无法回收。

遍历,对“活”的对象来说,一定能追溯到其中活在堆栈或静态存储区之中的引用,这个引用链条可能会穿过数个“活”对象,对于发现的每个引用,必须追踪它所引用的对象,然后是此对象包含的所有引用,如此反复进行,直到遍历完为止

停止—复制技术,先暂停程序,然后将所有活对象从当前堆复制到另外一个堆,没有被复制的都是垃圾,复制到新推时,是一个个紧凑排列的,就可以更方便的分配空间,这样方式有两个问题:一是会有额外的开销,二是对于一个稳定的程序来说,可能只会产生少量的垃圾,这样的复制可能就会很浪费

标记—清扫技术,遍历所有引用,然后每找到一个存活的对象就对它进行标记,让遍历完成后,没有标记的对象会被清理,虽然不会发生任何复制动作,但是剩下的空间是不连续的,不利于重新分配

在这里讨论的java虚拟机中,内存分配以较大的“块”为单位进行,如果文件较大,会占用单独的“块”,停止—复制技术可以将复制的活对象放在废弃的块中,每个块都用相应的代数来记录它是否还存活,通常,如果块在某处被引用,则代数被增加,垃圾回收器对块进行整理,以便于下次分配。java虚拟机会进行监视,如果所有对象都很稳定,就切换成标记—清扫模式,要是推中有很多碎片,就使用停止—复制模式

除了以上几种以外,java虚拟机中也有许多附加技术用以提升速度,比如:“即时”编译器技术

© 版权声明
THE END
喜欢就支持以下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容