2012-08-08 6 views
1

Рассмотрим приведенный ниже пример.Использование интерфейса в качестве типа параметра в java

Почему это так, что я не разрешено использовать BImpl в качестве типа параметра метода doSomething3? Когда я говорю «не разрешено», я имею в виду, что Eclipse жалуется, что doSomething3-метод из интерфейса AInf не реализован.

interface AInf 
{ 
    AInf doSomething(); 
    BInf doSomething2(); 
    void doSomething3(BInf param); 
} 


interface BInf 
{ 

} 

class AImpl implements AInf 
{ 

    @Override 
    public AImpl doSomething() { 
     // TODO Auto-generated method stub 
     return null; 
    } 

    @Override 
    public BImpl doSomething2() { 
     // TODO Auto-generated method stub 
     return null; 
    } 

    @Override 
    public void doSomething3(BImpl param) // This method is not overriding the doSomething3(BInf param) from the AInf 
    { 
     // TODO Auto-generated method stub 
    } 
} 

class BImpl implements BInf 
{ 

} 

ответ

3

Поскольку doSomething3(BImpl param) не реализует doSomething3(BInf param).

BInf может иметь множество реализаций, и метод должен работать для всех из них, а не только для одного.

Всегда помните, что расширение класса или реализация интерфейса определяет связь is a. Логичным следствием этого являются все правила расширения/сужения.

Это проще, если вы представляете его с конкретным примером: деньги. Монеты - деньги, а деньги - тоже деньги.

Если вы идете в магазин, который решил ограничить изменение, которое они дают вам от покупки на монетах, это может раздражать, но это законно. Это нормально, потому что это не нарушает контракт, они всегда возвращают деньги.

Но когда вы находитесь в магазине, где они должны принимать деньги, и они не будут принимать ваши монеты, это не нормально.

+0

Хорошо, я вижу вашу мысль. Итак, какие у меня варианты и какова наилучшая практика сужения принятых типов в качестве типов параметров в классе реализации AImpl для метода doSomething3()? Создание отдельного интерфейса только для AImpl? –

+0

@IsmarSlomic Почему вы хотите сузить его? – biziclop

+1

Если вам нужно это сделать, вам, вероятно, понадобится общий интерфейс. –

0

объявленное как:

void doSomething3(BInf param); 

но вы пытаетесь реализовать с помощью различного типа:

public void doSomething3(BImpl param) 

Binf и BImpl

+1

Но BImpl реализует BInf, справа. И это работает как возвращаемый тип doSomething2(), но не как тип параметра. Зачем? –

0

Проблема заключается в том, что doSomething3 принимает Bimpl в качестве параметра, но интерфейс говорит, что параметр BInf (BImpl не BInf). А поскольку есть аннотация @Override, вы сообщаете компилятору, что вы переопределяете метод из интерфейса, который явно не является и, следовательно, является ошибкой.

3

Вы должны иметь тот же тип, что и интерфейс.

интерфейс говорит, что будет принимать

void doSomething3(BInf param); 

Это означает, что будет принимать BInf и любой подтип (потому что они могут быть как ожидается, вести себя так же - см. В Liskov Substitution Princple

Ваше осуществление Безразлично «т соблюдать этот договор

public void doSomething3(BImpl param) 

Эта реализация говорит, что я буду работать только для BImpl, но ничего не говорит о BInf.

(редактирование в ответ на вопрос от @IsmerSlomic)

Для типов возврата, Java позволяет covariant return types.Это не нарушает LSP, потому что возвращает что-то, что гарантирует как минимум тип возврата в интерфейсе. Если тип возврата более специализирован, то LSP будет по-прежнему делать то же самое, что возвращать исходный интерфейс.

+2

Я вижу вашу точку зрения, но как этот принцип отличается, когда вы используете то же самое для типа возврата, см. DoSomething2() –

+0

@IsmarSlomic: для возвращаемых типов интерфейс AInf хочет что-либо, что соответствует контракту BInf, поэтому работает BImpl. Никогда не забывайте: PECS (Produces = Extends, Consumes = Super). В качестве параметра вы должны принять более высокий уровень, указанный интерфейсом, чтобы ответить на любой возможный вызов метода, но в качестве возвращаемого типа вы можете вернуть все, что расширяет интерфейс (так как вашему потребителю понадобится хотя бы контракт на интерфейс) , –

0

Вы можете вернуть AImpl и BImpl, потому что они являются ковариантными типами возврата (или просто put, все объекты AImpl являются объектами AInf, а все объекты BImpl являются объектами BInf, поэтому вызывающий абонент знает, что он возвращает объект AInf или BInf, объявленный в интерфейсе).

Это не работает для параметров метода, хотя из-за того, что вы не можете управлять передачей метода doSomething3(), нет никакой гарантии, что аргумент BInf на самом деле является BImpl.

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