Using an ArrayList<Class?> for casting?

自闭症网瘾萝莉.ら 提交于 2019-12-13 04:24:27

问题


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).


回答1:


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.




回答2:


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




回答3:


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.




回答4:


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



来源:https://stackoverflow.com/questions/26827226/using-an-arraylistclass-for-casting

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!