简体   繁体   中英

Introducing generics to Java code without breaking the build

The following code does not compile:

public class GenericsTest {    
    public static void main(String[] args) {
        MyList<?> list = new MyList<Object>();
        Class<?> clazz = list.get(0);

        // Does not compile with reason 
        // "Type mismatch: cannot convert from Object to Class"
        MyList list2 = new MyList();
        Class clazz2 = list2.get(0);
    }
    static class MyList<T> extends ArrayList<Class<T>> {
    }
}

I wanted to do this to introduce generics to old code without breaking the build.

Is this a bug in both the compiler (both eclipse and javac) or am I missing something here? What other possibility exists to introduce generics to MyList?

EDIT

For clarification:

I have the generic class

public class MyList extends ArrayList<MyObject> {}

with

public class MyObject {}

and code using MyList

MyList list = new MyList();
...
MyObject o = list.get(0);

Now during development I see I want to introduce generics to MyObject

public class MyObject<T> {}

and now I want to have this new generic thingy in MyList as well

public class MyList<T> extends ArrayList<MyObject<T>> {}

But that does break my build. Interestingly

public class MyList<T> extends ArrayList<MyObject<T>> {
    public MyObject<T> get(int i) {
        return super.get(i);
    }
}

will allow old code

MyList list = new MyList();
...
MyObject o = list.get(0);

to compile.

OK, seems that when I introduce this generic, I will have to live with having to change all calls to MyList to the generic form. I wanted the old code to just introduce a warning instead of an error.

I think you are not understanding quite how generics work.

MyList<?> list = new MyList<Object>();
Class<String> clazz= list.get(0);

This code snippet does not compile because you are telling the compiler that list is going to hold Class<Object> types - and then in the next line you are expecting it to return you a Class<String> . The generic system in Java is not capable of converting types used with generics based on inheritance like you might think it would.

If you expect list to hold Class<String> , then you need to declare it as so - or, if you want it to be able to hold any types, then you cannot do the second line without a cast.

MyList<String> list = new MyList<String>();
Class<String> clazz = list.get(0);

or

MyList<?> list = new MyList<Object>();
//generates a warning about an unchecked cast
Class<String> clazz = (Class<String>) list.get(0);

The second code snippet does not work because when you use raw types, you still need to cast the Object returned by get() to the declared type you are using (which has always been the case).

MyList list2 = new MyList();
Class clazz2 = (Class) list2.get(0);

I don't have a compiler on this machine, but this should work.

public class GenericsTest {    
    public static void main(String[] args) {
        MyList<Object> list = new MyList<Object>();
        Class<?> clazz= list.get(0);

    }


    static class MyList<T> extends ArrayList<Class<? extends T>> {
    }
}

In your example is MyList the old code you want to update to support generics? If so, what type of objects is my list supposed to contain?

As was mentioned here elsewhere that compilation error is valid. It is due to the fact that a raw list is being accessed without the get being cast to Class. Hence the code is attempting to assign an Object to a reference of a Class. It is equivalent to this:

Object o = new Object();
Class c = o;

Which simply cannot compile. Also, to fully utilize generics you should favor Class<?> instead of Class.

In your example the second example doesn't work because you are not using generics so it means that the get() method will return a Object and you will need to cast it to a Class. When you are not specifying a type for your MyList :

MyList list2 = new MyList();

Then you are losing the Generics advantages and you need to cast the object when calling the get() method just like in the good ol' days.

Have you tried:

Class clazz2 = list2.get(0).getClass();

Read about it at: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#getClass()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM