本文介绍了升级到Java 7后,泛型类的类型参数化字段不可见的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 现在 Eclipse Indigo SR1 内置Java 7 支持自一周或两周后终于出来,我我将我的游乐场项目从Helios SR2 + JDK 1.6_23迁移到Indigo SR1 + JDK 1.7.0。完成所有项目的重建后,只有一个类未能编译。它是下面的类,在Java 1.6(和1.5)上编译和运行得非常好: $ b public抽象类区域< A extends Area<>>实现可比< Area<>> { 私人字符串名称; 私人区域<?>父母; 私人套餐< A>区; 保护区域(字符串名称,A ...区域){ this.name = name; this.areas = new TreeSet< A>(); (面积:地区){ area.parent = this; this.areas.add(area); } } public Set< A> getAreas(){返回区域; } // ... } area.parent = this; 失败,并在父母中出现以下错误: 字段Area< capture#1 of?>。parent is not visible 在第一次怀疑Eclipse编译器之后,我用JDK 1.7.0中的plain javac 尝试过,但它给出了基本相同的错误,而 JDK 1.6.0_23中的javac 成功无误。 将可见性更改为 protected 或默认解决问题。但为什么完全超出了我。我偷看了 http://bugs.sun.com ,但我找不到任何类似的报告。 解决编译错误的另一种方法是用 A 声明c> Area (或者完全删除它): public abstract class Area< A extends Area<>>实现可比< Area<>> { 私人字符串名称; 私人区域<?>父母; private Set< Area<?>>区; 保护区域(字符串名称,区域<>区域){ this.name = name; this.areas = new TreeSet< Area<>>(); for(Area area:areas){ area.parent = this; this.areas.add(area); } } public Set< Area<>> getAreas(){返回区域; } // ... } public class Country extends Area< City> { public Country(String name,City ... cities){ super(name,cities); } } 我希望它能够返回设置< City> ,而不是 Set< Area<>> 。 Java 7中的哪个更改导致这些类型参数化字段变为不可见? 解决方案是一个javac6错误,在javac7中已修复。 解决方法是上传: ((区域<>区域).parent = this; 这看起来很奇怪 - 为什么我们需要上演访问超类中的成员? 根本问题是,私有成员被明确排除在继承之外,因此 A 没有父成员。同样的问题可以通过一个非泛型的例子来证明。 错误信息 parent在区域中具有私人访问权限并不完全准确,尽管在大多数情况下它可能很好。然而,在这种情况下,这是误导性的,更好的消息是 A不从区域继承私有成员'父母' 为了调查的兴趣,我们来对基于JLS的示例进行全面分析: §4.4:一个类型变量 X 的成员绑定了 T& I1 ... In 是交集类型的成员(§4.9) T& I1 ...在中出现在声明类型变量的地方。 §4.9:交集类型相同成员作为具有空体的类类型(§8),直接超类 Ck 和直接超接口 IT1,...,ITn,在交集类型出现的相同包中声明。如果成员或构造函数被声明为私有的,那么当且仅当它存在于顶级类的主体内时,才允许访问(§7.6)包含成员或构造函数的声明。 §8.2:声明为private的类的成员不会被该类的子类继承。 第8.5节:类继承自它的直接超类和直接超类接口,超类和超接口的所有非私有成员类型都可以在类中进行访问,并且不会被类中的声明隐藏。 Now Eclipse Indigo SR1 with builtin Java 7 support is finally out since a week or two, I'm migrating my playground projects from Helios SR2 + JDK 1.6_23 to Indigo SR1 + JDK 1.7.0. After a full rebuild of all projects, only one class has failed to compile. It's the following class which compiles and runs perfectly fine on Java 1.6 (and 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; } // ...}The line area.parent = this; fails with the following error on parent: The field Area<capture#1-of ?>.parent is not visible After first suspecting the Eclipse compiler, I tried with plain javac from JDK 1.7.0, but it gives basically the same error whereas the javac from JDK 1.6.0_23 succeeds without errors.Changing the visibility to protected or default solves the problem. But the why is completely beyond me. I peeked around on http://bugs.sun.com, but I couldn't find any similar report. Another way to fix the compilation error is to replace all used A declarations inside the class by Area<?> (or to remove it altogether):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; } // ...}But this breaks the purpose of the getter. In case of for example the following class:public class Country extends Area<City> { public Country(String name, City... cities) { super(name, cities); }}I'd expect it to return Set<City>, not Set<Area<?>>.Which change in Java 7 has caused those type-parameterized fields to become invisible? 解决方案 This appears to be a javac6 bug, which is fixed in javac7.The workaround is by up-cast:((Area<?>)area).parent = this;Which seems really odd - why would we need an up-cast to access a member in super class? The root problem is, private members are specifically excluded from inheritance, therefore A does not have a parent member. The same problem can be demonstrated by a non-generic example.The error message "parent has private access in Area" is not quite accurate, though it's probably fine for most cases. However in this case, it's misleading, a better message would be "A does not inherit the private member 'parent' from Area"For the interest of investigation, let's do a full analysis on your example based on the JLS:§4.4: The members of a type variable X with bound T & I1 ... In are the members of the intersection type (§4.9) T & I1 ... In appearing at the point where the type variable is declared.§4.9: The intersection type has the same members as a class type (§8) with an empty body, direct superclass Ck and direct superinterfaces IT1 , ..., ITn, declared in the same package in which the intersection type appears. §6.6.1: If the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor. §8.2: Members of a class that are declared private are not inherited by subclasses of that class.§8.5: A class inherits from its direct superclass and direct superinterfaces all the non-private member types of the superclass and superinterfaces that are both accessible to code in the class and not hidden by a declaration in the class. 这篇关于升级到Java 7后,泛型类的类型参数化字段不可见的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-22 15:27