升级到Java 7后,泛型类的类型参数化字段将变为不可见

Bal*_*usC 44 java generics visibility java-7

现在,带有内置Java 7支持的Eclipse Indigo SR1终于推出了一两个星期,我正在将我的游乐场项目从Helios SR2 + JDK 1.6_23迁移到Indigo SR1 + JDK 1.7.0.完全重建所有项目后,只有一个类无法编译.它是以下类,它在Java 1.6(和1.5)上编译和运行完全正常:

public abstract class Area<A extends Area<?>> implements Comparable<Area<?>> {

    private String name;
    private Area<?> parent;
    private Set<A> areas;

    protected Area(String name, A... areas) {
        this.name = name;
        this.areas = new TreeSet<A>();
        for (A area : areas) {
            area.parent = this;
            this.areas.add(area);
        }
    }

    public Set<A> getAreas() {
        return areas;
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

该行area.parent = this;失败,出现以下错误parent:

字段Area <capture#1-of?>.parent不可见

在第一次怀疑Eclipse编译器之后,我尝试使用javacJDK 1.7.0中的plain ,但是它给出了基本相同的错误,而javac来自JDK 1.6.0_23的成功没有错误.

将可见性更改为protected或默认可解决问题.但是为什么完全超出我的范围.我在http://bugs.sun.com上偷看,但我找不到任何类似的报道.

修复编译错误的另一种方法是用A类替换所有使用过的声明Area<?>(或者完全删除它):

public abstract class Area<A extends Area<?>> implements Comparable<Area<?>> {

    private String name;
    private Area<?> parent;
    private Set<Area<?>> areas;

    protected Area(String name, Area<?>... areas) {
        this.name = name;
        this.areas = new TreeSet<Area<?>>();
        for (Area<?> area : areas) {
            area.parent = this;
            this.areas.add(area);
        }
    }

    public Set<Area<?>> getAreas() {
        return areas;
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

但这打破了吸气剂的目的.例如,以下类:

public class Country extends Area<City> {

    public Country(String name, City... cities) {
        super(name, cities);
    }

}
Run Code Online (Sandbox Code Playgroud)

我希望它能够回归Set<City>,而不是Set<Area<?>>.

Java 7中的哪个更改导致这些类型参数化字段变得不可见?

irr*_*ble 31

这似乎是一个javac6错误,在javac7中修复.

解决方法是向上转换:

((Area<?>)area).parent = this;
Run Code Online (Sandbox Code Playgroud)

这看起来很奇怪 - 为什么我们需要一个up-cast来访问超类中的成员?

根本问题是,私有成员被明确排除在继承之外,因此A没有parent成员.非通用示例可以证明同样的问题.

错误消息" 父亲在区域中有私人访问权限 "并不十分准确,尽管在大多数情况下它可能都很好.但是在这种情况下,它会产生误导,更好的消息是" A不会从Area继承私有成员'父级' "


为了调查的利益,让我们基于JLS对您的示例进行全面分析:

  • §4.4:X带有bound 的类型变量T & I1 ... In的成员是T & I1 ... In出现在声明类型变量的点处的交集类型(第4.9节)的成员.

  • §4.9:交集类型与类类型(§8)具有相同的成员,其中包含空体,直接超类CkIT1 , ..., ITn,在交叉类型出现的同一包中声明的直接超接口.

  • §6.6.1:如果成员或构造函数被声明为private,则当且仅当它发生在包含成员或构造函数声明的顶级类(第7.6节)的主体内时才允许访问.

  • §8.2:声明为private的类的成员不会被该类的子类继承.

  • §8.5:一个类继承自其直接超类和直接超接口超类和超接口的所有非私有成员类型,这些类型既可以访问类中的代码,也不会被类中的声明隐藏.

  • 使用新的关键字,我终于找到了两个相关的错误报告:[6711619](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6711619)和[7022052](http://bugs.sun.com /bugdatabase/view_bug.do?bug_id=7022052). (3认同)