2011-01-07 2 views
0

Скажем, у меня есть класс Foo, класс A и некоторый подкласс B A. A. Foo принимает A и его подкласс как общий тип. A и B оба требуют экземпляр Foo в своем конструкторе. Я хочу Foo A, чтобы быть типа А и Б Foo к типу B или суперкласс B. Таким образом, в сущности, Так что я хочу только это:Java: использование общих подстановочных знаков с подклассом

Foo<X> bar = new Foo<X>; 
new B(bar); 

быть возможным, если X либо A, B, или как подкласс A и B. суперкласс

до сих пор это то, что у меня есть:

class Foo<? extends A>{ 
    //construct 
} 


class A(Foo<A> bar){ 
    //construct 
} 

class B(Foo<? super B> bar){ 
    super(bar); 
    //construct 
} 

вызов super(...) не работает, потому что <A> строже <? super B>. Можно ли каким-либо образом использовать конструктор (или избежать дублирования кода другими способами) при одновременном применении этих типов?

Редактировать: Foo хранит коллекцию элементов общего типа параметров, и эти элементы и Foo имеют двунаправленную ссылку. Поэтому не следует связывать A с Foo.

+0

Это не выглядит как ваш фактический код. –

+0

Да, это упрощенная версия кода. Думаешь, я что-то пропустил? – gibberish

ответ

1

Если вы измените Конструктор для:

class A(Foo<? extends A> bar){ 
    //construct 
} 

будет делать то, что вы хотите?

Если вы действительно хотите ограничить конструктор от A до Foo, вам нужно предоставить другой защищенный метод (также известный как производные классы), чтобы установить экземпляр Foo. Что-то вроде этого:

public class A { 

    Foo<?> foo; 

    public A(Foo<A> foo) { 
     setFoo(foo); 
    } 

    protected A() { 
    } 

    protected void setFoo(Foo<?> foo) { 
     this.foo = foo; 
    } 
} 

и B

public class B extends A { 

    public B(Foo<? super B> foo) { 
     setFoo(foo); 
    } 
} 

теперь это работает:

new A(new Foo<A>()); 
new A(new Foo<B>()); // this fails compilation 
new B(new Foo<B>()); 

Для того, чтобы Foo элемент А, чтобы быть правильно набран вам может понадобиться, чтобы сделать A A параметризованный класс тоже.

+0

Да, похоже, нет способа избежать этой возможности. – gibberish

+0

hehe :) Я просто обновил ответ с лучшим вариантом, я думаю. –

+0

Кажется, это довольно хорошее решение, спасибо! :) Слишком плохо, что это не полностью прозрачно для подклассов/пакетов, но я думаю, что это просто невозможно. – gibberish

0

Единственный способ сделать это будет иметь ...

class A(Foo<? extends A> bar) { 
    //construct 
} 

Но, похоже, это не то, что вы хотите. У вас не может быть другого подхода, потому что, когда вы создаете экземпляр B, вы также создаете экземпляр A (который является частью экземпляра B). Таким образом, B не может принимать специальные поля для частей в A. Я не уверен, почему вы не позволили бы A foo быть типа B, не могли бы вы расширить его?

+0

Ну, Foo хранит коллекцию элементов общего типа параметров, и эти элементы и Foo имеют двунаправленную ссылку. Возможно, я должен был упомянуть об этом. Поэтому, если у меня есть Foo, содержащий B, я хочу предотвратить привязку A к нему. – gibberish

0

Следующая установка скомпилирован для меня:

public interface MarkerInterface { 

} 

public class A implements MarkerInterface { 

    public A(Foo<A> fooA) { 

    } 
} 

public class SuperB implements MarkerInterface { 

} 


public class B extends SuperB { 

    public B(Foo<? super B> fooB) { 

    } 
} 

И с main метода:

public static void main(String[] args) { 
    B b = new B(new Foo<SuperB>()); 
} 

Это то, что вы ищете?

+0

Спасибо за предложение, но этот метод удаляет иерархию классов. Я полагаю, идея состоит в том, чтобы поставить сигнатуры метода A в MarkerInterface? Дублирование всего кода A в B не кажется идеальным для меня. – gibberish

+0

Ну, я не знаю, как вам помочь, так как вы только расширили свой сценарий. –

0

Java-генераторы являются мощными и хорошо продуманными; тем не менее мы иногда находим их недостающими. Я не думаю, что есть хороший способ сделать то, что вы хотите.

Проще всего сделать, чтобы изменить объявление Foo<X> на Foo<X extends A>. Если это не приемлемо, вы можете создать подкласс Foo так:

class Foo<X> { } 

class FooA<X extends A> extends Foo<X> { } 

class A { 
    public A(FooA<? extends A> foo) { } 
} 

class B extends A { 
    public B(FooA<? super B> foo) { 
     super(foo); 
    } 
} 

(Примечание: если у вас есть проблемы после, когда вы видите Foo, думаю ArrayList.)

Это имеет очевидный недостаток, что вы должны используйте FooA, а не Foo, препятствие код повторное использование.

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