Неопределенный класс в аргументах метода у интерфейса
public interface ClassWithList {
public void clearList();
public void tryAdd(Class<T> b);
public void update(Class<T> c);
}
При расширении указываю конкретный класс, и возникает ошибка.
public class Test implements ClassWithList {
@Override
public void clearList() {}
@Override
public void tryAdd(Test b) {
// Error
}
@Override
public void update(Test c) {
// Error
}
}
Может ли Java расширять интерфейс подобным образом?
Подскажите, что я делаю не так.
Спасибо!
Ответы (1 шт):
Поскольку в представленном коде возникают ошибки компиляции, связанные с неопределённым типом T в интерфейсе ClassWithList, прежде всего нужно решить эту проблему.
cannot find symbol public void tryAdd(Class<T> b); ^ symbol: class T location: interface ClassWithList error: cannot find symbol public void update(Class<T> c); ^
Для этого существуют два способа:
- Объявить интерфейс
ClassWithListобобщённым
В таком случае аргументы у методовtryAdd,updateбудут использовать один и тот же тип.
При этом, в методахtryAdd,updateаргумент должен иметь типT, а неClass<T>, если в классеTest, реализующем данный интерфейс, аргумент в упомянутых методах должен иметь типTest:
public interface ClassWithList<T> {
public void clearList();
public void tryAdd(T b);
public void update(T c);
}
Тогда при объявлении класса Test следует указать в угловых скобках тип класса-параметра:
public class Test implements ClassWithList<Test> {
@Override public void clearList() {}
@Override public void tryAdd(Test b) {}
@Override public void update(Test c) {}
}
Такая реализация наиболее естественная, в указанные методы можно передавать экземпляры класса Test:
Test t = new Test();
t.tryAdd(t);
1.а) Если аргументы в упомянутых методах по какой-либо причине должны сохранить тип Class<T>, потребуется следует изменить реализацию, чтобы она соответствовала интерфейсу.
public interface ClassWithListA<T> {
public void clearList();
public void tryAdd(Class<T> b);
public void update(Class<T> c);
}
public class TestA implements ClassWithListA<TestA> {
@Override public void clearList() {}
@Override public void tryAdd(Class<TestA> b) {}
@Override public void update(Class<TestA> c) {}
}
При вызове методов в данной реализации можно передавать только тип, известный на момент компиляции, т.е. TestA.class:
ClassWithListA t2 = new TestA();
// ок
t2.update(TestA.class);
// ошибка
t2.update(t2.getClass());
// Class cannot be converted to Class
// where CAP#1 is a fresh type-variable:
// CAP#1 extends TestA from capture of ? extends TestA
- Объявить каждый из методов
tryAdd,updateкак обобщённый
public interface ClassWithListB {
public void clearList();
public <T> void tryAdd(Class<T> b);
public <T> void update(Class<T> c);
}
Поскольку в объявлении этого интерфейса не указан параметр типа, он сам по себе не обобщённый, поэтому в реализации также останутся обобщённые методы:
class TestB implements ClassWithListB {
@Override public void clearList() {}
@Override public <T> void tryAdd(Class<T> b) {}
@Override public <T> void update(Class<T> c) {}
}
То есть, в них можно будет передавать объекты любых классов:
ClassWithListB t3 = new TestB();
t3.update(ClassWithListA.class);
t3.tryAdd("abcd".getClass());
t3.update(t2.getClass());
t3.tryAdd(t3.getClass());
Вопрос о необходимости такой реализации остается открытым.