【韩顺平 零基础30天学会Java】不同操作下类都经历了什么?

💡对象实例化

当使用实例化对象new Object()时,堆栈都经历了什么?

public class main{
    public static void main(String[] args) {
        A a = new A();
    }
}
class A{
    String name;// 全局变量
    static {// 静态代码块
		System.out.println("hjhcos");
	}
    {// 普通代码块
		this.changeName("hjh");
	}
    A(){// 构造器
        this.changeName("cos");
    }
    public void changeName(String name){// 成员方法
        this.name = name;
    }
}

通过调试上面的代码,可以简单地了解在对象实例化时堆栈的相应操作。

当执行到 A a = new A(); 时先执行 A()A.<clinit> 压栈,执行类里面的静态代码块然后出栈,这个过程称为类加载。在这个过程中,你不可以使用 this,因为它还没有在堆里面分配内存(即没有实例化)。

接下来执行 new A()A.<init>() 压栈,在压栈后就已经完成了 类的全局变量赋于默认值this 指向相应堆栈 的操作,因此从意义上来说已经完成了对象实例化(即对象实例在堆里面分配了内存)。为什么我会说它已经完成了对象实例化?
因为这个时候我们可以通过 this 来引用它。

那是不是上面操作完成后可以直接返回对象了?
其实还没有,普通代码块和构造器还没有执行。你可以理解为 A.<init>() 还没有执行完(即没有做出栈操作),因为在 A.<init>() 里面还有执行所有普通代码块和调用对应的一个构造器。
首先它会去执行完所有普通代码块(自上而下地执行每一个普通代码块),你可以在普通代码块里面调用普通方法,但是不可以调用构造器。
然后构造器开始被调用,你可以在构造器的第一行调用其他本类的构造器 通过 this(); 传实参的方式调用,也可以当前作用域里面调用普通方法。不管是在哪个里面调用普通方法都会在堆栈里面进行压栈出栈操作的。
最后返回这一系列操作后的对象,可以被标识符 a 引用。

通过上面的描述,总结一下

  • 执行到类中静态代码块时,对象还没有实例化(即没有 this)。
  • 执行到普通代码块和构造器,对象已经实例化且全局变量有了默认值(即可以使用 this)。
  • 普通代码块执行在构造器前面。
  • 普通代码块和构造器都可以调用普通方法。
  • 构造器的第一行代码可以用于调用相同类的其他构造器。
  • 先加载类信息(属性和方法,只会加载一次),再在堆中分配空间属性会进行默认初始化,最后把地址赋值给标识符。
  • 数据存储在方法区的常量池里面,其地址会引用到堆里面。

💡对象实例化后不再引用

通过上面的描述我们了解到,标识符只是对这个对象进行引用。因此当你对标识符重新赋值并不会改变之前引用的对象,那么问题来了不再被引用的对象,那么它何去何从?
当实例化后的对象不在引用a = null;时,JVM会在堆和方法区里面回收它所占的资源, 但是需要注意的是a标识符的类型声明还在方法区里面没有被JVM回收至于什么时候回收?暂时我还不知道,但可以肯定的是作用域消失里面的标识符的类型信息也会相应消失。


💡构造器重新初始对象

在构造器重新初始化本身,会不会调用普通代码块?

class A{
    String name;
    {// 普通代码块
        System.out.println("hjhcos");
    }
    A(){// 构造器
        this("hjh");
        System.out.println("cos");
    }
    A(String name){// 构造器
        this.name = name;
        System.out.println(name);
    }
}
public class main{
    public static void main(String[] args) {
        A a = new A();
        a = null;
    }
}

通过调试上面的代码,我发现一个特别好玩的事情 —— 就是不会先去执行普通代码块,而是先去执行 this("hjh"); 然后跳到 A(String name) 构造器再去看是否有调用其他构造器,如果没有调用那么直接去执行所有普通代码块。放心你是无法进行递归调用的,因为那样做是无法通过编译器的。
构造器递归调用:在构造器里面调用已经调用过的构造器。

如果你是无意刷到这篇文章并看到这里,希望你给我的文章来一个赞赞👍👍。如果你不同意其中的内容或有什么问题都可以在下方评论区留下你的想法或疑惑,谢谢你的支持!!😀😀

参考文献

  1. 【零基础 快速学Java】韩顺平 零基础30天学会Java_哔哩哔哩_bilibili
  2. JAVA构造函数没有返回值是怎么赋值的?_srs1995的博客-优快云博客
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hjhcos

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值