Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange behaviour with parameterized method on abstract class

Can someone tell my why this gives a compile error? I don't see why the cast to A in the second for-loop causes strings() to return a general List of Objects.

import java.util.ArrayList;
import java.util.List;

public class E {

    public static void main(String[] args) {
        for (String s : new D().strings()) {
            System.out.println("s = " + s);
        }
        for (String s : ((A) new D()).strings()) {
            System.out.println("s = " + s);
        }
    }

    static class D extends A<C> {
    }

    static abstract class A<T extends B> {
        List<String> strings() {
            return new ArrayList<String>() {{
                add("Foo");
                add("Bar!");
            }};
        }
    }

    static class B {
    }

    static class C extends B {
    }
}

Is this a Generics quirk?

Thanks, Kristian

like image 434
Kristian Avatar asked Jan 07 '10 13:01

Kristian


People also ask

Can we use parameterized constructor in abstract class?

Yes, we can define a parameterized constructor in an abstract class.

Can you have a parameter whose type is an abstract class?

Abstract types cannot be used as parameter types, as function return types, or as the type of an explicit conversion (note this is checked at the point of definition and function call, since at the point of function declaration parameter and return type may be incomplete).

Can an abstract class have unimplemented methods?

An abstract class can have one or multiple number of unimplemented methods. As an abstract class is not proper, or does not have ideally defined methods compared to a regular class, so abstract classes cannot be instantiated, that means we cannot create any direct objects of abstract classes.

Can we achieve polymorphism using abstract class?

Abstract base classes are useful for creating polymorphic programs. An abstract base class defines an interface without an implementation. Each abstract base class has one or more concrete derived classes. Concrete derived classes implement the interface defined by their abstract base class.


1 Answers

In the line:

    for (String s : ((A) new D()).strings()) {

You are casting to the raw type A, so you lose the type arguments information there. In Java, any use method or field on a raw type would also result in a raw type (even if all the parameterized information is available) -- well raw type or non-parameterized technically. So A.string() is viewed as the raw type List rather than List<String>.

As the JSL specifies in Section 4.8:

The type of a constructor (§8.8), instance method (§8.8, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the generic declaration corresponding to C. The type of a static member of a raw type C is the same as its type in the generic declaration corresponding to C.

like image 178
notnoop Avatar answered Oct 01 '22 14:10

notnoop