【问题标题】:Validating instances of inner-classes验证内部类的实例
【发布时间】:2009-04-18 12:26:37
【问题描述】:

我有一个带有内部类 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) 我试图避免再次验证地图区域参数。

【问题讨论】:

  • C c1 = new C(); B foo = c1.getB() C c2 = 新 C(); c2.method(foo) // 我这里要编译错误。
  • 所以您说的是拥有多个外部 (B) 对象,每个对象可以创建多个内部 (C) 对象,但某些 C 对象方法必须只接受创建它们的 B?我不知道你将如何在编译时做到这一点。您正在谈论更多关于运行时层次结构。我能看到你可以做到这一点的唯一方法是用它的父级(创建它的 B)标记每个 C,然后在运行时使用断言以某种方式验证它。编译器可能帮不了你。
  • 看更多你的例子:简短的回答,不。编译器无法根据需要进行验证。
  • 我可以请您将其放入您的答案中以便我标记它吗?
  • 你到底为什么要这样做?

标签: java validation


【解决方案1】:

如果这确实是您想要的行为,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;
      //...
    }
  //...
  }
  //...
}

当然,如果您想要public void method(B b1, B b2, B b3),这并不能解决问题,其中 B 的所有三个实例都被同一个 C 实例包围。

【讨论】:

  • +1。这是迄今为止我看到的最好的答案。如果方法在内部类上,则不可能调用错误的外部类。
【解决方案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】:

    在编译时没有办法(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 实际上不是内部类,则上述方法将是必要的。

    【讨论】:

      【解决方案4】:

      如果你将内部类 (C) 的构造函数设为私有,我相信封闭类 (B) 仍然可以实例化它,而其他类则不能。这确保只有 B 和 C 可以实例化 C。

      编辑:我已经用一个小模型验证了这一点。将内部类构造函数设为私有,然后只有内部类(C)或封闭类(B)可以实例化它。

      请参阅http://tns-www.lcs.mit.edu/manuals/java-1.1.1/guide/innerclasses/spec/innerclasses.doc6.html 了解更多信息。特别是:“访问保护永远不会阻止一个类使用另一个类的任何成员,只要一个包含另一个类,或者它们被第三个类包围。”。

      【讨论】:

      • 我已经有一个私有构造函数,你可能想检查我添加的示例。
      【解决方案5】:

      没有编译时方法可以防止特定于实例的使用。当使用不正确时,您最好的选择可能是抛出异常。您拥有的另一个选择是让父类拥有内部类实例的Map,并让其他类告诉外部类不是通过实例而是通过其他一些引用对内部类进行操作。这将适用于其他类,不需要直接对内部类做任何事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-21
        • 2011-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-19
        相关资源
        最近更新 更多