当只给出类型名称的字符串时,如何将其转换为未知类型

8
我目前拥有一个对象列表(使用Java 1.3),假设我想将从list.get(i)返回的其中一个对象转换为一个我只知道类名的类型。基本上,我该怎么做才能使Object o = (classname)list.get(i); 其中className是一个className的字符串变量。
我认为我可以使用(Class.forName(className))list.get(i),但我收到了一个语法错误,声称我忘记了分号。
不幸的是,由于我正在使用Java 1.3,我无法访问Class.cast(Object)方法。
在Java 1.3中,用于转换为另一种类型的类名是什么?是否有某种方法可以通过类名的字符串参数给我所需的正确类型?

如果您升级Java版本,请直接升级到Java 6,因为Java 5将在十月份停止支持。:-] - Peter Lawrey
5个回答

11

当你把结果赋给对象时,强制类型转换的意义在哪里呢?如果它没有实现接口/扩展或不是该类,则只会导致异常,或者如果它实现了,则不会有任何影响。

为此,一个简单的:

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

足够了(而且更加简洁)

如果您使用反射来获取类的字段/方法,那也是可以的


这正是关键所在——快速失败,通过异常处理直接定位问题,而不是在未来的某个时间和地点。 - erickson

5

不可以,而且大多数编程语言都不能这样做。

原因是需要在编译时知道要转换的类型,而不是在运行时(这就是你试图做的事情)。

仔细想一想,这是有道理的,因为考虑到变量可以是任何类型名称,你怎么能访问各种成员呢?除非它们在所有实例中实现了一个基础类型/接口中定义,否则你无法访问它们,此时你应该直接使用该类型/接口。


2
一种需要这种方式的情况是在与遗留系统一起实施类型安全时。例如,假设您有一个像Hibernate这样的持久性系统,它从“查找器”方法提供原始的结果List。将此原始List强制转换为参数化类型将导致未经检查的警告,并且如果列表包含错误类型的对象,则ClassCastException可能会在某些远程相关代码中的未指定时间引发。最好事先验证列表的内容,使用像OP建议的机制。
以下是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

我猜你实际上想要写以下代码,而不是在左侧使用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

这个问题已经回答了,但我想补充一下,你应该有一个列表,其中包含几种不同类型的对象(在这种情况下,任何对象),然而你似乎希望调用它们各自不同类型的特定操作...

这个集合的意义是什么?你保存在其中的实例没有任何共同点吗 - 任何可以将它们强制转换成的共同超类型吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接