views:

2701

answers:

6

I currently posses a List of Objects(Using Java 1.3), and let's say that I wanted to cast one of the Objects returned from list.get(i) to a type of which I only know the name of the Class as a String. Essentially, how do I Object o = (classname)list.get(i); where className is a String variable of a className.

I thought that I could use ( Class.forName(className) )list.get(i), but I received a syntax error claiming that I forgot a semicolon.

Unfortunately, since I am using Java 1.3, I do not have access to the Class.cast(Object) method.

What is the name of the class used when casting to another type in Java 1.3? Is there some method that can give me the correct type I need with a String parameter of the class name?

+2  A: 

No, and you can't do this across most languages.

The reason is that the type to cast to has to be known at compile time, not at runtime (which is what you are trying to do).

If you think about it, it makes sense, because given that the variable could be any type name, how are you supposed to access the various members? You can't, not unless they are defined in a base type/interface that all instances implement, in which case you should just use that.

casperOne
A: 

I assume that you really wanted to write the following, instead of using Object on the left side. Since otherwise, it's really just about checking whether the object in the list is of the right type.

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

Well, Java is statically typed. It's not possible that you give it a string and it gives you the corresponding static type, so that you can go without casting. Even with generics and Class<T>.cast, the cast destination type is not given by a string, but by the generic type-argument T, which is known at compile-time. You have to manually cast to the right type, or keep using the most common type (may be Object in your case).

If you do Class.forName(className), it gives you back an object of the type Class which contains information about the type at runtime, so that it allows you to do

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

But the cast wants a type - not an object of some type. That is why the compiler told you there is something wrong with that code.

The static type of the reference returned by that is of Object. This is important: The dynamic type of an object that is referenced, and the static type of the reference that points to that object. The dynamic type of the object is what can be "controlled" by a string (by using Class.forName), but the static type of the reference that you have to do with at compile time, and that is (just to give an example) used to select functions that overload each other, can not be determined by a string.

Johannes Schaub - litb
+8  A: 

what is the point of casting when all you do is assign the result to object? All you would achieve is an exception if it did not implement the interface/extend or was the class or do nothing if it did.

For that a simple:

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

is sufficient (and cleaner)

If you were to the use reflection to get at the fields/methods of the class that's just fine

ShuggyCoUk
That's exactly the point---fail fast, with an exception, right where the problem is, rather than some unspecified later time and place.
erickson
A: 

The question was answered already, but I'd like to add that it seems a bit dubious that you should have a List in which you keep several different kinds of objects (in this case, any objects), yet you'd apparently like to invoke operations on them that are specific to each different type...

What's the point of this collection? Don't the instances you keep in it have anything in common - any common supertype that you could cast them into?

Jonik
+2  A: 

One scenario where the need for this arises is when enforcing type safety with a legacy system. For example, suppose you have a persistence system like Hibernate that provides a raw List of results from a "finder" method. Casting this raw List to a parameterized type will result in an unchecked warning, and if the List contains an object of the wrong type, a ClassCastException can be raised at an unspecified time in some distantly related code. It may be best to validate the contents of the list up front, using a mechanism like the OP suggests.

Here's the Java 1.3 version (without generics):

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();
    }
  }
}

In Java 5 and later, with generics, you can do something similar with the Class.cast() method to verify the contents of a collection, justifying the use of a SuppressWarnings annotation. In our review process, suppressing a warning without some "proof" that it is safe is filed as a bug.

erickson
A: 

public class ExampleClass {

public static void main(String[] args) {
 // TODO Auto-generated method stub
 Horse hr1 = new Horse();
 Horse hr2 = new Horse();
 Horse hr3 = new Horse();
 Horse hr4 = new Horse();
 Set hrSet = new HashSet();
 hrSet.add(hr1);
 hrSet.add(hr2);
 hrSet.add(hr3);
 hrSet.add(hr4);
 Horse hr;
 String hor = "sher_pkg.Horse";
 callHorse(hrSet,hor);
}
public static void callHorse(Set xSet,String clsName){
 try {
  Class hrt = Class.forName(clsName);

  Iterator hritr = xSet.iterator();
  while(hritr.hasNext()){
   exam(hrt.cast(hritr.next()));
  }
 } catch (ClassNotFoundException e) {

  e.printStackTrace();
 }
}
public static void exam(Object obj){  //I want it to be like exam(Horse hr)

 System.out.println(obj);
}

}

Here the argument for the exam function is an Object. But i want to have the argument to be Horse... so want changes must be done in "exam(hrt.cast(hritr.next()))" method call.. I dont want to explicitly use the class name Horse in callHorse()... So Want am i supposed to do??

msher420