This is the best question out of the three. My thinking is that the compiler/Eclipse doesn't want to assume that Object is necessarily the type T that is inferred between String and Integer so it plays it safe. As bringer128 pointed out String and Integer also both implement Serializable and Comparable - so these types are also candidates for the inferred type of the method.
Up vote 7 down vote favorite 5 share g+ share fb share tw.
This is a follow-up to my previous question but since the previous thread was a long one, I decided to start another thread pertaining to the almost same topic. Public class GenericMethodInference { static void test1(T t1, T t2) {} static void test3(T t1, List t2) {} static void test4(List t1, List t2) {} public static void main(String args) { List c = new LinkedList(); List d = new ArrayList(); List e = new ArrayList(); test1("Hello", new Integer(1)); // ok clause (1) GenericMethodInference. Test1("Hello", new Integer(1)); // ok clause (2) test3("Hello", c); // ok clause (3) test4(d,d) // clause (4) Error due to different type capture generated } Note: If you move your cursor over each clause, you will see the inference being generated and displayed on Eclipse: a.
Clause (1) will produce test1 b. Clause (2) will produce exactly what's defined in the actual type parameter c. Clause (3) will produce test3 > Questions: Why clause (1) didn't produce?
Since works as shown in clause (2), why being produce instead? Why clause (3) produce instead of? Since clause (4) uses the same variable, why 2 different type capture generated eventhough the parameter used is of the same variable d?
Java generics link|improve this question edited Sep 29 '11 at 3:53 asked Sep 28 '11 at 4:12yapkm0156229 72% accept rate.
– Paul Bellora Sep 28 '11 at 5:43 Please see update EDIT 1. Have another question in mind. Thanks – yapkm01 Sep 28 '11 at 19:23.
This is the best question out of the three. My thinking is that the compiler/Eclipse doesn't want to assume that Object is necessarily the type T that is inferred between String and Integer, so it plays it safe. As @bringer128 pointed out, String and Integer also both implement Serializable and Comparable - so these types are also candidates for the inferred type of the method.
It's worth noting that the following code gives the compiler error "illegal start of type": GenericMethodInference. Test1("Hello", new Integer(1)); This is because it's invalid to specify a wildcard as a method's type parameter. So the fact you're seeing that in the tooltip has to do with a subtlety of the compiler's/Eclipse's facility to report this information - it has determined only that T is within its bounds, not what it is.
Remember that Java's implementation of generics is solely for the convenience/sanity of programmers. Once compiled into bytecode, type erasure will have gotten rid of any notion of T. So in its checking, the compiler only needs to ensure that a valid T can be inferred, but not necessarily what it is.
Why clause (3) produce instead of? Because in this case, the fact that a List is passed in where a List is expected tells the compiler that T is exactly Object. Since clause (4) uses the same variable, why 2 different type capture generated eventhough the parameter used is of the same variable d?
It isn't safe for the compiler to assume that d actually refers to the same object, even between evaluating parameters. For example: test4(d,(d = new ArrayList())); In this case, a List would be passed into the first parameter, and an List into the second - both from d. Since this scenario is possible, it's easier for the compiler to play it safe.
1 FYI For clause 1 they have common parent interfaces Serializable and Comparable. The compiler will always try to infer the most specific interface they can find and doesn't like to do resolve to Object if it can help it. – Bringer128 Sep 28 '11 at 7:04 @Bringer128 - Great point, I'll add that to my answer.
– Paul Bellora Sep 28 '11 at 7:07 1 Oh, and I test this in IntelliJ by redefining the method to static List test1(T t1, T t2) { return null;} and then using the IDE to generate a variable (Ctrl+Alt+v) based on the return value of the method. I assume Netbeans can do something similar. – Bringer128 Sep 28 '11 at 7:11 1 @Bringer128 - Yeah, you're right.
Interesting - NetBeans seems to randomly choose Serializable for the generated variable. But when I change the variable to something invalid, say StringBuilder, the compile error is required: java.lang. StringBuilder found: java.lang.
Object&java.io. Serializable&java.lang. Comparable> So I guess that would be the formal expression of the inferred type.
– Paul Bellora Sep 28 '11 at 7:34.
The test1() case is actually quite sinister. See JLS3 15.12. 2.7. We are not supposed to know the details of type inference - in most cases intuition coincides with the algorithm. Alas that's not always the case, as in the seemingly trivial test1() example.
The constraints we have is T :> String and T :> Integer ( ":>" means super type) This leads to T=lub(String,Integer), lub means "least upper bound". Since String and Integer , this leads to lci({Comparable, Comparable}), which yields Comparable, i.e. Compable In the end, we have T = Serializable & Compable, a self referenced definition!
Spec calls it "infinite type": It is possible that the process above yields an infinite type. This is permissible, and Java compilers must recognize such situations and represent them appropriately using cyclic data structures. Let's find out how javac represents it: (javac 7) static T test1(T t1, T t2) {} public static void main(String args) { Void x = test1("Hello", new Integer(1)); } error: incompatible types required: Void found: INT#1 where INT#1,INT#2 are intersection types: INT#1 extends Object,Serializable,Comparable INT#2 extends Object,Serializable,Comparable That doesn't seems right; it's not really recursive; it appears that javac detects recursion in lub() and gives up, resulting a less specific type Comparable.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.