当前位置: 首页 > 知识库问答 >
问题:

内部类和this()构造函数

公孙弘深
2023-03-14

我有两个类: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的封闭实例不可用。java/Wk03_Ch10_文件IO_Ch13_接口/Wk03_Ch10_文件IO_Ch13_内部类第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()方法的要求。

共有2个答案

狄玮
2023-03-14

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

如果您是这样设置的:

public class Person {

    ...

    class Date {
        ...
    }

}

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

this.new Date(...)

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

p.new Date(...)

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

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

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

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

杜起运
2023-03-14

不能在对另一个构造函数的调用中创建内部成员(非静态)类。根据JLS§8.8.7.1:

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

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

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);
        }
    }
}

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

解决方案是使InnerClass成为静态内部类,并直接将名称传递给它:

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访问name,所以我们现在必须在构造中显式传递它,但是这是更好的,因为初始代码无论如何都会被破坏。

编辑:

根据你的问题:

让我困惑的是,我可以在Person的构造函数中创建日期类型的对象,只要它不在this()方法中。我可以这样做:datedt=新日期(生日、生日、生日) 上面的和这个(..,新日期(生日,生日,生日),…)之间有什么区别

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

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

 类似资料:
  • 问题内容: 我的代码中有内部类。我想授予对其实例的公共访问权限,但是只有外部类才可以创建此实例,就像在“私有”访问权限中一样。是否可以不做适当的小包装(或为每个这样的内部类创建公共接口)? (对不起,如果我的英语不好:P) 问题答案: 有可能的。将 内部类 声明为 public,但将其构造函数声明为private 。这样,您只能在封闭的类及其内部内部创建它,而不能从外部创建它。

  • 我在班里学习。出于好奇,我扩展了具有参数化构造函数的内部类。但是当我编写super(inti)来调用它时,代码不会编译。 因为内部类是外部类的一部分(成员),必须通过外部类访问它们。如何调用测试类的超级构造函数。 编译错误是:由于某些中间构造函数调用,没有外部类型的封闭实例可用

  • 问题内容: 我有一堂课。 在我的类方法中,我实例化该类,如下所示: 编译器将此代码转换为: 使用反射表明该类具有以下综合的构造函数: 由于该类是,因此编译器会将该构造函数添加到该类中,因此没有人可以实例化该类。但是很明显,该类应该能够实例化它,因此编译器添加了另一个包私有构造函数,后者又调用了私有构造函数。另外,由于package- private构造函数的名称中包含该名称,因此普通的Java代码

  • 问题内容: 码: 输出: 为什么以这种方式打印? 问题答案: 当您在运行时调用多态方法时,Java使用特殊的数据结构来决定需要调用哪个类的方法。在构造对象时,即 在执行用户提供的任何构造函数和初始化程序代码之前,都会 建立此结构。 创建时,在输入的构造函数 之前 已准备好“何时调用,则需要调用或” 的数据结构。由于此结构是为类准备的,因此即使调用代码在内部的构造函数中,它也指向。这就是为什么您看到

  • 我有一个类,它有一个类。 在我的类方法中,我按如下方式实例化类: 编译器将此代码转换为: 使用反射显示类具有以下合成构造函数: 由于类是,编译器向其添加构造函数,因此没有人可以实例化该类。但是显然,类应该能够实例化它,因此编译器添加了另一个包私有构造函数,该构造函数反过来调用私有构造函数。另外,由于包私有构造函数的名称中有,所以普通Java代码不能调用它。 问题:为什么要合成一个私有构造函数和一个

  • 类 类是对某一事物的抽象描述,具体地讲,类是C++中的一种构造的数据类型。它即可包含描述事物的数据,又可包含处理这些数据的函数,类在程序运行时是被用作样板来建立对象的。所以要建立对象,首先必须定义类。 定义类 定义一个类的一般格式为: class 类名{     private:         成员表1;     public:         成员表2;     protected: