【问题标题】:Static nested class has full access to private outer class members?静态嵌套类可以完全访问私有外部类成员吗?
【发布时间】:2015-01-26 16:16:27
【问题描述】:

更新:

我仍然不清楚这一点。我试图找到 JLS 来描述这种行为。相反,我在8.3 of the JLS 中找到了这句话:

成员类声明(第 8.5 节)描述嵌套类 周围班级的成员。成员类可能是静态的,在 在这种情况下,他们无法访问 周边班级;或者它们可能是内部类(第 8.1.3 节)。

这是否意味着嵌套的静态类不应该访问外部类变量?我在哪里可以找到有关行为应该是什么的说明?

结束更新

我正在寻求通过静态嵌套类的实例来澄清外部类的私有成员的可访问性。 Java tutorials 状态:

静态嵌套类在行为上是一个顶级类 嵌套在另一个顶级类中以方便打包

从这个问题 (Java inner class and static nested class) 中接受的答案提到:

创建静态内部类的唯一真正可能的原因是 这样的类可以访问其包含类的私有静态 成员

但似乎静态嵌套类也可以访问封闭类的任何实例的私有成员?这将在行为上与任何其他顶级课程不同。在下面的示例中,静态嵌套类Builder 可以访问Config 类的任何实例的私有成员。但是另一个顶级类将无法做到这一点(例如,ConfigTest 的实例将无法更改配置对象的私有成员,如注释的 manipulateConfig 方法中所示。

我理解正确吗?我没有在 JLS 中找到参考资料来为我澄清这一点。

配置:

public class Config {

    private String param1;
    private int param2;

    private Config() {}

    public String getParam1() { return param1; }
    public int getParam2() { return param2; }

    @Override
    public String toString() {
        return "Config{" + "param1=" + param1 + ", param2=" + param2 + '}';
    }



    public static class Builder {

        private String param1;
        private int param2;

        public Builder setParam1(String param1) { this.param1 = param1; return this; }
        public Builder setParam2(int param2) { this.param2 = param2; return this; }

        public Config build() {
            Config config = new Config();
            config.param1 = param1;  // <- Accessing private member of outer class
            config.param2 = param2;
            return config;
        }


        public void modifyParm2(Config config, int newVal) {
            config.param2 = newVal;  // <- Able to modify private member of any enclosing class
        }

    }

}

配置测试:

public class ConfigTest {


    private Config getConfig() {

        Config.Builder builder = new Config.Builder();

        Config config = builder
                .setParam1("Val1")
                .setParam2(2)
                .build();

        return config;

    }

//    private void manipulateConfig(Config config, String newParam1) {
//        config.param1 = newParam1;
//    }

    public static void main(String[] args) {

        ConfigTest configTest = new ConfigTest();
        Config config = configTest.getConfig();
        System.out.println(config);

        Config.Builder anotherBuilder = new Config.Builder();
        anotherBuilder.modifyParm2(config, 3);
        System.out.println(config);

//        configTest.manipulateConfig(config, "val11");

    }

}

运行 ConfigTest 的输出:

Config{param1=Val1, param2=2}
Config{param1=Val1, param2=3}

【问题讨论】:

  • 如果编译器允许你这样做......
  • “静态内部”在术语上是矛盾的。您的意思是“静态嵌套”。
  • @EJP 感谢您的更正。我更改了我能找到的剩余术语误用。

标签: java inner-classes


【解决方案1】:

您链接的答案并不完全正确:嵌套静态类可以访问其封闭类的所有成员,包括私有成员。

他们无法访问其封闭实例的公共或私有实例成员。但是,如果将静态嵌套类的方法传递给封闭类的实例,则嵌套类将能够访问封闭类的所有成员,而不管它们的访问级别如何。

我认为静态/非静态的混淆来自JLS这行:

成员类可能是静态的,在这种情况下它们无法访问周围类的实例变量

这并不意味着静态嵌套类根本无法访问实例变量。这意味着静态嵌套类无法“免费”访问封闭类的实例变量,就像非静态嵌套类所做的那样。

对我来说,静态嵌套类和顶级类之间的两个主要区别是

  1. 嵌套的静态类和接口表达了与其封闭类/接口更紧密的关联。例如,Map.Entry 嵌套接口比MapEntry 顶级接口的可读性更好。
  2. 如果您将嵌套类声明为私有,则它们可以作为另一个类的实现细节。您不能对顶级类执行此操作,因为它们至少对同一包中的类仍然可以访问。

【讨论】:

  • 使用非静态嵌套类,访问封闭实例的私有成员对我来说是有意义的。但是对于静态嵌套类,没有封闭实例,因此看起来嵌套类可以访问外部类的任何其他实例的私有成员,如上面的示例行anotherBuilder.modifyParm2(config, 3);。这对我来说感觉不对。
  • @Glenn 为什么?这对我来说非常有意义:如果这两个类在功能上密切相关,但它们的实例之间没有一对一的关系,那么可以访问封闭类的私有成员的静态类提供了一个不错的选择。
  • 我猜你是对的。这只是我以前没有意识到的一个微妙之处,我找不到任何文档或 cmets 指出这一点。然后我会认为a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience 的 Java 教程评论具有误导性:紧密耦合引入了行为变化。在我的示例中,我希望使用 Builder 来生成不可修改的实例,它恰好是一个非常有用的属性。
  • @Glenn 我同意 - 我认为本教程对材料的简化有点过头了。为了他们的辩护,静态类应该访问其封闭类的私有实例变量的情况的用例很难在向读者介绍嵌套类概念的教程的上下文中解释。
猜你喜欢
  • 2014-05-31
  • 2011-01-14
  • 2011-08-04
  • 2017-01-25
  • 2023-03-29
  • 1970-01-01
  • 2014-08-30
  • 2020-01-19
  • 2011-08-11
相关资源
最近更新 更多