3
public class MyGenericClass< G> {


    public <G> G genericMethod1(G g){
        System.out.println(g.toString());
        return g;

    }

    public <X> G genericMethod2(G g) {
        System.out.println(g.toString());
        return g;
    }

    public <X> X genericMethod3(G g) {
        System.out.println(g.toString());
        Integer i = new Integer(100);
        return (X) i;       
    }


    public static void main(String... cmdarg) {

        MyGenericClass<Employee> gemp = new MyGenericClass<Employee>();
        Employee e1 = new Employee();
        e1.setName("My Name");


        String resultOfMethod3 = gemp.genericMethod3(e1);
        System.out.println(resultOfMethod3);                            

    }


}

in genericMethod1: I get the compiler warning as "The type parameter G is hiding the type G".

Question: Which G is hidden by this G? What's the actual meaning of this?

genericMethod2 doesn't show any errors/warnings.

Question: I thought it should not compile. why is two different types allowed in same method signature? What can be typical real time example to compare with G and X?

In genericMethod3: I'm intentionally returning an Integer object and in the main method i'm trying to assign the result to a String. As expected: I got the ClassCastException.

Question: Isn't the original purpose of having generics to avoid ClassCastExceptions? Why did the compiler allow it? Is this a bug in the design of Generics?

npinti
  • 50,175
  • 5
  • 67
  • 92
Jinnah
  • 128
  • 9
  • 3
    You've declared a generic type `G` on your class _and_ on your method ... for what? And btw this is the reason why the generic `G` of the method hides the type `G` of the class. *"What can be typical real time example to compare with G and X?"* Where in method 2 do you compare something? – Tom Sep 28 '15 at 09:55
  • Thanks so much, Tom. So return type in the method is hiding the class type . is it? I think I got it. I think still my other two questions remain open. – Jinnah Sep 28 '15 at 10:01
  • No `` is not the return type, it is a generic type defined for that method. Your return happens to be `G` for method 1, but it could also be `int` or `void`. – Tom Sep 28 '15 at 10:03
  • great! I got it. Thanks. – Jinnah Sep 28 '15 at 10:18

3 Answers3

5

Generics can be used at class level and at method level:

  • public class MyClass<T>: T is available for all instance members (i.e. non-static) of the class (fields, methods, inner classes...)
  • public (static) <U> ReturnType myMethod(..) {...}: U is available for the method only

You're mixing them.

With public <G> G genericMethod1(G g), this <G> generic is hiding the class' one since they have the same name, so the latter isn't available in the method anymore. If you want to use the class' generic, don't specify it at the method level: public G genericMethod1(G g).

With public <X> G genericMethod2(G g), you're defining a generic <X> that isn't used: only the class' generic G is used.

With public <X> X genericMethod3(G g), you're defining a generic <X> that is used for the return value of the method. In the method body, you're casting an int to X but you can't be sure that X is a super type of int. Technically, this can be done with <X super Integer>, but I'm not sure this is actually what you're looking for.

sp00m
  • 44,266
  • 23
  • 127
  • 230
  • Wow..! Great explanation! I love it! – Jinnah Sep 28 '15 at 10:14
  • Could you please give me some real time example of method level Generics? Anything from Java API will also be fine. – Jinnah Sep 28 '15 at 10:16
  • @Mohamed Method level generics can be usually found in utilities classes, see for example [`Collections.unmodifiableList`](http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#unmodifiableList(java.util.List)). – sp00m Sep 28 '15 at 10:17
  • Thanks! And i'm sorry i'm unable to vote your answer as I'm a new user. I'm yet to earn 15 reputations to get the privilege. – Jinnah Sep 28 '15 at 10:21
  • @Mohamed No problem, glad I could help ;) But don't forget to [accept an answer](http://meta.stackexchange.com/a/5235) though. – sp00m Sep 28 '15 at 10:23
  • I've accepted. But I think one question is kind of partially open: "Isn't the original purpose of having generics to avoid ClassCastExceptions? Why did the compiler allow it? Is this a bug in the design of Generics?" Any thoughts? – Jinnah Sep 28 '15 at 10:29
  • 1
    @Mohamed The compiler can't know if the cast is allowed or not due to [type erasure](http://stackoverflow.com/a/339708/1225328). But it still warns you: *"Unchecked cast from Integer to X"*. – sp00m Sep 28 '15 at 10:42
3
public class MyGenericClass< G> {


    public <G> G genericMethod1(G g){
        System.out.println(g.toString());
        return g;

    }

You have two different <G> variables here, one on class level and one on method level. This is roughly equivalent to having a field and a local variable of the same name. The local variable would "win" in that case, just as the method level <G> would override the class-level one. Since this is a common cause of errors, IDEs warn you of this.

Method 2 doesn't redefine <G>, so it generates no warning.

Sean Patrick Floyd
  • 274,607
  • 58
  • 445
  • 566
  • Thanks Sean! What can be typical real time example to compare with G and X as in method2? Also why is method3 not illegal? Isn't the original purpose of having generics to avoid ClassCastExceptions? – Jinnah Sep 28 '15 at 10:06
0

change your genericMethod1 as follow:

public G genericMethod1(G g){
    System.out.println(g.toString());
    return g;
}
Vaseph
  • 664
  • 1
  • 8
  • 20