Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 类可以有自己类型的字段吗_Java_Oop_Object - Fatal编程技术网

Java 类可以有自己类型的字段吗

Java 类可以有自己类型的字段吗,java,oop,object,Java,Oop,Object,我做了下面的事情,一段时间后,我发现了一个stackoverflow错误,我明白为什么会这样 public class Cat { String name="default name"; Cat insideCat; public Cat(){ System.out.println("Cat constructor"); insideCat = new Cat(); } } 但是如果我不在构造函数中创建一个新的Cat对象,

我做了下面的事情,一段时间后,我发现了一个stackoverflow错误,我明白为什么会这样

public class Cat {
    String name="default name";
    Cat insideCat;

    public Cat(){
         System.out.println("Cat constructor");
         insideCat = new Cat();
    }

}
但是如果我不在构造函数中创建一个新的Cat对象,而是获取一个Cat类型的参数并将其分配给insideCat字段,该怎么办呢

public class Cat {
    String name="default name";
    Cat insideCat;

    public Cat(Cat insideCat){
         System.out.println("Cat constructor");
         this.insideCat = insideCat;
    }

}
我只是在玩弄代码,只是想找出Java能做什么和不能做什么。在第二段代码中,一切看起来都很正常,直到我开始测试这个类。我需要一个Cat对象来创建一个Cat对象(要创建这个Cat对象,我需要另一个Cat对象…它会继续)。所以技术上我不能测试这个类

所以我的问题是为什么java允许创建自己类型的实例变量?我猜构造函数的全部目的是初始化它的实例变量。所以要么我必须创建一个新对象来初始化insideCat,要么我必须从外部获取Cat对象。两者似乎都不起作用


我错过了什么。是否存在这样的情况:自身类型的实例变量可以变得有用,并且可以毫无问题地使用?提出这样的类是不是很糟糕的OOP实践

这样的类一直存在

考虑链表或树,例如:

class ListNode {
  ListNode next;
  // Etc.
}

class TreeNode {
  TreeNode left;
  TreeNode right;
  // Etc.
}
您不会在构造函数中初始化“子”对象,而是在以后添加它们


在您的示例中,您需要有一个稍后创建
insideCat
的方法。一般来说,您不会创建具有完全相同状态的子对象,在构建时会有一些区别,在这种情况下,您可能会遇到“哦,上帝,现在停止创建这些对象”的情况,或者在添加它们时,例如。,您可以通过方法而不是构造函数来添加它们。

拥有同一类的实例成员没有什么错。 员工有经理,经理也是员工

 public class Employee{
     private Employee manager;
     //getters setters and constructor
 }

有许多自引用数据结构的示例是有效的。想象一个
链接列表
。每个
LinkNode
都有一个数据字段和指向下一个
LinkNode
的指针

class LinkNode {
    int data;
    LinkNode nextLink;

    public LinkNode(int d1) {
        data = d1;
        nextLink = null;
    }
    ...
}

class LinkedList {
    private LinkNode first;
...
}
您的
StackOverflow
问题源于这样一个事实:创建一个而不是
X
需要无限地创建另一个X


想想你的
Cat
示例。为什么实例化一个Cat需要所有的东西…另一个
Cat

可以有多个构造函数。因此,您可以有另一个构造函数

public Cat(){...}

这将允许您创建一个内部猫。之后,您可以创建另一个包含内部Cat的Cat。显然,根据您的需要,这里的设计可能不太好。Dave Newton关于链表的回答是这种用法的一个很好的现实例子。

如何实现双链表?有一个相同类型的字段是可以的,但子对象的创建必须以某种方式停止。您的子对象是无条件创建的。您可以通过将
null
传递到第一个
Cat(…)
构造函数来轻松测试此类。然后,如果愿意,您可以提供一种方法,稍后将其他内容分配给
insideCat
。实例化cat确实需要其他cat;)然而,这里的例子是从生物学上倒退过来的,并且假设出生时有一只新生猫。我不同意。你可以有一个名为“consumate”的方法返回对新猫的引用…但它不必发生在幼猫的构造函数中。确切地说:怀孕前的猫没有任何意义。我明白了-我们在这里原则上同意构造函数。我知道我的类在现实生活中没有意义。我只是想要一个例子,并随机将其命名为“Cat”。我读到构造函数的全部目的是初始化其实例变量,所以我不是通过在新方法中初始化这些特殊字段来打破这一点吗?@DesirePRG一个构造函数的“全部目的”是构造一个对象。实例变量在构造期间可能不处于最终状态。在列表示例中,
next
值在添加到列表中之前可能不存在。列表本身将负责查找最后一个列表节点,将其
next
设置为新列表项,等等。在这种情况下,
ListNode
需要做的就是将
next
设置为
null
或null对象。好吧,如果我说,构造函数可以初始化所选的一组实例变量,并将其余字段保持为null(假设只有对象字段),直到初始化这些字段才有意义!关于构造函数,抽象类仍然可以有构造函数,但不能构造对象。那么,我们可以说构造函数的目的是构造一个对象吗?@DesirePRG-Yes;ctor只会初始化它需要初始化的内容。我认为说“构造函数的目的是构造一个对象”是。。。显而易见。抽象类必须扩展才能使用;抽象类的构造函数仍然可以用于构造子类实例。除非扩展抽象类的ctor,否则不能使用它:它的目的仍然是构造一个类;这样做需要额外的语义,这似乎无关紧要。@DaveNewton我不明白为什么我想不出你在答案中提供的例子:)显然是我这边的反对票