访问内部类的字段,有哪些推荐或正确的方式?

9

假设我们有这个类及其内部类:

/* Outer.java */
public class Outer {
    private static class Inner {
        private final Object foo;

        public Inner(Object foo) {
            this.foo = foo;
        }

        public Object getFoo() {
            return foo;
        }
    }

    Inner inner = parse(/* someMistery */);

    // Question: to access foo, which is recommended?
    Object bar = inner.getFoo();
    Object baz = inner.foo;
}

我很惊讶inner.foo能够起作用。

由于fooprivate的,所以只能通过getFoo()来访问,对吗?


1
Java的访问规则相当复杂(尤其是对于“protected”)。但如果它能正常工作,你应该感到高兴,为什么要抱怨呢 :) - ZhongYu
2个回答

11
由于foo是私有的,所以只能通过getFoo()访问,对吗?
在这种情况下,Outer也可以访问它,因为InnerOuter的成员。 6.6.1说:
[如果]成员或构造函数被声明为private,则只有当它在包含成员或构造函数声明的顶级类的主体内出现时才允许访问。
请注意,它被指定为可在包含声明的顶级类的主体内访问。
这意味着,例如:
class Outer {
    static class Foo {
        private Foo() {}
        private int i;
    }
    static class Bar {{
        // Bar has access to Foo's
        // private members too
        new Foo().i = 2;
    }}
}

无论使用getter与否都是个人口味问题。重要的是要认识到外部类可以访问其嵌套类的私有成员。
作为建议,我个人会说:
- 如果嵌套类是private(只有外部类可以访问它),除非getter执行了计算,否则我不会费心给它提供getter。这是任意的,其他人可以选择不使用它。如果样式混杂,代码就会变得模糊。(inner.foo和inner.getFoo()真的做同样的事情吗?我们必须浪费时间检查Inner类才能找出。) - 但是,如果你喜欢这种风格,你仍然可以通过getter来进行。 - 如果嵌套类不是private,请使用getter,以便样式统一。
如果你真的想要隐藏private成员,甚至连外部类也看不到,你可以使用一个带有本地或匿名类的工厂。
interface Nested {
    Object getFoo();
}

static Nested newNested(Object foo) {
    // NestedImpl has method scope,
    // so the outer class can't refer to it by name
    // e.g. even to cast to it
    class NestedImpl implements Nested {
        Object foo;

        NestedImpl(Object foo) {
            this.foo = foo;
        }

        @Override
        public Object getFoo() {
            return foo;
        }
    }

    return new NestedImpl(foo);
}

作为一条 pedantic 注意事项,你的 static class Inner {} 技术上是一个 静态嵌套类,而不是一个内部类。没有 staticclass Inner {} 将是一个内部类。
这是 明确定义 的:

static 关键字可以修改非内部类或接口 T 主体中成员类型 C 的声明。 它的效果是声明 C 不是内部类。


1
更严谨地说,“static, member, class” :) 嵌套类包括更多内容,例如局部类和匿名类;然而,只有成员类可以是静态的。 - ZhongYu
@bayou.io 是的,如果我们要具体说明的话。由于局部类和匿名类始终是内部类,所有静态嵌套类都是成员类。 - Radiodef
1
有趣的是,我不会理解Bar在顶层类的主体内,但它确实有效。(而且Eclipse不知道它,因为它抱怨私有的i没有被使用。)我猜“内部”可以有不同的理解方式 :) - eckes
@eckes 是的,这是一个奇怪的例子。 "类体" 是一个语法结构,它可以包含其他类体。 - Radiodef
是的,它可以包含在其中,但在这种情况下,我希望使用“在顶级类和嵌套所有类的主体内”(或类似语句)。仅限于某些情况下并不理想 :) - eckes
@eckes 是的,这就是JLS。要完全理解其中一部分,您需要阅读所有内容。每当我发现这样的歧义时,我倾向于在某个完全不同的部分中找到澄清的陈述。我们可以推断出我的解释的一种方式是,例如,如果不是这种情况,则嵌套的class Foo的私有成员将无法访问自身。 - Radiodef

0

这完全取决于你的代码片段,你想从哪里访问该对象。由于它是一个静态嵌套类,因此您可以从任何一种方式访问您的对象。请参考此链接http://www.javatpoint.com/static-nested-class以更好地理解内部类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接