Faton
Faton

Reputation: 873

Java generics with inner class and inner interface

Below I have a generic OuterClass, an InnerClass that use OuterClass generics and non-generic InnerInterface.

public class OuterClass<E> {

    public class InnerClass  {

        public E someMethod() {
            return null;
        }
    }

    public interface InnerInterface{
        public void onEvent(OuterClass.InnerClass innerClass);
    }
}

In the main method below, I use two instance of OuterClass, o1 parameterized with , and o2 with . My annonymous inner class myListener tries to use the generic type of the outer class (E). The code as it is below does not compile (Integer i = innerClass.someMethod() - Type mismatch: cannot convert from Object to Integer).

public class Test {
    public static void main(String[] args) {

        OuterClass<Integer> o1 = new OuterClass<Integer>();
        OuterClass<String> o2 = new OuterClass<String>();

        OuterClass.InnerInterface innerInterface = new OuterClass.InnerInterface() {
            @Override
            public void onEvent(InnerClass innerClass) {
                Integer i = innerClass.someMethod();
            }
        };
    }
}

I would like to express that myListener is for o1, and should use E = Integer, without repeating it (without repeating , I already say it when declaring o1). Is that possible?

Many thanks! Faton.

Upvotes: 10

Views: 16588

Answers (2)

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147154

As always, non-private nested types don't help keeping things simple. Push the boat out and create some new files, even if your IDe works against you.

Anyway, static members of a class do not share the generic parameters of the outer class. This is important for the behaviour of fields, and allows more flexibility on static nested types (such as InnerInterface) even if you don't want it. So, in your case, you need to give your (static) nested interface a generic parameter. For $deity's sake, use a different identifier!

public class OuterClass<E> {
    public class InnerClass  {
        public E someMethod() {
            return null;
        }
    }

    public interface InnerInterface<T> {
        void onEvent(OuterClass<T>.InnerClass innerClass);
    }
}


public class Test {
    public static void main(String[] args) {

        OuterClass<Integer> o1 = new OuterClass<Integer>();
        OuterClass<String> o2 = new OuterClass<String>();

        OuterClass.InnerInterface<Integer> innerInterface =
            new OuterClass.InnerInterface<Integer>() 
       {
            @Override
            public void onEvent(OuterClass<Integer>.InnerClass innerClass) {
                Integer i = innerClass.someMethod();
            }
        };
    }
}

(I've also qualified InnerClass where necessary.)

Edit: It's probably worth just looking at the original anonymous inner class in isolation from the rest of the use:

public interface InnerInterface{
    public void onEvent(OuterClass.InnerClass innerClass);
}

    OuterClass.InnerInterface innerInterface = new OuterClass.InnerInterface() {
        @Override
        public void onEvent(InnerClass innerClass) {
            Integer i = innerClass.someMethod();
        }
    };

Integer only appears once, in a place where it clearly cannot be inferred to be correct.

Upvotes: 1

Laurent Pireyn
Laurent Pireyn

Reputation: 6875

An inner interface or enum is implicitely static, and static members are not parameterized with the type parameters of the outer class. So InnerInterface should look like this:

public interface InnerInterface<E> {
    void onEvent(OuterClass<E>.InnerClass innerClass);
}

Note that the E parameter of InnerInterface is not the same as the E parameter of OuterClass.

Upvotes: 16

Related Questions