Приведение к неизвестному типу, когда только задано имя класса в виде строки этого типа - PullRequest
8 голосов
/ 26 января 2009

В настоящее время у меня есть список объектов (с использованием Java 1.3), и, скажем, я хотел привести один из объектов, возвращенных из list.get (i), к типу, для которого я знаю только имя класса как строка. По сути, как мне Объект o = (имя класса) list.get (i); где className - строковая переменная className.

Я думал, что смогу использовать (Class.forName (className)) list.get (i), но получил синтаксическую ошибку, утверждая, что я забыл точку с запятой.

К сожалению, поскольку я использую Java 1.3, у меня нет доступа к методу Class.cast (Object).

Какое имя класса используется при приведении к другому типу в Java 1.3? Есть ли какой-нибудь метод, который может дать мне правильный тип, который мне нужен, с параметром String имени класса?

Ответы [ 5 ]

10 голосов
/ 26 января 2009

в чем смысл приведения, когда все, что вы делаете, назначаете результат объекту? Все, чего вы добьетесь - это исключение, если он не реализует интерфейс / расширение, или является классом, или ничего не делает, если он это сделал.

Для этого просто:

  public static boolean IsInstance(object x, String className)
  {
     Class cls = Class.forName(className);
     return cls.isInstance(x);
  }

достаточно (и чище)

Если бы вы использовали рефлексию, чтобы получить доступ к полям / методам класса, это просто прекрасно

5 голосов
/ 26 января 2009

Нет, и вы не можете сделать это на большинстве языков.

Причина в том, что тип для приведения должен быть известен во время компиляции, а не во время выполнения (это то, что вы пытаетесь сделать).

Если подумать, это имеет смысл, потому что, учитывая, что переменная может быть именем любого типа, как вы должны получить доступ к различным членам? Вы не можете, если только они не определены в базовом типе / интерфейсе, который реализуют все экземпляры, и в этом случае вы должны просто использовать это.

2 голосов
/ 26 января 2009

Один из сценариев, в котором возникает необходимость, заключается в обеспечении безопасности типов с помощью устаревшей системы. Например, предположим, что у вас есть система персистентности, такая как Hibernate, которая предоставляет необработанные List результаты из метода «поиска». Преобразование этого необработанного List в параметризованный тип приведет к неконтролируемому предупреждению, и, если List содержит объект неправильного типа, ClassCastException может быть вызвано в неуказанное время в некотором отдаленно связанном коде. Возможно, лучше проверить содержимое списка заранее, используя механизм, подобный предложенному ФП.

Вот версия Java 1.3 (без обобщений):

private static void checkType(Collection objs, String className) 
  throws ClassNotFoundException
{
  Class clz = Class.forName(className);
  Iterator i = objs.iterator();
  while (i.hasNext()) {
    Object obj = i.next();
    if (!clz.isInstance(obj)) {
      throw new ClassCastException();
    }
  }
}

В Java 5 и более поздних версиях с обобщениями вы можете сделать нечто подобное с методом Class.cast() для проверки содержимого коллекции, что оправдывает использование аннотации SuppressWarnings. В нашем обзоре подавление предупреждения без каких-либо «доказательств» его безопасности считается ошибкой.

1 голос
/ 26 января 2009

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

ClassName o = (classname)list.get(i); 

Ну, Java статически типизирована. Невозможно, чтобы вы дали ему строку, и он дал вам соответствующий статический тип, так что вы можете идти без приведения. Даже с обобщениями и Class<T>.cast тип назначения приведения приводится не строкой, а обобщенным аргументом типа T, который известен во время компиляции. Вы должны вручную привести к нужному типу или использовать наиболее распространенный тип (в вашем случае это может быть Object).

Если вы сделаете Class.forName(className), он вернет вам объект типа Class, который содержит информацию о типе во время выполнения, так что он позволит вам сделать

Class.forName("my.stuff.MyClass").newInstance()

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

Статический тип возвращаемой ссылки - Object. Это важно: динамический тип объекта, на который ссылаются, и статический тип ссылки, указывающей на этот объект. Динамический тип объекта - это то, что может «контролироваться» строкой (с помощью Class.forName), но статический тип ссылки, с которой вы должны обращаться во время компиляции, и это (просто для примера). ) используется для выбора функций, которые перегружают друг друга, не могут быть определены по строке.

0 голосов
/ 26 января 2009

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

Какой смысл этой коллекции? Разве экземпляры, которые вы храните в нем, не имеют общего общего - какого-нибудь общего супертипа, в который вы могли бы их привести?

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