Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting to an inner class with generics

Consider the following code:

public class Outer<T>  {

    public class Inner{
    }

    public static <T> Outer<T>.Inner get(){
        Object o = new Object();
        return (Outer<T>.Inner)o;
    }

    public static void main(String[] args) throws Exception {
        Outer.<String>get();
    }
}

This code compiles successfully in Eclipse, but fails to compile in javac:

Outer.java:10: ')' expected
        return (Outer<T>.Inner)o;
                        ^
Outer.java:10: ';' expected
        return (Outer<T>.Inner)o;
                         ^
Outer.java:10: illegal start of expression
        return (Outer<T>.Inner)o;
                              ^
3 errors

Is this a bug in javac or Eclipse?

If I change the cast to (Outer.Inner)o it compiles, although there is a warning:

Eclipse:

Outer.Inner is a raw type. References to generic type Outer<T>.Inner should be parameterized

javac:

Outer.java:10: warning: [unchecked] unchecked conversion
found   : Outer.Inner
required: Outer<T>.Inner
        return (Outer.Inner)o;
               ^
1 warning

Javac version: 1.6.0_21

like image 917
dogbane Avatar asked Nov 11 '10 16:11

dogbane


People also ask

How do I access an inner class from another class?

They are accessed using the enclosing class name. For example, to create an object for the static nested class, use this syntax: OuterClass.

Can an inner class be accessed from outside?

Unlike a class, an inner class can be private and once you declare an inner class private, it cannot be accessed from an object outside the class.

What are the disadvantages of using inner classes?

Inner classes have their disadvantages. From a maintenance point of view, inexperienced Java developers may find the inner class difficult to understand. The use of inner classes will also increase the total number of classes in your code.

Can inner class have static methods?

Inner Classes As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields. Also, because an inner class is associated with an instance, it cannot define any static members itself.


2 Answers

I have found that this is a bug in the javac compiler that has since been fixed. JDK 7b100 compiles this fine.

See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6665356

like image 162
dogbane Avatar answered Oct 06 '22 00:10

dogbane


The most amusing thing is that, unless there is something that I miss about Java generics, both

return (Outer<T>.Inner) o;

And

return (Outer.Inner) o;

Both compile to the same bytecode.

The problem for the first line happens at parsing - meaning that javac and Eclipse do not use the same parser for Java source code. You should ask a question about what differences there are between Eclipse JDT's java parser and javac's. (Or post a bug at Eclipse).

If you insist on keeping that behaviour (I would suggest refactoring Inner to a static inner class), you could use @SuppressWarning with a field assignation (in order to restrict the @SuppressWarning to the smallest scope possible).

@SuppressWarnings({"rawtypes","unchecked"})
Outer<T>.Inner casted = (Outer.Inner)o;
return casted;

EDIT: OK, I believe I got it - Eclipse's JDT parses the Java code before passing it to the compiler - and their parser can make sense of such a cast, while (at least your and my version of) javac's cannot. (And after that, Eclipse directly passes the parsed code to compilation). Before filing a bug, look at how the last version of Java 6 behaves.

like image 42
Jean Hominal Avatar answered Oct 06 '22 00:10

Jean Hominal