2

我有 2 个类:Date 和 Person
Person 有 Date 类的两个属性

情况1

Date类是与 Person 类分开的类。我有这段代码正常工作:

private String name;
private Date born;
private Date died; // null indicates still alive.

public Person(String initialName, int birthMonth, int birthDay, 
      int birthYear) {
   // requirement from the instructor:
   // **implement using the this() constructor**
    this(initialName, new Date(birthMonth, birthDay, birthYear), null);
}

案例 2:内部班级(作业要求)

我把Date作为私有内部类Person

现在上面的构造函数代码不再起作用了。这是错误消息:

描述资源路径位置类型由于一些中间构造函数调用,没有可用的 Person 类型的封闭实例 Person.java /Wk03_Ch10_FileIO_Ch13_Interfaces/wk03_Ch10_FileIO_Ch13_Inner_Classes 第 43 行 Java 问题`

我该如何解决这个问题?我可以做这个:

Date dt = new Date(birthMonth, birthDay, birthYear);

不幸的是this()必须是构造函数的第一行

另一个解决方法是

public Person(String initialName, int birthMonth, int birthDay, 
      int birthYear) {
   // implement using the this() constructor
    this.name = initialName;
    this.born = new Date(birthMonth, birthDay, birthYear);
    this.died = null;
}

然而,最后一段代码不满足我this()在构造函数中使用方法的讲师要求。

4

2 回答 2

2

您不能static在对另一个构造函数的调用中创建内部成员(非)类。从JLS §8.8.7.1

构造函数体中的显式构造函数调用语句(原文:对 的调用this()不得引用在此类或任何超类中声明的任何实例变量或实例方法或内部类,或在任何表达式中使用this或;super否则,会发生编译时错误。

原因是非static内部类在构造时可能需要访问该类。例如:

public class OuterClass {

    private String name;
    private InnerClass inner;

    public OuterClass(String name, InnerClass inner) {
        this.name = name;
        this.inner = inner;
    }

    public OuterClass(String name) {
        this(name, new InnerClass()); // Will not compile
    }

    public class InnerClass {

        public InnerClass() {
            // Access to name is allowed since this inner class isn't static
            System.out.println(name);
        }
    }
}

这里的主要问题是,当我们构造非static内部类时,它可以static从其封闭实例中访问非成员(OuterClass但封闭OuterClass还没有调用它super(),因此被认为是不安全的访问。事实上,如果允许编译该代码, 它将null根据构造函数调用顺序打印。简而言之,InnerClass将在调用之前创建, 与此问题this.name = name中提供的信息类似的概念.

解决办法是做InnerClass一个static内部类,直接把名字传给它:

public class OuterClass {

    private String name;
    private InnerClass inner;

    public OuterClass(String name, InnerClass inner) {
        this.name = name;
        this.inner = inner;
    }

    public OuterClass(String name) {
        this(name, new InnerClass(name));
    }

    public static class InnerClass {

        public InnerClass(String name) {
            System.out.println(name);
        }
    }
}

InnerClass无法nameOuterClass它被声明后访问static,所以我们现在必须在构造时明确地传递它,但这更好,因为初始代码无论如何都会被破坏。

编辑:

根据您的问题:

让我感到困惑的是,我可以在 的构造函数中创建一个Date类型的对象Person,只要它不在this()方法内部。我可以这样做:Date dt = new Date(birthMonth, birthDay, birthYear);上述和 有什么区别this(...., new Date(birthMonth, birthDay, birthYear), ...)

不同之处在于,在 之外的调用中this(),所有对 的调用super()都发生了,this()因为对 的隐式调用,它们都是作为 的一部分发生的super(),因此对象已经达到可以被访问的程度。您的Date实例无法访问Person该类,因为尚无 thePerson及其字段的上下文,因此编译器不允许这样做。

简而言之,一旦this()被调用,那么至少调用super()已经发生,这是这个约束背后的驱动力,也是为什么不鼓励可覆盖的方法调用。如果一个方法被子类覆盖,然后在超类的构造函数中调用,则可以在子类初始化之前访问子类中的字段,甚至导致字段null返回final基本上,这一切都是为了super()在调用调用之前保护自己不访问你的类。

于 2013-06-10T06:44:04.160 回答
0

虽然我永远不会在Date类内部创建一个Person类(从应用程序建模的角度来看,这听起来是个坏主意!),但您似乎说过这是某些作业的要求。

如果你是这样设置的:

public class Person {

    ...

    class Date {
        ...
    }

}

然后在 的方法中Person,您将需要调用Date构造函数:

this.new Date(...)

这就是 Java 使用的语法。您需要一个 Person 类型的封闭实例,在该实例上创建内部类的对象。关于内部类(无论它们是成员、本地还是匿名)的事情是每个实例都绑定到外部类的一个实例。所以如果我有一个人实例p,我可以说:

p.new Date(...)

但这里最大的问题是您不能在Person使用即将创建的人的构造函数中创建日期!例如,这失败了

public Person() {
    this(this.new Date());
}

因为 的值this还没有准备好以这种方式使用(尽管有趣的是,有时您可以this在其他情况下使用内部构造函数,例如将其存储在数组中)。

就像您意识到的那样,制作Date静态嵌套类很好,因为静态嵌套类的实例不绑定到封闭类的任何实例,所以这是最好的解决方案。如果您真的必须有一个内部类,您将无法将新日期作为this()表达式的“参数”传递并将其绑定到您正在创建的人!也许这就是作业的重点(这是研究生班吗?:-))

于 2013-06-10T06:30:02.173 回答