- 什么是自引用/递归调用
- 代码示例和分析
- 自引用情况
- 类比C++:
在编写代码的过程中,我们经常看到类中出现该类的声明,示例:
class A{
int data;
A a;
}
这种情况就被称为自引用.
代码示例和分析首先明确一点,Java有自己的语法规则,在Java中不能直接在类的主体中调用方法。类的主体用于声明类成员,而不包含可执行行为。以下这种写法是错误的语法,方法的调用应该存在代码块{}中。
class A {
A a = new A();
a.moon();
public static void main(String[] args) {
}
public void moon(){
System.out.printf("java是最好的编程语言");
};
}
自引用情况
第一种情况:
class A {
public static void main(String[] args) {
A a = new A();
a.moon();
}
public void moon(){
System.out.printf("java是最好的编程语言");
}
}
#输出:java是最好的编程语言
从输出结果可以判断,在方法体中调用本类的方法可以正常执行
分析:
JVM先加载了方法区的类定义,并没有实例化这个类,系统什么都没发生,只是声明了一下。只有当new的时候才是真正的创建这个类。
流程:
进入main方法,调用A a = new A();这时候系统真正创建了一个实例a,然后这个实例调用实例方法。程序结束。
第二种情况:
class A {
A a1 = new A();
public static void main(String[] args) {
A a = new A();
a.moon();
}
public void moon(){
System.out.printf("java是最好的编程语言");
}
}
#输出:
Exception in thread "main" java.lang.StackOverflowError
这种情况自己调用自己并且生成了确定的对象,出现了堆栈内存溢出错误。
分析:
从代码分析,当我们创建一个对象时,会先初始化成员变量。我们这里在初始化成员变量时,又会去创建一个相同类型的对象,如此陷入了死循环,最后导致堆栈溢出。
第三种情况:
class A {
static A a = new A();
public static void main(String[] args) {
a.moon();
}
public void moon(){
System.out.printf("java是最好的编程语言");
}
}
#输出:java是最好的编程语言
虽然在成员变量中,实例化该对象,但是正常输出。
分析:
static生成的是静态变量,这个变量在JVM第一次读取方法区定义的时候被装载进方法区中,在装载该变量的同时,也在堆区实例化这个类的实例。
因为静态变量在加载类时加载唯一一次,并不会像非静态变量一样因为循环引用而重复实例化而导致堆栈溢出。
第四种情况:
class A {
A[] aa = new A[26];
public static void main(String[] args) {
A a = new A();
a.moon();
}
public void moon(){
System.out.printf("java是最好的编程语言");
}
}
#输出:java是最好的编程语言
分析:数组是一种引用类型的变量,因此使用它定义一个变量时,仅仅表示定义了一个引用变量(相当于定义了一个指针),这个引用变量还未指向任何有效的内存,为null,未初始化直接使用会出现空指针异常。
当在class成员变量中初始化时,仍然会出现内存溢出现象,如下:
class A {
A[] aa = new A[26];
{aa[0] = new A();}
public static void main(String[] args) {
A a = new A();
a.moon();
}
public void moon(){
System.out.printf("java是最好的编程语言");
}
}
#输出:
Exception in thread "main" java.lang.StackOverflowError
at A.(file.java:4)
类比C++:
自引用结构兼谈Malloc和Free函数
#这个结构是非法的,因为结构中包含B,B里包含自己的成员B,会无休止的循环下去,直至内存溢出
struct SELF_REF1{
int A;
struct SELF_REF1 B;
int C;
};
编译器在结构的长度确定之前,就已经知道指针的长度,所以这样自引用是合法的。
struct SELF_REF1{
int A;
struct SELF_REF1 *B;
int C;
};
在C++中,在定义对象的时候就创建了对象的实例,即分配了对象的内存空间。因此,C++类定义中仅有类的声明也会出现错误。
暑期编程PK赛 得CSDN机械键盘等精美礼品!


