泛型类的类型参数化字段在升级到 Java 7 后变得不可见

2022-09-01 00:11:58

现在,具有内置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;
    }

    // ...
}

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

字段区域<捕获 #1-of ?>.parent 不可见

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

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

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

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;
    }

    // ...
}

但这打破了获取者的目的。例如,在以下类的情况下:

public class Country extends Area<City> {

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

}

我希望它能回来,而不是。Set<City>Set<Area<?>>

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


答案 1

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

解决方法是通过向上转换:

((Area<?>)area).parent = this;

这似乎很奇怪 - 为什么我们需要一个上层演员来访问超级类的成员?

根本问题是,私有成员被明确排除在继承之外,因此没有成员。同样的问题可以通过一个非通用的例子来证明。Aparent

错误消息“父级在区域中具有专用访问权限”不是很准确,尽管在大多数情况下可能没问题。但是,在这种情况下,它具有误导性,更好的消息是“A不会从区域继承私人成员'父'。"


为了便于调查,让我们根据 JLS 对您的示例进行全面分析:

  • §4.4: 带 bound 的类型变量的成员是出现在声明类型变量的点的交集类型 (§4.9) 的成员。XT & I1 ... InT & I1 ... In

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

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

  • §8.2:声明为私有的类的成员不会被该类的子类继承。

  • §8.5:类从其直接超类继承,并直接超接口继承超类和超接口的所有非私有成员类型,这些超接口既可供类中的代码访问,又不被类中的声明隐藏。


答案 2