Narkha
Narkha

Reputation: 1197

Generic interface with a method that return a list

I have a Generic interface (Pack<A extends PackAnimal>) with one method that returns List<A>. Today I've found that if in a class that implements the interface I forget to speficy the class (class XXX implements PackAnimal) the return type is not checked in compilation time and fail during execution

interface PackAnimal {
}
class Buffalo implements PackAnimal {
}

interface LonelyAnimal {
}
class Puma implements LonelyAnimal {
}

interface Pack<A extends PackAnimal> {
    List<A> getMembers();
}

class PumaPack implements Pack {

    @Override
    public List<Puma> getMembers() {
        return null;
    }
}

Why is that? How could I force that if there any type of mistake in the declaration the compilation will fail?

Upvotes: 3

Views: 1666

Answers (2)

OldCurmudgeon
OldCurmudgeon

Reputation: 65813

You are experiencing the scary and wierd results of using Raw Types.

Essentially if you miss out the <...> anywhere it should be the compiler treats your code as legacy and does not do much of the normal type checking it should. MOst compilers try their best but it leaves gaping holes in the checking process.

interface PackAnimal {
}

class Buffalo implements PackAnimal {
}

interface LonelyAnimal {
}

class Puma implements LonelyAnimal {
}

interface Pack<A extends PackAnimal> {
    // Obviously fine.
    List<A> getMembers();
}

// Raw type so no checking.
class PumaPack implements Pack {

    @Override
    public List<Puma> getMembers() {
        // Raw typed class so Puma isn't checked for PackAnimal super.
        return Arrays.asList(new Puma());
    }
}

class Six {

}

// Properly typed so Raw Types not happening.
class SixPack implements Pack<Six> {

    @Override
    // NOT ALLOWED: Attempt to use incompatible return type!!!
    public List<Six> getMembers() {
        return null;
    }
}

Upvotes: 1

Bohemian
Bohemian

Reputation: 424993

Your List is declared with an unknown type. Use the class type:

interface Pack<A extends PackAnimal> {
    List<A> getMembers();
}

// won't compile because Puma not within bound
class PumaPack implements Pack<Puma> {
    List<Puma> getMembers() {return null;}
}

// compiles OK
class BuffaloPack implements Pack<Buffalo> {
    List<Buffalo> getMembers() {return null;}
}

But you can't stop someone coding a raw (missing type) implementation like your PumpPack example, however you will get a compiler warning:

// compile warning
class PumaPack implements Pack {
    List getMembers() {return null;}
}

If you set your compile to fail if there are warnings:

javac -Werror ...

then you will achieve your goal even for raw types.

Upvotes: 2

Related Questions