当Java类的成员变量是自己本身时,为什么会出现StackOverflowError?

当我们声明一个类:

public class MyTest{
    MyTest a;
}

MyTest类中有一个类型是本身的成员变量test,这样声明并不会出现什么问题。但是成员变量是可以初始化的,如果我们一开始就给test初始化会出现什么问题:

public class MyTest{
    MyTest a = new MyTest();
}

用上面这个声明,我们调用一下:

public class Main{
    public static void main(String[] args) {
        MyTest demo = new MyTest();
    }
}

我们在外部声明一个MyTest类型的变量demo并初始化,这时候运行会出现错误:java.lang.StackOverflowError,栈溢出,为什么?

一步一步来看一下,首先demo有一个属性是a,当执行MyTest demo = new MyTest();的时候,demo的属性也会初始化,因此会执行MyTest a = new MyTest();,发现没有,当执行MyTest a = new MyTest();的时候,是不是跟执行MyTest demo = new MyTest();的效果是一样的,a也有自己的属性也叫a(暂且叫做a’),这个a‘也要被初始化,也要执行MyTest a' = new MyTest();a’也有自己的属性a’‘,a’‘有属性a’‘’,a’‘‘有属性a’’‘’…这样就进入了无线递归,因此就会出现栈溢出。

但是

如果声明是这样的:

public class MyTest{
    static MyTest a = new MyTest();
}

会出现栈溢出吗?

static修饰了a,那么a就是一个静态属性,静态属性的生命周期跟类一样,并且在内存中仅有一份,我们还是在外部调用:

public class Main{
    public static void main(String[] args) {
        MyTest demo = new MyTest();
    }
}

这时候,当执行MyTest demo = new MyTest()时候,其实静态属性a会比demo先被加载,也就是说,static MyTest a = new MyTest()先被执行,此时a已经被实例化了,接下来就实例化demo,那么实例化demo的时候,会再实行static MyTest a = new MyTest()吗,答案是不会。因为a是静态资源,仅会被加载一次,因此这样子的声明不会出现栈溢出。

这也就是为什么单例模式中,要将属性声明为static。

以下是饿汉式的单例模式的简单声明:

public class Singleton {
    private final static Singleton INSTANCE = new Singleton();   //用于引用全局唯一的单例对象,在一开始就创建好
    
    private Singleton() {}   //不允许随便new,需要对象直接找getInstance
    
    public static Singleton getInstance(){   //获取全局唯一的单例对象
        return INSTANCE;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值