学习是最好的投资!
public class A { A a = new A(); public static void main(String[] args) { A a = new A(); } }
上面这段代码编译成字节码在翻译回来就像下面这样:
public class A { public A(){ A a = new A();//这里重复调用了自己 } public static void main(String[] args) { A a = new A(); } }
最简单的回答应该是每次new A()时都会创建一个对象。
new A()
下面分析一下稍微详细一点的过程1.程序执行后首先进入main函数,然后第一次执行main函数,然后第一次执行new A();2.由于没有显示的构造函数,编译器在编译的时候会生成一个无参构造函数
main
public A(){ }
3.进入上面的构造函数后先要初始化成员变量,也就是 A a = new A(); A a = new A();4.这里就到的问题的关键,成员变量A初始化还是new A()继续调用2中的构造函数。5.接着就会重复2、3、4的步骤,直到这个线程的栈空间不够用,抛出StackOverflowError4.这里就到的问题的关键,成员变量A初始化还是
A a = new A();
A
StackOverflowError
5.接着就会重复2、3、4的步骤,直到这个线程的栈空间不够用,抛出JVM中,每个线程都会分配一定的栈空间(非共享),这个栈空间可以是固定的可以是动态扩展的,不同的JVM错误。
JVM
这里还要普及一点方法调用的知识,在StackOverflowError这里的实现方式可以不同。线程中每执行一个方法,这个方法就会以栈帧的形式压入线程栈中。
当系统加载类或创建该类的实例时,系统自动为成员变量分配内存空间,并在分配内存空间后,自动为成员变量指定初始值。
局部变量定义后,必须经过显式初始化后才能使用,系统不会为局部变量执行初始化。这意味着定义局部变量后,系统并未为这个变量分配内存空间,直到等到程序为这个变量赋初始值时,系统才会为局部变量分配内存,并将初始值保存到这块内存中。
public class A { public static void main(String[] args) { A a = new A(); } }
java.lang.StackOverflowError就是内存溢出,出现死循环;题主不应该在A类里创建A类的实例,A()相当于一个无参构造器,在A类里直接写A a = new A();会导致无限迭代地创建实例,最后导致内存溢出;错误提示也写明程序在第4行处出现错误,而且反复循环地出现错误
欢迎题主来我主页学习Java知识并交流指导,关于题主所提及的知识点在我主页的Java面向对象(上)有提及:https://segmentfault.com/a/11...
楼上两位已经解释的很清楚了,简单的说就是你为类A增加了一个自身的实例变量a,这本身没什么问题,但是你将a的初始化放在了实例初始化的过程中,这样的话只要调用一次new A()就会进去一个无限调用的循环,所以就栈溢出了。
非常明显的递归调用,而且没有结束条件,肯定就内存溢出。递归就是方法里调用方法本身,而你给出的案例特殊一点,是构造方法,原因就是这么简单。
上面这段代码编译成字节码在翻译回来就像下面这样:
最简单的回答应该是每次
new A()
时都会创建一个对象。下面分析一下稍微详细一点的过程
1.程序执行后首先进入
main
函数,然后第一次执行main
函数,然后第一次执行new A()
;2.由于没有显示的构造函数,编译器在编译的时候会生成一个无参构造函数
3.进入上面的构造函数后先要初始化成员变量,也就是
继续调用2中的构造函数。A a = new A();
A a = new A();
4.这里就到的问题的关键,成员变量
A
初始化还是new A()
继续调用2中的构造函数。5.接着就会重复2、3、4的步骤,直到这个线程的栈空间不够用,抛出
StackOverflowError
4.这里就到的问题的关键,成员变量A
初始化还是5.接着就会重复2、3、4的步骤,直到这个线程的栈空间不够用,抛出
JVM
中,每个线程都会分配一定的栈空间(非共享),这个栈空间可以是固定的可以是动态扩展的,不同的JVM
错误。这里还要普及一点方法调用的知识,在
🎜上面出现🎜就是因为一直不断的调用构造方法,然后一直创建栈帧压入线程栈,最后栈空间不够用,导致栈溢出。🎜StackOverflowError
这里的实现方式可以不同。线程中每执行一个方法,这个方法就会以栈帧的形式压入线程栈中。变量的初始化和内存中的运行机制
成员变量的初始化和内存中的运行机制
当系统加载类或创建该类的实例时,系统自动为成员变量分配内存空间,并在分配内存空间后,自动为成员变量指定初始值。
局部变量的初始化和内存中的运行机制
局部变量定义后,必须经过显式初始化后才能使用,系统不会为局部变量执行初始化。这意味着定义局部变量后,系统并未为这个变量分配内存空间,直到等到程序为这个变量赋初始值时,系统才会为局部变量分配内存,并将初始值保存到这块内存中。
正确的代码
java.lang.StackOverflowError异常
java.lang.StackOverflowError就是内存溢出,出现死循环;题主不应该在A类里创建A类的实例,A()相当于一个无参构造器,在A类里直接写A a = new A();会导致无限迭代地创建实例,最后导致内存溢出;错误提示也写明程序在第4行处出现错误,而且反复循环地出现错误
知识补充
欢迎题主来我主页学习Java知识并交流指导,关于题主所提及的知识点在我主页的Java面向对象(上)有提及:https://segmentfault.com/a/11...
楼上两位已经解释的很清楚了,简单的说就是你为类A增加了一个自身的实例变量a,这本身没什么问题,但是你将a的初始化放在了实例初始化的过程中,这样的话只要调用一次new A()就会进去一个无限调用的循环,所以就栈溢出了。
非常明显的递归调用,而且没有结束条件,肯定就内存溢出。递归就是方法里调用方法本身,而你给出的案例特殊一点,是构造方法,原因就是这么简单。