02_初始化与清理

本文详细介绍了Java中的对象初始化,包括构造器的作用、方法重载规则、默认构造器的使用,以及this关键字的应用。此外,还讲解了Java垃圾回收机制的原理,如引用计数法和停止-复制、标记-清扫策略。同时,讨论了静态和实例代码块的执行时机和作用,以及数组的初始化和可变参数列表的使用。最后,简单介绍了枚举类型及其特性。
摘要由CSDN通过智能技术生成

java初始化与清理

1.用构造器确保初始化

创建对象时,Java会在用户操作对象之前自动调用相应的构造器从而保证了初始化的进行。

  • 构造器与类名相同。
  • new Dwx(); 创建一个对象,为对象分配存储空间,并调用相应的构造器。
  • Java中,”初始化“和”创建“捆绑在一起,两者不能分离。
  • 构造器是特殊的方法,没有返回值。

2.方法重载

  1. 区分方法重载看方法的参数列表是否独一无二,不可以根据返回值来区分重载方法。
  2. 参数为char类型时,如果无法找到恰好接受char参数的方法,就会把char直接提升至int型。

3.默认构造器

  1. 默认构造器(又名”无参构造器“)是没有形式参数的,它的作用是创建一个”默认对象“。
  2. 表达式 new Bird() , 创建了一个新对象,并调用其默认构造器。
  3. 如果定义了一个构造器(无论是否有参数),编译器就不会再帮你自动创建默认构造器。

举个栗子:
Bird b = new Bird(99);
如果继续使用new Bird()则会报错


4.this关键字

注:

  1. this关键字只能在方法内部使用,表示对”调用方法的那个对象“的引用。
  2. 在方法内部调用同一个类的另一个方法,就不必使用this,直接调用即可。
  3. 可以用this调用一个构造器,但不能调用两个,必须将构造器调用置于最起始处!
4.1 static的含义

static方法就是没有this的方法,在static的方法内部不能调用非静态方法。但是可以传递一个对象的引用到静态方法里,然后这个引用(和this效果相同),就可以调用非静态方法和访问非静态成员。

4.2 java垃圾回收器
  1. 垃圾回收器对于提高对象的创建速度,有明显的效果,问题来了,垃圾回收是释放对象,而关创建对象什么事?
  • 首先了解一下Java是如何在堆上分配内存的,Java使用“堆指针”,每分配一个对象,指针就往后移一位,类似于堆栈,这样就达到了高速创建对象,但这样的方法带来了弊端,在堆栈中还可以出栈来释放,在堆里你没有出栈啊,不一会堆(内存)就满了,就要放磁盘上去,非常浪费时间。那么这时候垃圾回收装置就介入了,他帮助我们回收空间,并处理因为释放对象而产生的碎片(因为有的对象可能比较小,释放后就空了一块内存,比如大小为5,但是其他对象的大小都在10以上,那么这块内存就是碎片了,别的对象根本就放不进去)。有了垃圾回收器,所以java才能使用“堆指针”来创建对象,所以说垃圾回收器对创建速度有明显的效果
  1. Java垃圾回收器的具体机制
  • 2.1 引用计数法
    就是每个对象都有一个标志,每次被引用1次就加1,如果引用为0,那么就会去回收,但会有特殊情况,如果两个对象在堆里,互相引用,那么使用这种方法就失效了,所以java中不用这种方法。
  • 2.2 停止-复制(stop-and-copy)和标记-清扫(mark-and-sweep)
      这两个思想是相同的,不同具体实现略有不同。这两种方式需要程序暂停才能工作。
    首先从堆栈或静态存储区开始,遍历所有的引用,根据引用找到对象,再遍历查看找到对象中的引用,依次下去,这样就避免的互相引用的问题,因为如果互相引用,那么在堆栈中根本就不会出现.
    停止-复制就是在开辟一个堆,然后把“活”的引用复制到堆中,不过开辟堆实在太浪费,感觉就在把一个堆划分成不同的块,在块中复制。
    标记-清扫就是“活”的对象给个标记,先找出打好标记,然后在回收。Java虚拟机可以自适应切换两种方法,因为如果在很少需要回收的对象时,如果还使用停止-复制未免也太浪费了,如果一直用标记-清扫,那么就会产生很多的碎片,有很多碎片的时候就用停止-复制,因为复制到另一个块中,程序自然会去把对象排列好。
4.3 构造器初始化
4.3.1 静态数据的初始化

无论创建创建多少对象,静态数据都只占用一份存储区域。

总结:对象的创建过程,假设又个Dog类:

1. 即使没有显示地使用static关键字,构造器实际上也是静态方法。因此当首次创建类型为Dog对象时(构造器可以看成静态方法),或者Dog类的静态方法/静态域首次被访问时,java解释器必须查找类路径,以定位Dog.class文件。 2. 然后载入Dog.class(将创建一个Class对象),有关静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。 3. 当用new Dog()创建对象的时候,首先在堆上为Dog对象存储空间。 4. 这块存储空间会被清0,自动将Dog对象中所有基本类型数据都设置成默认值。(对数字、布尔类型和字符型来说就是0),引用则设置成null。 5. 执行所有出现于字段定义处的初始化动作。 6. 执行构造器!

5. 代码块

类的成分:
​ 1.成员变量
​ 2.构造器
​ 3.成员方法
​ 4.代码块
​ 5.内部类

代码块按照有无static可以分为静态代码块和实例代码块。

5.1 静态代码块

静态代码块
​ 必须有static修饰,必须放在类下。与类一起加载执行。

格式

static{
     // 执行代码
}

特点

  • 每次执行类,加载类的时候都会先执行静态代码块一次。
  • 静态代码块是自动触发执行的,只要程序启动静态代码块就会先执行一次。
  • 作用:在启动程序之前可以做资源的初始化,一般用于初始化静态资源。

案例演示

public class DaimaKuaiDemo01 {
    public static String sc_name ;

    // 1.静态代码块
    static {
        // 初始化静态资源
        sc_name = "黑马程序员!";
        System.out.println("静态代码块执行!");
    }

    public static void main(String[] args) {
        System.out.println("main方法执行");
        System.out.println(sc_name);
    }
}

5.2 实例代码块

实例代码块
​ 没有static修饰,必须放在类下。与对象初始化一起加载。

格式

{
     // 执行代码
}

特点

  • 无static修饰。属于对象,与对象的创建一起执行的。
  • 每次调用构造器初始化对象,实例代码块都要自动触发执行一次。
  • 实例代码块实际上是提取到每一个构造器中去执行的。
  • 作用:实例代码块用于初始化对象的资源。

案例演示

public class DaimaKuaiDemo02 {
   
    private String name ;

    // 实例代码块。 无static修饰。
    {
        System.out.println("实例代码块执行");
        name = "dl";
    }

    // 构造器
    public DaimaKuaiDemo02(){
        //System.out.println("实例代码块执行");
    }

    // 有参数构造器
    public DaimaKuaiDemo02(String name){
        //System.out.println("实例代码块执行");
    }

    public static void main(String[] args) {
        // 匿名对象,创建出来没有给变量。
        new DaimaKuaiDemo02();
        new DaimaKuaiDemo02();
        new DaimaKuaiDemo02("xulei");
    }
}
// 输出三次:实例代码块执行

5. 数组

5.1 数组初始化

int a1[] = {1,2,3,4,5}; //定义一个int型数组
注:

  • java中允许数组相互赋值,int a2[] = a1; //合法,a2[1]实际上是a1[1],其实真正做到的只是复制了一个引用(a2获取到了a1的首地址,类似指针)。

  • 每个数组都有一个固有成员length,a1.length即可获取数组长度。

  • java中可以直接使用new在数组里创建元素

int[] a;
Random rand = new Random(47);
a = new int[rand.nextInt(20)];
  • 如果创建一个非基本类型类的数组,那么创建的就是一个引用数组!
//包装器类Integer
 Integer[] a = new Integer(rand.nextInt(20));//此时a只是一个引用数组
 a[i] = rand.nextInt(500);//创建对象赋值给引用,初始化进程才算结束

如果忘记创建对象,运行时就会报错!

5.2 可变参数列表
1. 语法:

参数类型…(三个点)
例如: void printArray(Object…)
注意: 每个方法最多只有一个可变参数,因为:可变参数必须是方法的最后一个参数

2. 可变参数的类型

可变参数可以设置为任意类型:引用类型,基本类型;当然也会进行类型检查的;

3. 参数的个数:

0个参数
1个参数:如果是数组,那么就直接将这个数组作为参数传进方法里面,不再填充新的数组;
多个参数: 参数可以是数组,也可以是单个变量、常量;但是这时候会,将这些参数填充进新的数组里面,再将这个数组,传进方法里面;

4. 可变参数的使用

可变参数完全可以当作一个数组来使用,或者说,本质上可变参数就是一个数组(下面详细介绍)。所以,数组拥有的方法、属性,可变参数一样拥有。

public void varArgMethod(int b,int... arr) {
	//和数组一样,拥有属性length
	int lenth = arr.length;
	//索引遍历
	for(int i=0;i<arr.length;i++) {
		System.out.println(arr[i]);
	}
	//forEach循环遍历
	for(int ele:arr) {
		System.out.println(ele);
	} 	
}

上面的例子中,可变参数的使用跟数组的使用是完全一样,也就是说,可变参数是可以等价成数组的.

5. 可变参数的方法重载

可变参数列表的方法的重载不同于普通方法: 无法仅通过改变 可变参数的类型,来重载方法。
如:varArray(int… a)、varArray(Object… a),这两个方法在调用时会出错,方法重载失败。

6. 枚举类型

关键字:enum。是一个类,并具有自己的方法。

public enum Spiciness{//创建名为Spiciness的枚举类型
    NOT,MILD,MEDIUM,HOT,FLAMING 
}
  • 由于枚举类型的实例是常量,按照命名规则应全部大写。
  • 为了使用enum,需要创建一个该类型的引用,并赋值:
    Spiciness howHot = Spiciness.HOT; 
  • 创建enum时,编译器会自动添加一些有用的新特性。如:创建toString()方法,方便地显示某个enum实例的名字。编译器还会创建ordinal()方法,用来表示特定enum常量的声明顺序,以及static values()方法,用来按照enum常量的声明顺序产生这些常量值构成的数组。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值