Подтвердить что ты не робот

Зачем бросать после instanceOf?

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

if (p1 instanceof Square) {c1 = (Square) p1;}

Я не понимаю здесь, что мы сначала проверяем, что p1 действительно является Square, а затем мы все равно его используем. Если это a Square, зачем использовать?

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

Edit:
Как компилятор справится с:

if (p1 instanceof Square) {c1 = p1;}

Edit2:
Является ли проблема, что instanceof проверяет фактический тип, а не кажущийся тип? А потом, что литье меняет видимый тип?

Спасибо,

JDelage

4b9b3361

Ответ 1

Имейте в виду, вы всегда можете назначить экземпляр Square для типа, расположенного выше цепочки наследования. Затем вы можете захотеть присвоить менее конкретный тип более конкретному типу, и в этом случае вам нужно быть уверенным, что ваш актер действителен:

Object p1 = new Square();
Square c1;

if(p1 instanceof Square)
    c1 = (Square) p1;

Ответ 2

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

if (p1 instanceof Square) {
    // if we are in here, we (programmer) know it an instance of Square
    // Here, we explicitly tell the compiler that p1 is a Square
    c1 = (Square) p1;
}

В С# вы можете выполнить проверку и трансляцию в 1 вызов:

c1 = p1 as Square;

Это приведет к p1 к квадрату, и если сбой приведения, c1 будет установлен на null.

Ответ 3

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

Ответ 5

Старый код не работает корректно

Функция принудительного литья оправдана после всех, но у нас есть проблемы с реализацией этого FR для java из-за обратной совместимости.

Смотрите это:

public class A {
    public static void draw(Square s){...} // with impield cast
    public static void draw(Object o){...} // without impield cast
    public static void main(String[] args) {
        final Object foo = new Square();
        if (foo instanceof Square) {
            draw(foo);
        }
    }
}

Текущий JDK будет компилировать использование второго объявленного метода. Если мы реализуем это FR в java, он будет скомпилирован для использования первого метода!

Ответ 6

например. Если вы передадите p1 по типу Object, компилятор не будет знать, что он фактически является экземпляром Square, поэтому методы и т.д. Не будут доступны. Если просто проверяет, чтобы определенный тип возвращал true/false, но это не меняет тип переменной p1.

Ответ 7

Переменная p1 имеет тип, с которой он начинался - пусть говорят Shape. p1 - ​​это форма и только форма, независимо от того, что ее текущее содержимое оказывается квадратом. Вы можете позвонить - пусть говорят - side() на квадрате, но не на фигуре. Пока вы идентифицируете объект, о котором идет речь, с помощью переменной p1, тип которой Shape, вы не можете вызвать на нем функцию side() из-за типа переменной. Как работает система типа Java, если вы можете вызвать p1.side(), когда вам известно это Квадрат, вы всегда можете вызвать p1.side(). Но p1 может содержать не только квадратные фигуры, но также (скажем) Circle Shapes, и было бы ошибкой вызвать p1.side(), когда p1 удерживал круг. Таким образом, вам нужна другая переменная для представления формы, которую вы знаете, - это квадрат, переменная, тип которой - квадрат. Вот почему бросок необходим.

Ответ 8

Если c1 объявлен как тип Square, тогда требуется литье. Если это объявлено как Object, то литье не требуется.

Ответ 9

Тест выполняется для предотвращения ClassCastExceptions во время выполнения:

Square c1 = null;
if (p1 instanceof Square) {
   c1 = (Square) p1;
} else {
   // we have a p1 that is not a subclass of Square
}

Если вы абсолютно уверены, что p1 является Square, вам не нужно тестировать. Но оставьте это частным методам...

Ответ 10

Не быть неприятным, но вы должны сказать компилятору, что вы хотите сделать, потому что альтернативой было бы угадать, что вы пытаетесь сделать. Конечно, вы можете подумать: "Если я проверю тип объекта, ОБЯЗАТЕЛЬНО, это должно означать, что я хочу передать его этому типу". Но кто говорит? Возможно, это то, что вы делаете, и, возможно, это не так.

Конечно, в простом случае, таком как

if (x instanceof Integer)
{
  Integer ix=(Integer) x;
  ...

Мое намерение довольно очевидно. Или это? Возможно, я действительно хочу:

if (x instanceof Integer || x instanceof Double)
{
  Number n=(Number) x;
... work with n ...

Или что, если я писал:

if (x instanceof Integer || x instanceof String)

Что бы вы ожидали от компилятора? Какой тип он должен принимать для x?

RE комментарии, что instanceof устарел или в противном случае плохая идея: он, безусловно, может быть неправильно использован. Недавно я работал над программой, в которой первоначальный автор создал шесть классов, все из которых оказались страницами и страницами, но идентичными друг другу, и единственная видимая причина их наличия заключалась в том, что он мог сказать "x instanceof classA" по сравнению с "x instanceof classB" и т.д. То есть он использовал класс как флаг типа. Было бы лучше иметь только один класс и добавить перечисление для различных типов. Но есть и много очень хороших применений. Возможно, наиболее очевидным является что-то вроде:

public MyClass
{
  int foo;
  String bar;
  public boolean equals(Object othat)
  {
    if (!(othat instanceof MyClass))
      return false;
    MyClass that=(MyClass) othat;
    return this.foo==that.foo && this.bar.equals(that.bar); 
  }
  ... etc ...
}

Как бы вы это сделали, не используя instanceof? Вы можете сделать параметр типа MyClass вместо Object. Но тогда нельзя даже назвать его универсальным объектом, который во многих случаях может быть очень желанным. В самом деле, может быть, я хочу, чтобы коллекция включала, скажем, и строки, и целые числа, и я хочу, чтобы сравнения разных типов просто возвращали false.