Have a look at this simple example of Java generics:
class List<T> {
T head;
List<T> next;
}
class A<T> {
List<T> l;
public <T> int length() {
List<T> l = this.l;
int c = 1;
while (l.next != null) {
c++;
l = l.next;
}
return c;
}
public static void main(String[] args) {
A<Integer> a = new A<Integer>();
a.l = new List<Integer>();
a.l.head = 123;
a.l.next = new List<Integer>();
a.l.next.head = 432;
System.out.println("list length: " + a.length());
}
}
It gets an error compiling, claiming that the types are incompatible, yet claiming that the two variables are the same type:
$ javac A.java && java A
A.java:10: incompatible types
found : List<T>
required: List<T>
List<T> l = this.l;
^
1 error
If I change the first line of length() to List<T> l = (List<T>)(Object)this.l;
, it works. Why?
Equals(Object) Method which is inherited from the Object class is used to check if a specified List<T> object is equal to another List<T> object or not. Syntax: public virtual bool Equals (object obj);
if (myList. Contains(myString)) string element = myList. ElementAt(myList. IndexOf(myString));
They are two separate objects. See this answer from the C# FAQ. Show activity on this post. In other words, since these are two different lists, they have different references, so Equals returns false .
You've declared a generic method inside a generic class with this line:
public <T> int length() {
This <T>
is different than your class's <T>
. According to the JLS Section 6.3:
The scope of a class's type parameter (§8.1.2) is the type parameter section of the class declaration, the type parameter section of any superclass or superinterface of the class declaration, and the class body.
You don't need to re-declare <T>
on your method; the class's type parameter is already in scope.
To use your class's generic type parameter <T>
, have your method not declare another <T>
and simply use your class's <T>
:
public int length() {
To understand why your casting works:
List<T> l = (List<T>)(Object)this.l;
You can cast any object to Object
. Then you are casting the result to List<T>
. You can always cast it to anything you want; Java will simply throw a ClassCastException
at runtime if it wasn't really a List
at runtime. But the compiler will also give a warning that it uses unchecked or unsafe operations, because it can't guarantee that this <T>
is the original <T>
.
To illustrate the difference between <T>
s, you can use <U>
as the generic type parameter for the method and get the same results:
public <U> int length() {
List<U> l = (List<U>)(Object)this.l;
This compiles with the same type safety warning.
If you really know that type safety can be guaranteed, you can use @SuppressWarnings("unchecked")
to annotate your method. But here, I'd still go with removing the generic type parameter from the method entirely, and using the class's type parameter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With