【问题标题】:Java: Anonymous Inner Class Instance Initializer Access to Outer Class Private MembersJava:匿名内部类实例初始化程序访问外部类私有成员
【发布时间】:2014-04-15 13:51:17
【问题描述】:

我有一种情况,我无法更改一组类的主要API,但我需要从归档数据中构造一个新实例,包括设置大量私有字段。

到目前为止,我的想法是创建一个静态工厂方法,该方法将从档案中生成我的实例,如下所示:

版本 1:

public class Item {
    private Long id;

    public static Item fromArchived(final ArchivedItem archived) {
        return new Item(){{
            this.id = archived.getId();
        }};
    }
}

IntelliJ IDEA 没有给我任何红线,直到我运行我的 maven 构建,我才知道有问题:

error: id has private access in Item

相比之下,这是可行的:

版本 2:

public class Item {
    private Long id;

    public static Item fromArchived(final ArchivedItem archived) {
        Item item = new Item(){{
//            this.id = archived.getId();
        }};

        item.id = archived.getId();

        return item;
    }
}

我一直在审查我的coreJavaknowledge,关于版本 1 为何不起作用的唯一模糊猜测是实例初始化程序(双括号初始化)以某种方式出现在静态上下文,这也没有任何意义。想法?

编辑

我认为问题的最初形式是模糊的。我正在寻找的答案解释了为什么我在静态方法的主体中可以看到父级的私有 id 字段,但在同一内部匿名子类的实例初始化程序的主体中却无法看到它静态方法。

【问题讨论】:

    标签: java inner-classes


    【解决方案1】:

    其他答案是准确的,但这是我的看法。

    public class Item {
        private Long id;
    
        public static Item fromArchived(final ArchivedItem archived) {
            return new Item(){{
                this.id = archived.getId();
            }};
        }
    }
    

    这里的静态方法生成了一个扩展 Item 的匿名类。 Item$id 将对这个匿名类隐藏。

    下面的sn-p等价于前面的,但是作为一个命名的嵌套类,它暴露了一个构造方法,而不是一个调用构造方法的方法。

    public class Item {
        private Long id;
    
        class FromArchived extends Item {
            public FromArchived(final ArchivedItem archived) {
                this.id = archived.getId();
            }
        }
    }
    

    无论访问是来自命名类、嵌套类还是匿名类,都会一致地强制执行可见性修饰符。

    最后,下面的 sn-p 应该像在一个类中一样工作,您可以完全访问该类的所有私有字段和方法。

    public class Item {
        private Long id;
    
        public static Item fromArchived(final ArchivedItem archived) {
            Item item = new Item();
            item.id = archived.getId();
            return item;
        }
    }
    

    无论您是在构造函数、方法还是静态方法中,这都是正确的。

    【讨论】:

      【解决方案2】:

      您一直在创建扩展 Item 类的匿名内部类。private 变量可从声明的同一类中访问。因此您不能访问 Item 中的 Item 类私有变量@内部类

      【讨论】:

      • 我明白了。我尝试不使用 this 并且抱怨无法在静态上下文中访问 id。
      【解决方案3】:

      在您的第一个示例中,this 指的是匿名(内部)Item,而不是外部,这就是您收到错误消息的原因。

      【讨论】:

      • 我故意引用内部的id,因为在静态上下文中没有外部id。我正在尝试在工厂创建一个实例,并且我显然可以看到实例的私有字段(上面的版本 2),但是在实例初始化程序的情况下我的可见性受到限制?
      【解决方案4】:

      使用下面的构造,您可以创建 Item 子类,其中包含实例初始化块。

      return new Item() { // equivalent to: class AnonymousItem extends Item
          {
              this.id = archived.getId();
          }
      };
      

      子类无法访问父类的私有字段,因此编译器会为您生成错误。

      【讨论】:

      • 我意识到,在正常情况下,子类无法访问父类的私有字段,但为什么内部类不能访问?
      【解决方案5】:

      你可以写((Item) this).id = ...或super.id = ...,而不是写this.id = ...。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-15
        • 2013-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多