Неопределенный класс в аргументах метода у интерфейса
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());
Вопрос о необходимости такой реализации остается открытым.