第五章 初始化与清理

1、构造器的作用

  • 构造器采用与类名相同的名称,初始化期间自动调用构造器:new Rock()将会为对象分配内存空间,并调用相应的构造器;
  • 构造器有助于减少错误,使代码易于阅读;

创建一个类,它包含一个在定义时就被初始化了的String域,以及另一个通过构造器初始化的String域,两种方式有何差异?

-> 定义时期的初始化次数为1次

    构造器初始化为两次:① 首先编译器发现变量未初始化,赋予正确的值;

                                        ② 在构造方法中再次赋值;

2、什么是重载

重载即一个类中的多种构造器(含有相同的名字/类名)有不同种参数同时存在,只能以参数的不同来区分(参数顺序不同也是不同的构造器)。

class Flower {
    grow() {
        print("还是花苞");
    }
    grow(String s) {
        print(s + "开花了!");
    }
}

3、this关键字

3.1 this的用法

  • 在方法内部,this表示“”调用方法的那个对象“的引用,例如当需要返回当前对象的引用时;
public class Leaf {
    int i;
    Leaf increment() {
        i++;
        return this;
    }
}
  • this关键字对于将当前对象传递给其他方法也很有用;
package nuc.test;

class Person {
	public void eat(Apple apple) {
		Apple peeled = apple.getPeeled();    //将apple对象传递给peeler的peel方法
		System.out.println("Yummy");
	}
}

class Apple {
	Apple getPeeled() {
		return Peeler.peel(this);
	}
}

class Peeler {
	static Apple peel(Apple apple) {
		//remove peel
		return apple; //peeled
	}
}

public class test1 {
	public static void main(String[] args) {
		new Person().eat(new Apple());
	}
}
	
  • 在构造器中调用构造器
public class test1 {
	public test1() {
		// TODO Auto-generated constructor stub
		this("炜炜");
	}
	test1(String s) {
		System.out.println("希望未来有你," + s);
	}
	public static void main(String[] args) {
		test1 t = new test1();
		
	}
}
  • 编译器禁止在任何方法中调用构造器

3.2 遗留问题

  1. 为什么可以用this调用一个构造器,却不能调用两个?
  2. 为什么必须将构造器调用放在最起始处?
  3. 为什么禁止在其他方法中调用构造器?

答:

  1. 一个对象只能实例化一次,也就是说,由某个类创建的对象要唯一;
  2. Java在操作对象之前,需要确保每个对象都能够得到实例化,因此调用相应的构造器确保初始化的进行;
  3. 如果在其他方法中调用了构造器,那么实例化对象之后,若调用含有构造器的该方法,会导致对象再次被编译器默认初始化;(目前自己这么理解,若有补充或错误请及时指正

4、static方法

4.1 定义

  • 就是没有this的方法;
  • 在static方法中不能调用非静态方法;
  • 可以在不创建对象的前提下,仅仅通过类本身来调用static方法;
  • 不可以在static方法中定义static变量,但可以引用,static变量又叫做类变量,就是说它和方法是处在同一个位置的,没有包含被包含的关系。方法中可以引用static变量,但是不可以在方法中定义即使static变量即使该方法是static方法~ 同样的main里面也不可以;
class test2 {
	static void test1() {
		System.out.println("test2()");
	}
}
public class test1 {
	public static void main(String[] args) {
		test2.test1();;
		
	}
}
	

4.2 为什么static里面不能含有this

因为static方法和类的实例(对象)是两码事,它只在类装载的时候(即编译的时候或者javac命令的时候)初始化,被称作类级变量(属于类);而类的实例是在程序运行的时候(即Java命令的时候)初始化,被称作对象级变量(属于对象);

this表示这个类的当前实例,super表示父类的当前实例,static是属于类的,this是类的一个对象,当然调用了不了他,static太牛了,只有类名可以调用它,static叫静态方法,也叫类方法,就是在程序启动的时候,就会为这个方法分配一块内存空间,所以什么时候都可以调用这个方法。所以,静态方法里不能调用非静态方法,除非你先实例化那个类,像这样:

package nuc.housy;

import static nuc.test.Print.*;

public class test1 {
	public static void tes() {
		test1 t = new test1();
		t.tes1();
		print("我是静态方法");
	}
	void tes1() {
		print("我是非静态方法");
	}
	public static void main(String[] args) {
		print("我是一");
	}
}

如果在static修饰的方法中使用this关键字,而这个关键字就无法指向合适的对象;所以我们也说,静态成员不能直接访问非静态成员;jvm有类加载器,第一次加载类时执行类中的static域,jvm会专门划分一个内存区域给static程序块,可以成为静态区,属于这个类。this指针是指向类的对象,在实例化对象时jvm会在区分配内存给一个具体的对象,this指针指向这个对象。而类中的static域始终是在静态区分配内存,this指向堆区,所以不能调用。static是属于类的,this是对象指针

而堆不是在静态存储区的,属于动态存储区,所谓静态,就是会永恒存在、不会消失,这样的数据包括常量、常变量、静态变量、全局变量等;动态的区域,就是堆栈,在第一章里写到过:

  • 栈区:也叫栈内存,主管java程序的运行,实在线程创建的时候创建,他的生命周期是跟随线程的生命周期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,生命周期与线程一致,基本类型的变量对象的引用变量都是在函数的栈内存中分配,分为三个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。 
  • 堆区:是jvm中最大的,应用的对象数据都存储在这个区域,这块区域也是线程共享的,也是gc主要回收区,一个 JVM 实例只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,以方便执行器执行,堆内存分为三部分:新生代、年老代、永久代。
  • 方法区:方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在此定义。简单说,所有定义的方法的信息都保存在该区域,此区域属于共享区间。静态变量+常量+类信息+运行时常量池存在方法区中,实例变量存在堆内存中。 

  • 1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。 
    2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。 


 

 5、清理和垃圾回收(一般不用

finalize()方法类似于c++中的析构函数;

  • 析构函数,在对象销毁时自动调用,若不销毁则不调用;
  • finalize方法,一旦垃圾回收器准备释放对象占用的存储空间,首先调用finalize方法;

6、垃圾回收的工作原理 (没有太明白

回收机制名称优点缺点简要说明
引用计数简单、速度慢若对象存在循环引用时,工作量很大每个对象都含有一个引用计数器,当有引用连接至对象时,引用计数加一,当引用离开作用域时或被置为null,引用计数减一;

 

自适应  

① 停止 - 复制

② 标记 - 清扫

 

7、成员初始化

  • 默认初始化:对象默认成null,其他基本类型默认给定一个正确的值;
  • 指定初始化:即字面量;
  • 构造器初始化:在自动初始化之后执行;

7.1初始化顺序

  • 非静态数据初始化:在调用构造器或者其他方法之前初始化;
  • 静态数据初始化:静态数据初始化只有在必要时刻才进行,如果不创建带有静态数据的对象,也不再调用带有静态数据的对象的方法,将不会初始化;
  • 初始化顺序:先静态对象,而后非静态对象;
  • 显示静态初始化:尽管看起来像个方法,实际姿势一段跟在static关键字后面的代码。与其他初始化动作一样,这段代码仅执行一次:首次生成这个类的一个对象时,或者首次访问属于这个类的静态数据成员时(即便从未生成过这个对象)
    public  class  Spon {
    
        static  int  i;
        static  {
            i = 47;
        }
    }

    ------->这篇博客有详细说明:https://blog.csdn.net/hou_shiyu/article/details/95002777

  • 非静态实例初始化:这种语法对支持匿名内部类是必须的,且无论调用了哪个显式构造器,某些操作都会发生,可以理解成非静态变量的初始化执行多次;

    public  class  Spon {
    
        int  i;
        {
            i = 47;
        }
    }

     

8、数组

8.1 数组初始化

int[] a1;         [1]
int a1[];         [2]

int[] a1 = {1,2,3,4};
int[] a2 = a1;   //这样只是复制了一个引用,也就是说,a2指向的值若发生改变,a1中也会发生变化

Integer[] a = {
    new Integer(1),
    new Integer(2),
    3, 
}  //最后的逗号可以省略      [3]

Integer[] b = new Integer[] {
    new Integer(1),
    new Integer(2),
    3,
}                          [4]

 

8.2 可变参数列表 

  • 可变参数列表不依赖于自动包装机制
class test2 {
	static void test1(int...args) {
		System.out.println(args.length);
	}
}
class test3 {
	static void test1(Integer...args) {
		System.out.println(args.length);
	}
}

public class test1 {
	public static void main(String[] args) {
		test2.test1(1,2,3);
        test2.test3(1,2);
	}
}
  •  自动包装机制会有选择地将int参数提升为Integer

9、enum

  • ordinal() : 表示特定的enum常量的声明顺序;
  • 结合switch使用;

参考博客:http://blog.itpub.net/30046312/viewspace-2143647/

                  https://blog.csdn.net/lin542405822/article/details/80338256

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值