2017-01-29 3 views
0

Насколько я понимаю, класс, реализующий интерфейс, может использовать дочерние классы класса, определенного в интерфейсе, а не только использовать этот конкретный класс.Реализация интерфейса с использованием исключения дочернего класса

Вот пример того, что я имею в виду: Предположим, что следующий код

public abstract class TestRootAbstractClass implements TestInterface {} 

и

public abstract class TestChildAbstractClass extends TestRootAbstractClass {} 

TestInterface определено в TestRootAbstractClass выглядит следующим образом

public interface TestInterface<T extends TestRootClass> { 
    void test(T extendedTestClass) throws Exception; 
} 

и TestRootClass ссылочного в TestInterface выглядит так

public abstract class TestRootClass {} 

Этот класс также имеет дочерний класс, который выглядит следующим

public class TestChildClass extends TestRootClass {} 

Я думаю, что следующий код Java будет недействительна из дженериков, используемых в TestInterface

public class TestImplementation extends TestChildAbstractClass { 

    public void test(TestChildClass top) { 
     System.out.println("tested"); 
    } 
} 

но Ява жалуется, что

абстрактный метод test(T), определенный в TestInterface, не реализован.

Разве это не работает ООП, который должен работать?

+0

если 'T' дефолт в' Object', то это было бы даже лучше для кода, который я отправил ... я бы определенно не вопрос. И в 'TestInterface', я фактически указываю, что действительный' T' - это 'T extends TestRootClass', который должен сузить область действия дальше от' Object' – reayn3

+0

. Я не вижу, как абстрактное решение TestImplementation решит проблему. Во всяком случае, это «задержит» проблему до первой конкретной реализации. – reayn3

+0

Я исправил свое первоначальное заявление и попытался быть более точным в своем ответе. – luk2302

ответ

3

Вам не хватает указать, что должно выглядеть T. Номер public abstract class TestRootAbstractClass implements TestInterface {}. Поэтому T по умолчанию TestRootClass, что означает, что TestImplementation не правильно реализовать интерфейс TestChildAbstractClass, потому что только позволяет TestChildClass параметров, но никаких других подклассы TestRootClass.

Вы должны либо указать его, либо дать этому классу child TestRootAbstractClass. Далее делает позже, компиляция просто отлично:

abstract class TestRootAbstractClass<T extends TestRootClass> implements TestInterface<T> {} 

abstract class TestChildAbstractClass<T extends TestRootClass> extends TestRootAbstractClass<T> {} 

interface TestInterface<T extends TestRootClass> { 
    void test(T extendedTestClass) throws Exception; 
} 

abstract class TestRootClass {} 

class TestChildClass extends TestRootClass {} 

class TestImplementation extends TestChildAbstractClass<TestChildClass> { 

    public void test(TestChildClass top) { 
     System.out.println("tested"); 
    } 
} 

или изменить метод в TestImplementation принимать все TestRootClass эс.

abstract class TestRootAbstractClass implements TestInterface {} 
abstract class TestChildAbstractClass extends TestRootAbstractClass{} 
interface TestInterface<T extends TestRootClass> { 
    void test(T extendedTestClass) throws Exception; 
} 
abstract class TestRootClass {} 
class TestChildClass extends TestRootClass {} 
class TestImplementation extends TestChildAbstractClass { 

    public void test(TestRootClass top) { 
     System.out.println("tested"); 
    } 
} 

Но теперь вы можете отбросить дженерики все вместе и просто использовать:

interface TestInterface { 
    void test(TestRootClass extendedTestClass) throws Exception; 
} 
+0

Спасибо @ luk2302 однако причина, по которой я использую 'public void test (TestChildClass top)', а не 'public void test (TestRootClass top)', состоит в том, что 'TestChildClass' имеет дополнительные методы, в которых у его родительского класса' TestRootClass' нет – reayn3

+0

@ reayn3 хорошо, тогда вы можете и должны использовать первый блок кода. Обратите внимание, что я не уверен на 100%, если вы захотите переместить ограничение на «TestChildClass» на уровень вверх. Вы можете использовать 'class TestImplementation extends TestChildAbstractClass' и' abstract class TestChildAbstractClass extends TestRootAbstractClass 'или что-то подобное. – luk2302

+0

Ответ принят. Что касается местоположения ограничения, для моего конкретного варианта использования, добавление этого в класс абстрактного класса TestChildAbstractClass extends TestRootAbstractClass лучше всего работает. Тем не менее, я все еще не могу поколебать чувство, что java ожидает здесь слишком много ... кажется, что, просто реализуя generics в интерфейсе TestInterface , можно устранить всю двусмысленность. Так или иначе ... – reayn3

0
public abstract class TestRootAbstractClass implements TestInterface {} 

Поскольку вы не указали параметр типа для TestInterface, метод в TestRootAbstractClass будет иметь следующую подпись :

public abstract void test(TestRootClass extendedTestClass) throws Exception; 

Поскольку этот метод не является чрезмерным он жалуется.

Похоже, вам нужно будет добавить параметры типа для всех соответствующих классов вверх по иерархии, чтобы они могли делать то, что вы пожелаете.

0

ваш интерфейс TestInterface является общим; с общим типом T расширяет TestRootClass. Когда вы делаете класс, реализуете их, у вас есть 3 варианта.

1) Lose типичность: Java будет решать по умолчанию как объект

public abstract class TestChildAbstractClass implements TestInterface {} 

2) Не типичность. поэтому ваш новый класс, который реализует интерфейс, должен быть généric.

public abstract class TestChildAbstractClass<P extends TestRootClass> implements TestInterface<P> {} 

3) Освободите гейнерский тип. так что ваш новый класс имеет родовой тип хорошо определен:

public abstract class TestChildAbstractClass implements TestInterface<TestChildClass> {} 
Смежные вопросы