Tim
Tim

Reputation: 127

Using an ArrayList<Class?> for casting?

Previous question

I have the following code:

ArrayList<Object> list = new ArrayList<Object>();
list.add("StringType");
list.add(5);
list.add(new RandomClass());

List<Class<?>> classes = new ArrayList<>();
classes.add(String.class);
classes.add(int.class);
classes.add(RandomClass.class);

for (int i = 0; i < list.size(); i++) {
    if (classes.get(i).isInstance(list.get(i))) {
        ...
    }
}

if (isvalid)
 mymethod(...);


public void mymethod(String string, int num, RandomClass randomClass){ }

Now I'm trying to cast the object into the right type with a method using a string argument.

Instead of:

mymethod( (String) list.get(0), (int) list.get(1), (RandomClass) list.get(2) );

I would like to reuse the definition created above for the cast.

mymethod( ( define.get(0) ) list.get(0), .... );

I've also tried using the Class.cast(obj) but of course it returns a type '?' which again defeats the purpose of casting it again using (String).

Upvotes: 0

Views: 59

Answers (4)

RealSkeptic
RealSkeptic

Reputation: 34628

In order to be able to select the appropriate method, the compiler needs to know at compile time what the types of the arguments are. Or at least a general category such as List<?> etc.

This is needed to support overloading of methods. There can be many methods with the same name, but with different parameter types.

Since you are asking the VM to call a method when it can't determine which exact method you want to call, because it doesn't know at compile time what the types of your parameters are, what you ask cannot be done in Java.

Here is the relevant section from the Java Language Specification.

What it says is that the system selects at compile time which method signature to use, and then, at run time, the particular implementation of that method signature that's correct for the given instance.

Upvotes: 1

Boris the Spider
Boris the Spider

Reputation: 61158

What is type safety?

In computer science, type safety is the extent to which a programming language discourages or prevents type errors.

If code is type safe, then the compiler can verify, at compile time, that all the types are correct:

String getName() {
    return "name";
}

The compiler knows that "name" must be a String so it can verify that this code will never throw a type error.

Once you do something like:

int getNumber() {
    (int) number;
}

The need to explicitly cast to int tells you that this code has an error condition, namely when number is not of type int or a type that is assignable to int.

How does it affect you?

Your code:

define.get(0).cast(list.get(0))

You want the return type of this statement to be of the type of get(0). But the compiler has no way of knowing, at compile time, what define.get(0) returns. This is inidcated to you by the return type.

You have a List<Class<?>>, i.e. a List of a class of "I don't care what type". You then use a member of this List to cast a member of your other List - the only result can be an "I don't care what type".

You can hack around this with:

<T> T get(final int i) {
    return (T) define.get(i).cast(list.get(i));
}

This will happily compile:

final String thing = get(0);

As will:

final int thing = get(0);

i.e. all that you have done is to endogenise the cast. The error condition still exists.

Upvotes: 2

Germann Arlington
Germann Arlington

Reputation: 3353

You don't actually need to store object's class separately

list.get(0).getClass()

will get you the class of the stored object and then you can use what @Eran suggested

and

list.get(0).getClass().getName() 

will get you the String name of your class

Upvotes: 0

Eran
Eran

Reputation: 393846

define.get(0).cast(list.get(0)) would attempt to cast list.get(0) to the required type.

Upvotes: 2

Related Questions