2009-04-18 3 views
0

У меня есть класс Java B с внутренним классом C. Некоторые методы B принимают экземпляр C как параметра, но я хочу только принять экземпляры C, созданные соответствующим экземпляром B. Есть ли способ выполнить эту проверку во время компиляции?Проверка экземпляров внутренних классов


Пример

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. 

Мой случай

Иметь имена классов Карта, которые удерживают матрицу экземпляров внутреннего MapArea класса. Самое приятное в этой схеме заключается в том, что я могу проверять поля xPos и ​​yPos в конструкторе, поэтому не создаются недопустимые области для данной карты. Карта как метод distanceFrom (MapArea startPos, MapArea toLocation, MapArea ... otherLocations), и я пытался избежать повторной проверки аргументов области карты.

+0

C c1 = новый C(); B foo = c1.getB() C c2 = новый C(); c2.method (foo) // Я хочу ошибку компилятора здесь. –

+0

Итак, вы говорите о наличии нескольких внешних (B) объектов, каждый из которых может создавать несколько внутренних (C) объектов, но некоторые методы объекта C должны принимать только B, из которого они были созданы? Я не вижу, как вы это сделаете во время компиляции. Вы говорите больше о иерархии времени исполнения. Единственный способ, которым я могу видеть, что вы можете это сделать, - пометить каждый C своим родителем (B, который его создал), а затем как-то проверить его во время выполнения с помощью assert. Возможно, компилятор вам не поможет. – Andrew

+1

Глядя на ваш пример: короткий ответ, нет. Компилятор не может проверить, как вы хотите. – Andrew

ответ

0

Если вы сделаете конструктор внутреннего класса (C) частным, я считаю, что включенный класс (B) все еще может создавать его, а другие классы не могут. Это гарантирует, что только B и C могут создавать экземпляр C.

Редактировать: Я проверил это с небольшим макетом. Сделайте внутренний конструктор класса закрытым, а затем только внутренний класс (C) или охватывающий класс (B) может его создать.

См. http://tns-www.lcs.mit.edu/manuals/java-1.1.1/guide/innerclasses/spec/innerclasses.doc6.html для получения дополнительной информации. В частности: «Защита доступа никогда не препятствует тому, чтобы класс использовал какой-либо член другого класса, если один ограничивает другой, или они заключены в третий класс».

+0

У меня уже есть частный конструктор, вы можете проверить пример, который я добавил. –

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

На самом деле, так как одновременно ответов показывает, Кип, B может получить доступ к C.this, чтобы получить родительский объект, поэтому нет необходимости хранить родительскую ссылку. Однако описанный выше метод был бы необходим, если бы C не был фактически внутренним классом.

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; } 
    //... 
    } 
} 
0

Там нет времени компиляции способа защиты от использования экземпляра конкретного. Ваш лучший выбор, вероятно, бросает исключение, когда использование неверно. Другой вариант, который у вас есть, состоит в том, чтобы родительский класс имел Map экземпляров внутреннего класса и чтобы другие классы указывали внешнему классу работать с внутренним классом не экземпляром, а с помощью некоторых других ссылок. Это будет работать с другими классами, не нужно ничего делать непосредственно с внутренним классом.

3

Если это действительно то, что вы хотите, 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

+1. Это лучший ответ, который я видел до сих пор. Если метод находится во внутреннем классе, тогда невозможно вызвать неправильный внешний класс. – Eddie

Смежные вопросы