【问题标题】:Object of the class as instance variable inside the class [duplicate]类的对象作为类内的实例变量[重复]
【发布时间】:2012-11-16 11:06:09
【问题描述】:

可能重复:
How can a class have a member of its own type, isnt this infinite recursion?

代码:

public class Test2{
    private Test2 subject = new Test2(); //Create Test2 object in Test2
    private int num;
}

问题:

  1. 为什么Java允许执行上述代码,而C++不允许?

  2. 上面的代码是否创建了无限数量的对象?由于Test2 本身包含一个Test2 对象,该对象又包含一个Test2 对象,该对象本身具有一个Test2 对象等等。

【问题讨论】:

  • 关于问题 #1:因为代码是 Java,而不是 C++。
  • @JohnDibling:大概,“C++”这个问题的意思是“用 C++ 编写的等效代码”。
  • @MikeSeymour:我想我的问题是,OP 认为等效代码是什么?

标签: java c++ oop reference instance-variables


【解决方案1】:

为什么Java允许执行上述代码而C++不允许?

自 2011 年起,C++ 还允许在其声明中初始化类成员。

但是,它不允许这种情况:您只能实例化完整类型,并且类类型在类定义中是不完整的,因此必须在构造函数中初始化它,或者通过调用函数来初始化:

class Test;
Test * make_test();

class Test {
    // Test is incomplete, so "new Test" is not possible here
    Test * test = make_test();
};

// Test is complete, so we can instantiate it here
Test * make_test() {return new Test;}

Java 没有不完整类型的概念,因此可以在允许实例化任何类的任何地方实例化该类。

上面的代码会创建无限对象吗?

是的,尝试实例化这样的类会使您的程序陷入递归死亡螺旋。

【讨论】:

  • +1 表示递归死亡螺旋
  • 恕我直言,这应该是公认的答案。简而言之,两者都会失败,但 java 的类型系统只是选择将问题留给运行时环境。
【解决方案2】:

关于您的问题,两种语言之间的主要区别在于 Java 是一种具有引用语义的语言(原始类型除外),而 C++ 是一种具有值语义的语言,允许通过引用和指针进行引用语义。

在两种语言中看起来相似的语法具有完全不同的含义,当在 Java 中创建 reference (Test2 x = new Test2();) 时,C++ 中的等效构造将使用指针 (Test2 *x = new Test2();)。

一个关键的区别是通过使用指针在值语义之上提供引用语义很简单,但在(纯)引用语义之上提供值语义是不可能的。该语句的一些含义包括无法控制 Java 中对象在内存中的布局或数据的局部性(对于原始类型和原始类型数组以外的任何内容),而在另一个方向上可以更好地控制对象在 C++ 中允许您模仿 Java 对象。

【讨论】:

  • 优秀的答案!没有其他人给出任何合理的解释。我不认为许多纯 Java 程序员(如果有的话)可以理解这一点。这个问题需要 C++ 和 Java 方面的知识。
  • 这当然是一个深入的分析,但恕我直言,它无法直接解决初学者可能有的反直觉:无论语义如何,相同的“算法”(试图创建一个自我-引用循环)在一种语言中是允许的,但在另一种语言中是禁止的。正如@assylias 所指出的,一个直接而简单的答案是两者最终都会失败(编译时为c++,运行时为java)。 java编译器之所以不抱怨,只是一个选择问题——与c++中“不完整类型”的概念不同,java类型系统只是选择了沉默。
【解决方案3】:

因为你可以有多个构造函数,所以它是允许的。 如果你只有一个构造函数,这确实会导致无限循环。

public class Test{
    private Test a;

    public Test(String s){
        this.a=new Test();
    }

    public Test(){

    }

}

【讨论】:

    【解决方案4】:

    如果您将subject 声明为static,您将获得单例模式的急切初始化版本,这不会让您耗尽资源。

    【讨论】:

    • 嘿,请您详细说明一下如何将变量声明为静态不会将其置于递归螺旋中
    【解决方案5】:

    关于问题 2 - 如果您运行此代码,您会得到 StackOverflowException => 是的,它会创建无限数量的对象(它会尝试...)

    public class Test2 {
    
        private Test2 subject = new Test2(); //Create Test2 object in Test2
    
        public static void main(String[] args) throws Exception {
            Test2 t = new Test2();
        }
    }
    

    【讨论】:

      【解决方案6】:

      subject 这是对Test2 实例的引用。如果你尝试运行它,代码会很快耗尽一些资源(可能是堆栈空间,也可能是堆空间)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-16
        • 1970-01-01
        • 2018-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多