内部类和this()构造函数

时间:2013-06-10 06:16:18

标签: java constructor this inner-classes

我有两个课程:日期和人员 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.java / Wk03_Ch10_FileIO_Ch13_Interfaces / wk03_Ch10_FileIO_Ch13_Inner_Classes第43行Java问题`没有封闭的Person类型实例

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

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()方法的要求。

2 个答案:

答案 0 :(得分:2)

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

  

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

原因是非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 {1}}尚未调用super(),因此被认为是不安全的。事实上,如果允许编译该代码,由于构造函数调用顺序,它将打印null。简而言之,InnerClass会在调用this.name = name之前创建,这与this question中提供的信息类似。

解决方法是让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

name无法从OuterClass访问static,因此我们现在必须在构建时明确传递它,但这是因为初始代码更好无论如何都会被打破。

修改

根据你的问题:

  

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

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

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

答案 1 :(得分:0)

虽然我永远不会在Date类中创建Person类(从应用程序建模的角度来看,这听起来不错!),您似乎已经说过这是一个必需一些任务。

如果你这样设置:

public class Person {

    ...

    class Date {
        ...
    }

}

然后在Person的内部方法中,您需要使用以下命令调用Date构造函数:

this.new Date(...)

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

p.new Date(...)

这里的一个大问题是你无法在使用即将创建的人的Person构造函数中创建日期!例如,fails

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

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

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