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

Различные методы приведения объекта в Java

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

Object o = "str";

String str1 = (String) o;                // Method 1

String str2 = o.toString();              // Method 2

String str3 = String.class.cast(o);      // Method 3
  • Какой подход лучше, и каковы преимущества/недостатки одного метода по сравнению с другими?
  • Что происходит с объектом во время литья внутри?
4b9b3361

Ответ 1

Второй метод, который вы показываете, не выполняется; он просто вызывает метод toString() для объекта, который не отличается от любого другого вызова метода:

String str2 = o.toString();

Эффект первого и третьего методов по существу тот же. Я бы предпочел использовать первый метод.

Что произошло с объектом во время кастинга внутри?

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

В вашем примере тип переменной o равен Object. Когда вы назначаете o переменной типа String, компилятор не разрешит ее, потому что она проверяет типы, и не может быть уверенной, что o на самом деле относится к объекту String. Поэтому вы используете приведение, чтобы сообщить компилятору "Я знаю, что это объект String, поэтому позвольте мне выполнить это назначение".

Тип будет по-прежнему проверяться, но во время выполнения, а не во время компиляции. Если во время выполнения тип объекта не является String, вы получите ClassCastException.

Ответ 2

Первый из них ссылается на ссылку o, объявленным типом которой является объект Object, а фактический конкретный тип - String, для строки. Это канонический способ кастинга. Это будет работать, только если объект, на который ссылается o, имеет тип String. Если это не так, вы получите исключение ClassCastException.

Второй не бросается вообще. Он вызывает toString() объекта, на который ссылается o. Это всегда будет работать, но это действительно сильно отличается от актерского состава.

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

Class<?> someClassToCastTo = ...; // could be String.class or anything else, you don't know)

String str3 = someClassToCastTo.cast(o);

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

Ответ 3

Вот он:

Object o = "str";

String str1 = (String) o;

Это работает только тогда, когда объект фактически является строкой.

String str2 = o.toString();

Когда вы используете toString() для объекта String, вы получаете строку. Он выдает исключение, когда объект o имеет значение null.

String str3 = String.class.cast(o);

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

Ответ 4

Java - это строго типизированный язык, и он позволяет только бросать объект в один из его родительских классов или интерфейсов. То есть, если у вас есть следующее:

class A {}

interface I {}

class B extends A implements I {}

class C {}

Вы можете сделать объект типа B следующим:

B b = new B();
A a = b; // no need for explicit casting
I i = b;
Object o = b; // Object is implicit parent of A
C c = b; // ERROR C isn't a parent class of b

Это называется повышением. Вы также можете отключить:

A a = new B();
B b = (B) b;

вам нужно использовать явный приведение здесь, и JVM будет проверять время выполнения, если бросок действительно разрешен.

Кастинг String.class.cast(o) полезен, когда вы не знаете, какой тип вы вставляете во время компиляции.

.toString() не выполняется. Это просто метод, который должен возвращать строковое представление вашего объекта. Но представление - это не объект, а просто представление. Этот метод определен в классе Object, поэтому он присутствует во всех классах и немного испечен на языке. То есть, если вы пишете

String s = "Hell " + o;

JVM вызовет метод o.toString() для получения его представления.

Ответ 5

Вы можете сами это рассуждать.

$ cat Cast.java 
public class Cast {
    private Cast() {}
    public static void main(String[] args) {
        Object o = "str";
        String str1 = (String) o;                // Method 1
        String str2 = o.toString();              // Method 2
        String str3 = String.class.cast(o);      // Method 3
    }
}
$ javac Cast.java 
$ javap -c Cast
Compiled from "Cast.java"
public class Cast {
  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String str
       2: astore_1
       3: aload_1
       4: checkcast     #3                  // class java/lang/String
       7: astore_2
       8: aload_1
       9: invokevirtual #4                  // Method java/lang/Object.toString:()Ljava/lang/String;
      12: astore_3
      13: ldc           #3                  // class java/lang/String
      15: aload_1
      16: invokevirtual #5                  // Method java/lang/Class.cast:(Ljava/lang/Object;)Ljava/lang/Object;
      19: checkcast     #3                  // class java/lang/String
      22: astore        4
      24: return
}

Как вы можете видеть,

  • Метод 1 - это просто код операции checkcast.
  • Метод 2 - это код операции invokevirtual.
  • Метод 3 - это ldc (класс нагрузки), за которым следуют invokevirtual и checkcast.

Очевидно, что метод 3 уступает в плане многословия, удобочитаемости и производительности.

Из 1 и 2, что лучше?

checkcast означает "посмотреть на этот объект: действительно ли это String?" - если да, приступайте к назначению; если нет, введите a ClassCastException.

invokevirtual означает "искать, какой метод toString() вызывать на основе класса o" - в этом случае он String.toString(). Очевидная реализация этого метода -

public String toString() {
    return this;
}

Учитывая выбор между запросом "Является ли это String?" и "Что это за тип? какой метод мы называем результатом? Пусть выполняется String.toString() on с str2 как подразумеваемый параметр." - Метод 1 должен быть немного проще.