升级到Java 7后,generics类的types参数化字段变为不可见
现在, Eclipse Indigo SR1内置Java 7支持终于在一两周内出现,我将我的游乐场项目从Helios SR2 + JDK 1.6_23迁移到Indigo SR1 + JDK 1.7.0。 所有项目完全重build后,只有一个类未能编译。 下面这个类在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
上失败并出现以下错误:
区域<capture#1-of>父区不可见
在第一次怀疑Eclipse编译器之后,我试着用JDK 1.7.0中的普通的javac
,但是它给出了基本相同的错误,而来自JDK 1.6.0_23的javac
成功没有错误。
将可见性更改为protected
或缺省可解决问题。 但为什么完全超越了我。 我偷窥了http://bugs.sun.com ,但是我找不到任何类似的报告。
解决编译错误的另一种方法是用Area<?>
replace类中所有使用的A
声明(或者将其全部删除):
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中的哪个更改导致这些types参数化的字段变得不可见?
这似乎是一个javac6的错误,这是在javac7中修复的。
解决方法是上传:
((Area<?>)area).parent = this;
这看起来很奇怪 – 为什么我们需要上演访问超级成员?
根本问题是,私有成员被明确排除在inheritance之外,因此A
没有parent
成员。 同样的问题可以通过一个非generics的例子来certificate。
错误消息“ 家长在区域中具有私人访问 ”并不十分准确,尽pipe在大多数情况下它可能是正确的。 然而,在这种情况下,这是误导性的,更好的消息将是“ A不从Areainheritance私有成员'父'
为了调查的兴趣,让我们对你的基于JLS的例子做一个完整的分析:
-
§4.4:绑定
T & I1 ... In
的typesvariablesX
的成员是交集types的成员(§4.9)T & I1 ... In
出现在声明typesvariables的地方。 -
§4.9:交集types与空类体,直接超类
Ck
和直接超接口IT1 , ..., ITn,
ITn的类types(§8)具有相同的成员,在交集types出现的相同包中声明。 -
§6.6.1:如果成员或构造函数被声明为private,则只有在包含成员或构造函数声明的顶级类(§7.6)的主体内才允许访问。
-
§8.2:被声明为private的类的成员不会被该类的子类inheritance。
-
§8.5:一个类inheritance自它的直接超类,并直接超接口所有超类和非超类接口的非私有成员types,它们都可以在类中进行访问,并且不会被类中的声明所隐藏。