2015-06-05 2 views
0
class Animal{ 
    public void findAnimal(){ 
    System.out.println("Animal class"); 
    } 
    public void sayBye(){ 
    System.out.println("Good bye"); 
    } 
} 

class Dog extends Animal{ 
public void findAnimal(){ 
    System.out.println("Dog class"); 
} 
} 

Учитывая вышеизложенное наследования, следует понимать, что ссылка на животных может относиться к объекту DogПочему downcasting разрешено в java?

Animal animal=new Dog(); 

В качестве объекта Собака может выполнять все животное может сделать, как и в описанном выше случае собака также скажем, и найти методы поиска.

Но почему это разрешено опускать объект Animal на объект Dog, который не имеет никакой цели и не работает во время выполнения.

Dog dog=(Dog)new Animal(); // fails at runtime but complies. 

Dog dog=(Dog)animal; 

Вышеуказанное утверждение выглядит логичным, поскольку ссылка на животных указывает на объект Собаки.

+3

Вы утверждаете, что 'собака собаки = (Animal) новый Animal();' компилируется? – Kayaman

+3

Это синтаксически и семантически корректно: точно так же, как x = 1/0 – cup

+0

@ Кайаман: мой плохой должен быть Собака собака = (Собака) new Animal(); – Pankaj

ответ

1

Вам нужна эта возможность для доступа к более раннему литому объекту в качестве его исходного типа.

Например, если вы передаете собаку животному, чтобы передать ее на общий процессор, позднее вам может понадобиться вернуть ее Собаке для выполнения определенных методов.

Разработчик несет ответственность за то, чтобы убедиться, что тип совместим - и когда он не будет ошибки. Некоторые псевдо-код:

public void example(Animal foo){ 
    if(...condition...) ((Dog)foo).bark(); 
    else if(...other condition...) ((Cat)foo).meow(); 
} 

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

3

Потому что вам это нужно иногда.

Особенно, когда у Java еще не было дженериков (Java 1.4 и старше), вам почти всегда нужно было отбрасывать, когда вы получили, например, объект из коллекции.

// No generics, you don't know what kinds of objects are in this list 
List list = new ArrayList(); 

list.add(new Dog()); 

// Need to cast because the return type of list.get() is Object 
Dog dog = (Dog)list.get(0); 

Поскольку у нас есть дженерики с Java 5, потребность в литье значительно уменьшается.

Вы должны стараться избегать литья в вашем коде как можно больше. Бросок - это способ сознательно отключить проверку типа компилятора - в общем, вы не хотите этого делать, вы хотите использовать проверку компилятора вместо обхода. Итак, если у вас есть код, где вам нужно бросить, подумайте немного дальше, чтобы увидеть, можете ли вы написать его без актерского состава.

+0

Спасибо Jesper. Здесь объект в ArrayList имеет тип Dog. Поэтому имеет смысл отбросить их на Dog from Object. Мой поиск - это то, почему разрешено использование Dog dog = (Dog) new Animal(). – Pankaj

+0

@Pankaj Точные правила для того, что есть и что не разрешено, описаны в [разделе 5.5.1 JLS] (https://docs.oracle.com/javase/specs/jls/se8/html/jls-5 .html # ПСБ-5.5.1). Если типы не связаны друг с другом, компилятор выдаст вам ошибку. Но если типы связаны (например, потому что 'Animal' - это супертип' Dog'), компилятор разрешит создание. – Jesper

4

Этот вид литья разрешен для ситуаций, когда вы получаете объект суперкласса из внешнего кода, например. как параметр для вашего метода, а затем вам нужно вызвать методы, специфичные для подкласса.

Это не очень хорошая практика, но в некоторых редких случаях, вы вынуждены делать что-то подобное, так что язык позволяет ему:

void sound(Animal animal) { 
    if (animal instanceof Dog) { 
     Dog dog = (Dog)animal(); 
     dog.bark(); 
    } 
    if (animal instanceof Cat) { 
     Cat cat = (Cat)animal(); 
     cat.meow(); 
    } 
} 

почему допускается компилировать Dog dog=(Dog) new Animal()

Потому что разработчики компилятора решили не обнаруживать эту ошибку во время компиляции. Они подтвердили, что выражение, отлитое от Dog, имеет тип, который является суперклассом Dog и позволяет компилировать выражение.Они могут пойти дальше и проверить, что выражение всегда приведет к исключению, но для этого потребуется дополнительное усилие для очень небольшого улучшения в работе с языком.

+0

Я согласен с этим, если ссылка «животное» указывает на объект «Собака», он должен быть отброшен на собаку. Но почему это разрешено компилировать Dog dog = (Dog) new Animal(). Кроме того, он не работает во время выполнения, даже если мы не используем эталонную собаку. – Pankaj

+0

@Neeraj указал на JLS, который объясняет, почему данный бросок разрешен во время компиляции. После этого это чистое догадки. Если только кто-то не является фактическим разработчиком и разработчиком функциональности кастингов, нет никакого способа утверждать, что было сознательное решение не выполнять указанные функции. Самое лучшее, что мы можем догадаться, это то, что компилятор с удовольствием рассмотрит типы с двух сторон оператора литья и применил спецификацию языка к двум обнаруженным типам. Почему компилятор не пытается усложнить обнаружение явных нарушений, может быть вызвано любым количеством причин. – manish

0

case 1 -

Здесь мы используем свободную муфту.

животных животное = getSomeDog(),

Собака собака = (собака) животных; // это разрешено, потому что животное может ссылаться на собаку

корпус 2

Здесь используется герметичное соединение.

Животное animal = new Animal();

Собака собака = (Собака) животное; // это произойдет сбой во время выполнения, так как животное не ссылается на собаке

Мы используем понижающее приведение, когда есть возможность добиться успеха во время выполнения так случай 1 имеет возможность для достижения успеха во время выполнения над случае 2

0

вниз кастинг считается плохой объектно-ориентированной практикой. Этого следует избегать как можно дольше.

У Java все еще есть это, и ваш вопрос является хорошим вопросом, почему Java допускает Down-casting.

Предположим, что дело ниже.

public interface List{ 
    public boolean add(Object e); 
    public boolean remove(Object o); 
} 

public class ArrayList implements List{ 

    // Extra method present in the ArrayList and not in the parent Interface 
    public Object[] toArray() { 
     // returns array of the objects 
     return Arrays.copyOf(elementData, size); 
    } 

    @Override 
    public boolean add(Object e){ 
     // add e to the ArrayList Underlying array 
    } 
    @Override 
    public boolean remove(Object o){ 
     // remove o from the ArrayList Underlying array 
    } 
} 

Хорошая объектно-ориентированная практика - Code for Interfaces. Но часто есть методы, определенные в конкретных реализациях, которые нам нужно вызвать. Я прочитал комментарий от кого-то, и я цитирую его в своих словах.

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

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

public void processList(List items){ 
    items.add(new Object()); 
    items.add(new Object()); 
    processAsPerTypeOfList(items); 
} 

public void processAsPerTypeOfList(List items){ 
    if(items instanceof ArrayList){ 
     Object[] itemArray = ((ArrayList)items).toArray();// DOWNCASTING 
     // Process itemArray 
    } 
} 

Для получения дополнительной справки вы можете также увидеть связанный с этим вопрос: Why Java needs explicit downcasting?

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