【问题标题】:Inner class and this() constructor内部类和 this() 构造函数
【发布时间】:2013-06-10 06:16:17
【问题描述】:

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

案例一

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

【问题讨论】:

  • 没有。我应该使用私有内部类(我认为)
  • @BevynQ 我尝试将 Date 设为私有静态内部类,并且我的原始代码有效。所以我会问教练是否可以接受。同时,还有什么办法吗?谢谢
  • 您的教师需要清楚术语。来自Official Java Tutorial:嵌套类分为两类:静态和非静态。声明为静态的嵌套类简称为静态嵌套类。非静态嵌套类称为内部类。一般来说,嵌套的静态类不是内部类

标签: java constructor this inner-classes


【解决方案1】:

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

构造函数主体中的显式构造函数调用语句(原文:对this() 的调用)不得引用任何实例变量或实例方法或在此类或任何超类中声明的内部类,或在任何表达式中使用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 内部类时,它可以从其封闭实例(OuterClass,但封闭的OuterClass 尚未访问非static 成员调用了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 一旦被声明为OuterClass 就无法从OuterClass 访问name,因此我们现在必须在构造时显式传递它,但这更好,因为初始代码无论如何都会被破坏。

编辑:

根据您的问题:

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

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

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

【讨论】:

  • 令我困惑的是,我可以在 Person 的构造函数中创建 Date 类型的对象,只要它不在 this() 方法中。我可以这样做:Date dt = new Date(birthMonth, birthDay, birthYear);上面和this(...., new Date(birthMonth, birthDay, birthYear), ...)有什么区别?
  • 谢谢布赖恩。很抱歉,我还不能投票赞成你的答案。
【解决方案2】:

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

如果你是这样设置的:

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() 表达式的“参数”传递,并将其绑定到您正在创建的人!也许这就是作业的重点(这是研究生班吗?:-))

【讨论】:

  • 理论上,你是对的。但是,在 ideone (code example) 上测试并不起作用。
  • @LuiggiMendoza +1 很好,谢谢!我也只是在尝试这个。 +1首先获得它。有意义,因为在 person 构造函数完成之前,封闭实例不存在。整个“任务”非常可疑。可能是误会? :)
  • 这是错误消息:描述资源路径位置类型在显式调用构造函数 Person.java /Wk03_Ch10_FileIO_Ch13_Interfaces/wk03_Ch10_FileIO_Ch13_Inner_Classes 第 43 行 Java 问题时无法引用“this”或“super”
  • 这可以通过将内部类标记为static 来轻松解决。但是,如果老师不希望学生使用 static 内部类(因为它不是真正的内部类),那么最好的办法是将 null 参数传递给构造函数,然后在调用构造函数。
  • 先求助,怎么在评论中换行?以及如何制作一段代码,就像原来的帖子一样?对不起,这里是新手
猜你喜欢
  • 1970-01-01
  • 2013-08-04
  • 1970-01-01
  • 2011-04-16
  • 1970-01-01
  • 2011-09-18
  • 2020-02-19
  • 2019-02-01
  • 1970-01-01
相关资源
最近更新 更多