Правила Java для приведения - PullRequest
       6

Правила Java для приведения

22 голосов
/ 10 февраля 2010

Когда определенный объект может быть превращен в другой объект?Должен ли приведенный объект быть подтипом другого объекта?Я пытаюсь выяснить правила ...

Редактировать : Я понял, что вообще не объяснил свою проблему: в основном я приводил объект к типу интерфейса.Однако во время выполнения я получаю java.lang.ClassCastException.Что должно произойти с моим объектом, чтобы я мог привести его к этому интерфейсу?Должен ли он это реализовать?

Спасибо

Ответы [ 6 ]

30 голосов
/ 10 февраля 2010

В Java существует два типа приведения ссылочной переменной:

  • Downcasting : если у вас есть ссылочная переменная, которая ссылается на объект подтипа, вы можете назначитьэто ссылочная переменная подтипа.Вы должны сделать явное приведение, чтобы сделать это, и в результате вы можете получить доступ к членам подтипа с помощью этой новой ссылочной переменной.

  • Upcasting : Вы можете назначитьссылочная переменная на ссылочную переменную супертипа явно или неявно.Это по сути безопасная операция, потому что назначение ограничивает возможности доступа новой переменной.

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

5 голосов
/ 23 декабря 2016

Предположим, мы хотим привести объект d к A,

A a = (C) d;

Итак, внутренне 3 правила были проверены компилятором и JVM. Компилятор проверяет первые 2 правила во время компиляции, а JVM проверяет последнее правило во время выполнения.

Правило 1 (проверка времени компиляции):

Тип 'd' и C должны иметь некоторое отношение (дочерний к родительскому или родительскому. к ребенку или в то же время). Если нет никаких отношений, то мы получим ошибка компиляции (необратимые типы).

Правило 2 (проверка времени компиляции):

«C» должен быть того же типа или производного типа (подкласса) «A» в противном случае мы получим ошибку компиляции (несовместимые типы).

Правило 3 (исключение времени выполнения):

Тип объекта времени выполнения 'd' должен быть таким же или быть производным от типа 'C' в противном случае мы получим исключение времени выполнения (ClassCastException Исключение).

Найдите следующие примеры, чтобы получить больше идей,

String s = new String("hello"); StringBuffer sb = (StringBuffer)s;  // Compile error : Invertible types because there is no relationship between.

Object o = new String("hello"); StringBuffer sb = (String)o;       // Compile error : Incompatible types because String is not child class of StringBuffer.

Object o = new String("hello"); StringBuffer sb = (StringBuffer)o; // Runtime Exception : ClassCastException because 'o' is string type and trying to cast into StingBuffer and there is no relationship between String and StringBuffer.
3 голосов
/ 10 февраля 2010

Это будет работать:

class Foo implements Runnable {
    public void run() {}
}

Foo foo = new Foo();
System.out.println((Runnable) foo);

Но это не будет:

class Bar {
    public void run() {}
}

Bar bar = new Bar();
System.out.println((Runnable) bar);

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

Java требует, чтобы вы объявляли реализованные интерфейсы name . У него нет утки, набираемой , в отличие от некоторых других языков, таких как Python и Go

2 голосов
/ 10 февраля 2010

Существует интуитивный способ думать об этом - вы не изменяете объект при помощи приведения, вы делаете только то, что уже было бы разрешено, если бы тип был известен - другими словами, вы можете приводить только к типу, который ваш объект уже есть. Так что просто посмотрите «вверх» цепочку объектов, чтобы увидеть, какие виды применимы к вашему объекту.

Таким образом, вы можете привести к интерфейсу только , если он определен где-то выше в цепочке (например, если ваш родительский класс реализует его и т. Д. И т. Д.). Это должно быть явно - из вашего вопроса это звучит так, как будто вы думаете, что если вы реализуете метод "void foo ()", то вы сможете привести к интерфейсу, который определяет метод "void foo ()" - это иногда описывается как «типизирование утки» (если он крякает как утка, это утка), но это не то, как работает Java.

1 голос
/ 10 февраля 2010

Если:

interface MyInterface{}

class MyClass implements MyInterface{}

Тогда

MyClass m = new MyClass();
MyInterface i = (MyInterface)m;

возможно.

1 голос
/ 10 февраля 2010

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

EDIT:

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

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