Вопрос интерфейса Java относительно полиморфизма - PullRequest
0 голосов
/ 22 марта 2011

Итак, у меня есть это:

interface C {
    void shutUp();
}

class A {
    public void speak() {
       System.out.println("Class a");
    }
}

class B extends A implements C {
    public void shutUp() {
        System.out.println("Saying nothing...");
    }

    public void speak() {
        System.out.println("Class B");
    }
}

Если я это сделаю, это сработает:

A obj = new B();
obj.speak()

Но я не могу сделать obj.shutUp() Почему бы и нет? У меня такое чувство, что я просто запутался в чем-то очень простом.

Спасибо!

Ответы [ 11 ]

2 голосов
/ 22 марта 2011

Статический тип A не связан с C, поэтому вы не можете выполнить эту команду, это было бы так же, как:

A obj = new A();
obj.shutUp();

(что явно незаконно ..)
единственный, кто может использовать оба - B

B obj = new B();
obj.shutUp();
obj.speak();

все это связано с тем, что Java static typing

1 голос
/ 22 марта 2011

Поскольку A не является C - он не реализует интерфейс - и вы не можете создать экземпляр интерфейса таким образом, потому что нет конструктора по умолчанию.

Ссылка типа A не имеет метода shutUp(), поэтому неудивительно, что он не работает.

И ваш код использует неверные ключевые слова: это class иinterface для Java.Дело имеет значение.

0 голосов
/ 16 января 2013

Говоря A obj = новый B ();Вы отделяете свой код от конкретной реализации интерфейса.Поэтому у obj не будет доступа к функции shutup (), которая была реализована в классе b.

0 голосов
/ 22 марта 2011

Объект, созданный new B(), может использоваться как объект любого из трех типов - A, B или C. Но вы не можете объявить переменную нескольких типов.

Поскольку B является подтипом A и C, вы можете использовать его экземпляр в качестве экземпляра любого из этих типов. Э.Г.

B o = new B();
A aO = o;
C cO = o;

Теперь вы можете использовать o для доступа к методам speak и shutUp, вы можете использовать aO для доступа к методу speak и cO для доступа к методу shutUp. Неважно, какую переменную вы будете использовать, вызываемые методы будут одинаковыми, поскольку все эти переменные ссылаются на один и тот же объект. Почему вы не можете использовать aO для вызова shutUp в Java, потому что вы объявили переменную с типом, у которого нет такого метода. Хотя вы знаете, что этот конкретный объект имеет этот метод, он вообще не делает его таким.

class D extends A {
    public void speak(){
        System.out.println("Class D");
    }
}

List<A> as = new ArrayList<A>();
as.add(new A());
as.add(new B());
as.add(new D());

A a0 = as.get(0);
A a1 = as.get(1);
A a2 = as.get(2);

a0.speak(); // >> Class A
a1.speak(); // >> Class B
a2.speak(); // >> Class D 

Теперь в этом примере у вас есть экземпляры трех разных классов в одной коллекции. Когда вы передаете эту коллекцию или изменяете ее, вы никогда не узнаете, к какому классу относится каждый объект. Все, что вы знаете, это то, что все они относятся к типу A, они гарантированно принадлежат к этому типу, хотя на самом деле они могут быть любого подтипа A (например, B или D).

0 голосов
/ 22 марта 2011
A obj = new B();

Здесь вы создаете экземпляр типа «B» типа «A». то есть вы говорите: «Я хочу создать объект B и назвать его obj типа A».

В классе A доступен только один метод. Он не реализовал C

public void speak() {}

Чтобы иметь доступ ко всем методам класса B, вы должны создать экземпляр типа «B» типа «B»

B obj2 = new B();

Таким образом, вы сможете получить доступ к

 public void shutUp() {}

Это потому, что именно B реализует класс "C".

Один из способов получить доступ к обоим методам с использованием "obj" - заставить A реализовать C

0 голосов
/ 22 марта 2011

Другие люди уже ответили на это, но учтите, что есть способ позвонить на shutUp() без приведения к B или C:

A obj = new B();
try {
    Method shutUp = obj.getClass().getMethod("shutUp", null);
    shutUp.invoke(obj, null);
}
catch (Exception ignored) {}
0 голосов
/ 22 марта 2011

причина, по которой вы не можете вызвать shutUp для obj, заключается в следующем:

obj - это не объект, это указатель или ссылка. объект, который вы создаете, когда создаете новый B () - это одно, а obj (или «как вы используете объект») - это отдельная вещь. вы используете объект с помощью ссылки (в данном случае obj), которая позволяет получить доступ к различным сторонам реального объекта.

если ссылка, которую вы используете для доступа к объекту, относится к типу, который ссылается на данный объект (то есть имеет то же имя), тогда вы можете получить доступ ко всему объекту через эту ссылку. в противном случае вы можете получить доступ только к тем частям объекта, которые может видеть ссылочный тип.

в вашем примере тип ссылки - A, то есть obj видит только часть A любого объекта, на который он ссылается. поэтому он не может получить доступ к части B / C объекта, событие, хотя объект имеет эти поведения.

0 голосов
/ 22 марта 2011

A obj = новый C ();

поскольку C является интерфейсом, вы не можете создать экземпляр интерфейса. Пожалуйста, исправьте вопрос.

0 голосов
/ 22 марта 2011

В вашем вопросе ошибка: вы не можете создать объект C, потому что это интерфейс - поэтому я думаю, что вы хотите создать объект B, тогда:

Это потому, что obj это A, а не C, чтобы использовать метод shutUpВы можете:

((C) obj).shutUp() // cast to C type
((B) obj).shutUp() // cast to B type

Или объявить:

B obj = new B();
obj.shutUp();

Или:

C obj = new B(); // (!) but: you can't (without casting) call speak method
obj.shutUp();
0 голосов
/ 22 марта 2011

Тип obj определяется как A;следовательно, obj может использовать только те элементы, которые доступны для A.Поскольку C наследуется от A, в C есть все члены, которые должны рассматриваться как форма A, поэтому он позволяет вам создать новый C в переменной A.Только приведя его к типу C, вы можете использовать всех членов, принадлежащих к C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...