我有一个带有内部类C的Java类B.一些B的方法接受一个C实例作为参数,但我只想接受由B的正确实例创建的C实例。有没有办法进行这种验证在编译时?
示例
C c1 = new C();
B foo = c1.getB(); // foo was created by instance c1
C c2 = new C();
c2.method(foo); // I want a compiler error here.
我的案例
有一个类名Map,它包含内部类MapArea的实例矩阵。这个方案的好处是我可以在构造函数中验证xPos和yPos字段,因此不会构建给定映射的无效区域。地图作为方法distanceFrom(MapArea startingPos,MapArea toLocation,MapArea ... otherLocations),我试图避免再次验证地图区域参数。
答案 0 :(得分:3)
如果这确实是你想要的行为,那么{I}应该真正在内部类中定义。
换句话说,而不是:
method()
应该是:
public class C {
//...
public void method(B b) {
this.x = b.y;
//...
}
//...
public class B {
//...
}
//...
}
当然,如果您想要public class C {
//...
public class B {
//...
public void method() {
C c = this.C;
c.x = this.y;
//...
}
//...
}
//...
}
,并且B的所有三个实例都被C的相同实例包围,那么这就无法解决问题。
答案 1 :(得分:2)
在编译时没有办法(AFAIK)这样做。
在运行时,您可以通过让外部实例的工厂方法将对自身的引用传递给内部实例的构造函数来实现。
内部类需要存储该引用,以便外部类可以检查它是否创建了该实例:
public class C {
public class B {
private C parent;
private B(C parent) {
this.parent = parent;
}
public C getParent() {
return parent;
}
}
public B getB() {
return new B(this);
}
public void method(B b) {
assert(this == b.getParent());
}
}
实际上,正如Kip的并发答案所示,B
可以访问C.this
来获取父对象,因此无需存储父引用。但是,如果C实际上不是内部类,则上述方法是必要的。
答案 2 :(得分:2)
编译错误无效,但您至少可以抛出异常:
public class C
{
public static void main (String [] args)
{
C c1 = new C();
B b = c1.getB();
c1.useB(b); //OK
C c2 = new C();
c2.useB(b); //throws IllegalArgumentException
}
public B getB() { return new B(); }
public void useB(B b) {
if(b.getC() != this)
throw new IllegalArgumentException();
//...
}
private class B
{
public C getC() { return C.this; }
//...
}
}
答案 3 :(得分:0)
如果你将内部类(C)的构造函数设为私有,我相信封闭类(B)仍然可以实例化它,而其他类则不能。这确保了只有B和C才能实例化C。
编辑:我已经用小样本验证了这一点。使内部类构造函数为private,然后只有内部类(C)或封闭类(B)才能实例化它。
有关详情,请参阅http://tns-www.lcs.mit.edu/manuals/java-1.1.1/guide/innerclasses/spec/innerclasses.doc6.html。特别是:“访问保护永远不会阻止类使用另一个类的任何成员,只要一个包含另一个类,或者它们被第三个类包围。”。
答案 4 :(得分:0)
没有编译时方法来防范特定于实例的用法。当用法不正确时,你最好的选择可能是抛出异常。另一个选择是让父类拥有内部类的Map
个实例,并让其他类告诉外部类不是通过实例而是通过其他一些引用来操作内部类。这将适用于其他类,不需要直接与内部类做任何事情。