2016-07-27 4 views
2

Я столкнулся с ситуацией, когда не ясно, как сделать компиляцию кода, хотя ее можно легко решить, создав новый метод в каждом подклассе, а не один метод в суперклассе (но это выглядит уродливо!) I «ве упростил мой код, так что я начинаю с цепью классов (я объявляю их статическими просто для удобства):Java-вложенные дженерики: какой должен быть формальный тип параметра?

interface U0 { } 
static class U1 implements U0 { 
    public int x = 1; 
} 
static class U2 extends U1 { } 

Тогда есть абстрактный класс, который делает что-то с каким-то контейнером:

static abstract class M<U extends U0, C extends List<? extends U>> { 
    C field; 
    public abstract boolean check(C c); 
} 

и пример производного класса, действующего на U1 или любого потомка U1 (скажем, U2):

static class M1 extends M<U1, List<? extends U1>> { 

    @Override 
    public boolean check(List<? extends U1> c) { 
     return !c.isEmpty() && c.get(0).x > 0; 
    } 

} 

Теперь, скажем, я хочу, чтобы расширить емкость, добавьте сначала общий класс:

static class MyList<U extends U0> extends ArrayList<U> { 
    ... 
} 

и производный класс, который называет "проверить" метод M:

static class MyList1 extends MyList<U2> { 
    void test() { 
     M1 m1 = new M1(); 
     m1.check(this); 
    } 
} 

Все это работает до сих пор, но сейчас я хочу заменить линии

M1 m1 = new M1(); 
m1.check(this); 

одним звонком

callCheck(new M1()); 

какой-либо метод, заявленный в MyList. Таким образом, класс MyList теперь изменяется на

static class MyList<U extends U0> extends ArrayList<U> { 
    void callCheck(??? m) { 
     m.check(this); 
    } 
} 

Какой должен быть тип параметра m?

Также обратите внимание, что могут быть и другие потомки М с, скажем, C = MyList1 или какой-либо другой расширение списка, и до сих пор callCheck должны работать с этими потомками, а также (до тех пор, как код

SomeM someM = new SomeM(); 
someM.check(this); 

работает, где SomeM расширяет M < ...>)

+0

Этот код компилируется с помощью Java 1.8.0_77 и установка parmaeter type to M – ghg565

+0

Да, но есть два предупреждения: тип сырого типа и тип безопасности ... Можно ли обойтись без него? В противном случае нет смысла использовать генераторы в любом случае ... –

ответ

0

Во-первых, я избавился от первого параметра типа M, что бесполезно. U не используется в корпусе M и отображается только один раз внутри определения другой границы как ? extends U, но с U extends U0 это просто эквивалентно ? extends U0. (. Если это не ваш реальный код и U используется где-то, что, вероятно, может быть добавлен обратно с некоторой мысли)

компилируется:

interface U0 { } 
static class U1 implements U0 { 
    public int x = 1; 
} 
static class U2 extends U1 { } 

static abstract class M<C extends List<? extends U0>> { 
    C field; 
    public abstract boolean check(C c); 
} 

static class M1 extends M<List<? extends U1>> { 

    @Override 
    public boolean check(List<? extends U1> c) { 
     return !c.isEmpty() && c.get(0).x > 0; 
    } 

} 

static class MyList<U extends U0> extends ArrayList<U> { 
    void callCheck(M<? super MyList<U>> m) { 
     m.check(this); 
    } 
} 

static class MyList1 extends MyList<U2> { 
} 

//... 
new MyList1().callCheck(new M1()); 
+0

Спасибо, это именно то, что мне нужно! –

+0

После некоторого раздумья я понял, что если есть другой потомок 'M', который использует, например,' MyList2' вместо 'List', то' callCheck' не будет работать: –

+0

Это код: static class M2 расширяет M > { @Override public boolean check (MyList2 c) { return! c.isEmpty() && c.get (0) .x> 0; } Тогда, очевидно, новый MyList1(). CallCheck (новый M1()); 'не будет работать, а также' new M2(). Check (new MyList1()); 'won ' t, так как метод 'check'' M2' может использовать некоторые методы, объявленные в 'MyList1' и отсутствующие в' MyList'. –

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