Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
228 views
in Technique[技术] by (71.8m points)

java - Generic screws up non-related collection

Why do collections that are not related to the template class drop their type? Here is an example: (Sorry, it will not compile because of the error I'm confused about.)

package test;

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

public class TemplateTest {

    public static class A { }

    public static class B<T extends Comparable> {
        List<A> aList = new ArrayList<A>();

        public List<A> getAList() {
            return aList;
        }

        public int compare(T t, T t1) {
            return t.compareTo(t1);
        }
    }

    public static void main(String[] args) {
        B b = new B();
        for (A a : b.getAList()) { //THIS DOES NOT WORK

        }
        List<A> aList = b.getAList(); //THIS WORKS
        for (A a : aList) {

        }
    }
}

This code throws an error upon compilation:

test/TemplateTest.java:24: incompatible types
    found   : java.lang.Object
    required: test.TemplateTest.A
        for (A a : b.getAList()) {

If I specify the template of B like B<String>, or if I remove the template from B completely, then everything is ok.

What's going on?

EDIT: people pointed out there was no need to make B generic so I added to B

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Yes, it is known behaviour that if you use a raw type, then all type parameters on the class are lost, not just the type-level parameter that you failed to declare.

The issue is partly here:

If I specify the template of B like B<String>, or if I remove the template from B completely, then everything is ok.

That's not an option, you aren't to choose if you want to specify the type parameter or not. The only reason it compiles at all with no parameter specified is for backward compatibility. Writing new code with missing type parameters is a programming error.

List<A> list = b.getList() does not successfully interpret the type, it is just effectively sticking in an arbitrary cast and trusting you that the assignment is correct. If you look at the compiler warnings it is in fact generating a warning for an unsafe conversion.

for(A a : b.getList()) {} upgrades that warning to an error because the inserted cast would be inside compiler generated code, so it refuses to auto-generate unsafe code at all, rather than just give a warning.

From the java language specification:

The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.

Bottom line really is that the only significant thing java generics share with C++ templates is the <> syntax :)

More details: What is a raw type and why shouldn't we use it?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...