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

Почему я должен использовать java.lang.Class.cast

Возможный дубликат:
Когда следует использовать метод java 5 для класса Class?

Недавно я наткнулся на фрагмент кода, который был следующим:

Object o = .. ;
Foo foo = Foo.class.cast(o);

Я даже не знал, что у java.lang.Class был метод cast, поэтому я просмотрел документы, и из того, что я собираю, это просто делает приведение к классу, который представляет объект класса. Таким образом, приведенный выше код будет примерно эквивалентен

Object o = ..;
Foo foo = (Foo)o;

Итак, я задавался вопросом, почему я хотел бы использовать метод cast вместо того, чтобы просто делать "старый способ". У кого-нибудь хороший пример того, как использование метода литья выгодно для простого приведения?

4b9b3361

Ответ 1

От Java Class.cast() против оператора трансляции

Я только когда-либо использовал Class.cast(Object), чтобы избежать предупреждений в "generics land". Я часто вижу методы, которые делают такие вещи:

@SuppressWarnings("unchecked")
<T> T doSomething() {
Object o;
// snip
return (T) o;
}  

Лучше всего заменить его на

<T> T doSomething(Class<T> cls) {
Object o;
// snip
return cls.cast(o);
}  

Это единственная утилита для Class.cast(Object), с которой я когда-либо сталкивался.

Ответ 2

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

public static <T extends Number> T castToNumber(Object o) {
    return (T)o;
}

На самом деле это не делает ничего полезного из-за стирания стилей.

В то время как это работает и безопасно по типу (по модулю ClassCastExceptions):

public static <T extends Number> T castToNumber(Object o, Class<T> clazz) {
    return clazz.cast(o);
}

EDIT. Пара примеров использования google guava:

Ответ 3

В Java часто бывает более одного способа скинуть кошку. Такая функциональность может быть полезна в тех случаях, когда у вас есть код структуры. Представьте метод, который принимает экземпляр объекта класса и экземпляр объекта и возвращает объект Object как класс:

public static void doSomething(Class<? extends SomeBaseClass> whatToCastAs,Object o)
    {
        SomeBaseClass castObj =  whatToCastAs.cast(o);
        castObj.doSomething();
    }

В общем, используйте более простое кастинг, если это не достаточно.

Ответ 4

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

Ответ 5

Нет абсолютно никакой причины писать Foo.class.cast(o), это эквивалентно (Foo)o.

В общем случае, если X является возвращаемым типом, а Class<X> clazz, то clazz.cast(o) совпадает с (X)o.

Если все типы являются повторно идентифицируемыми, метод Class.cast() является поэтому избыточным и бесполезным.

К сожалению, из-за стирания в текущей версии Java не все типы можно повторно использовать. Например, переменные типа не сохраняются.

Если T - это переменная типа, cast (T)o не проверяется, потому что во время выполнения точный тип T неизвестен JVM, JVM не может проверить, действительно ли o type T. Бросок может быть допущен ошибочно, что может вызвать проблемы позже.

Это не огромная проблема; обычно, когда программист делает (T)o, он уже аргументировал, что бросок безопасен и не вызовет никаких проблем во время выполнения. Листинг проверяется логикой приложения.

Предположим, что a Class<T> clazz доступно в точке броска, тогда мы знаем, что T во время выполнения; мы можем добавить дополнительную проверку времени выполнения, чтобы убедиться, что o действительно является T.

check clazz.isInstance(o);
(T)o;

И это по существу то, что делает Class.cast().

Мы никогда не ожидали, что приведение в случае неудачи произойдет в любом случае, поэтому в правильно реализованном приложении проверка clazz.isInstance(o) всегда должна преуспеть, поэтому clazz.cast(o) эквивалентно (T)o - еще раз, в предположении, что правильный код.

Если можно доказать, что код верен, а литье безопасно, можно предпочесть (T)o - clazz.cast(o) для повышения производительности. В примере MutableClassToInstanceMap, поднятом в другом ответе, мы можем видеть, очевидно, что бросок безопасен, поэтому простого (T)o было бы достаточно.

Ответ 6

class.cast предназначен для типа дженериков.

Когда вы создаете класс с общим параметром T, вы можете передать Класс. Затем вы можете сделать актерский состав как статическим, так и динамическим проверка (T) не дает вам. Он также не производит непроверенный предупреждений, потому что он проверен (в этой точке).

Ответ 7

Общим примером является то, что вы извлекаете из постоянного слоя коллекцию объектов, на которую ссылается объект класса, и некоторые условия. Возвращенная коллекция может содержать непроверенные объекты, поэтому, если вы просто нажмете ее как заостренную G_H, вы бросите исключение Cast в этот момент, а не когда к ним будут доступны значения.

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

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

Ответ 8

Потому что у вас может быть что-то такое:

Number fooMethod(Class<? extends Number> clazz) {
    return clazz.cast(var);
}

Ответ 9

A "cast" в Java, например. (Number)var, где предмет в круглых скобках является ссылочным типом, действительно состоит из двух частей:

  • Время компиляции: результат выражения cast имеет тип типа, который вы использовали для
  • Время выполнения: оно вставляет операцию проверки, которая в основном говорит, если объект не является экземпляром этого класса, а затем бросает ClassCast Exception (если вещь, которую вы выполняете, является переменной типа, тогда класс он проверяет, будет ли нижняя граница переменной типа)

Чтобы использовать синтаксис, вам нужно знать класс во время написания кода. Предположим, вы не знаете во время компиляции, на какой класс вы хотите бросить; вы знаете это только во время выполнения.

Теперь вы спросите, тогда в чем смысл кастинга? Разве точка литья не должна превращать выражение в желаемый тип во время компиляции? Итак, если вы не знаете тип во время компиляции, тогда во время компиляции нет никакой пользы, правильно? Правда, но это только первый пункт выше. Вы забываете компонент времени выполнения (второй элемент выше): он проверяет объект на класс.

Следовательно, цель выполнения времени выполнения (т.е. Class.cast()) заключается в проверке того, что объект является экземпляром класса, а если нет, генерирует исключение. Это примерно эквивалентно этому, но короче:

if (!clazz.isInstance(var))
    throw new ClassCastException();

Некоторые люди упомянули, что Class.cast() также имеет хороший тип возвращаемого значения, который основан на параметре типа переданного класса, но это всего лишь функция времени компиляции, которая предоставляется в любом случае при компиляции. Поэтому для этой цели нет смысла использовать Class.cast().