Java:匿名内部类实例初始化程序访问外部类私有成员

时间:2014-04-15 13:51:18

标签: java inner-classes

我的情况是我无法更改一组类的主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;
    }
}

我一直在审核我的core Java knowledge,我唯一模糊的猜测是为什么版本1不起作用的是实例初始值设定项(双括号初始化) )不知何故发生在静态上下文中,这也没有意义。想法?

修改

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

5 个答案:

答案 0 :(得分:2)

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

public class Item {
    private Long id;

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

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

以下代码段与前一个代码段相同,但是作为一个命名的嵌套类,它暴露构造函数方法而不是调用构造函数的方法。

public class Item {
    private Long id;

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

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

最后,以下代码段应该在课堂内工作,您可以完全访问所有私有字段&该类的方法。

public class Item {
    private Long id;

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

无论您是在构造函数,方法还是静态方法中,都是如此。

答案 1 :(得分:1)

你一直在创建扩展Item类的匿名内部类。private变量可以在那些声明的同一个类中访问。所以你不能访问Itemanonymous内部类

中的私有变量

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

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

答案 4 :(得分:0)

您可以写this.id = ...((Item) this).id = ...而不是写super.id = ...