Please go through the entire question to have complete idea.
First let the class Box
is given as follows:-
public class Box <T>{
private T t;
public void set(T t){
this.t = t;
System.out.println("value:\n");
System.out.printf("%s", t.toString());
}
public T get() {
return t;
}
static int retInt(){
return 5;
}
public <U extends Number> void inspect(U u){
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
}
Generic class Util
as given below:-
public class Util<T>{
private T t;
//Generic method
public <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
/* Static generic or non-generic methods can be declared in generic class
but they can not make use of generic parameter type(as generics static
methods using class type variable must know the type argument
(i.e value of type parameter); and knowledge of type argument is
possible only when object of same generic class are instantiated
(meaning assigning value of generic type parameter <T> or better to
say declared object have it's type argument; for example
as in List<T> replace T with Integer,String, Float etc);
but static method may be called without having
instance of class; so such declaration for static generic method are
not allowed) here it is <T>; like for example as shown below
public static int checkFun(T t){
return 5;
} // this generate compiler error complaining "can not make static
// reference to non-static type T".
*/
public static <K> boolean cmp(Box<K> b1, Box<K> b2){
// implement comparator to compare but here
return true;
}
// Inner class Pair
public class Pair <K, V> {
private K key;
private V value;
// Generic constructor
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public void setKey(K key) {
int i = 6;
if(i >4 || i<9);
this.key = key;
}
public void setValue(V value) {
this.value = value;
}
public K getKey(){
return key;
}
public V getValue(){
return value;
}
}
public void main1() {
//The complete syntax for invoking this method would be:
// <Integer, String> new Util<T>().
Pair<Integer, String> p1 = new Pair<Integer,String>(1, "apple");
Pair<Integer, String> p2 = new Pair<Integer, String>(2, "pear");
boolean same = compare(p1, p2);
//boolean same = true;
if(same)System.out.println("it is true: they are the same");
else System.out.println("nah! they are not the same...");
//boolean sm = compare();
}
public static void main (String[] args) /*throws FileNotFoundException */{
//new Util<Integer>(). main1();
Util<Integer> util = new Util<>();
util.main1();
}
}
Above code compiles and executes just fine, my discomfort lies here:
If we add static
modifier to method
public <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) -------(1)
// called in method main1()
and make it
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) -------(2)
then compiler will complain that Cannot make a static reference to the non-static type Pair whereas similar method
public static <K> boolean cmp(Box<K> b1, Box<K> b2) -------(3)
which is also static but doesn't complain. Even though we are not using type parameter <T>
in both method but
a big but
in method we are talking from eq-1
the argument it uses is from inner class Pair
(so reasoning of my ambiguity may be explained with reference to this feature).
But still; logically, I feel that adding modifier static
to method in eq-1
should not generate compile time error because wherever the method in eq-2
is called it will be responsibility of that method to call with correct argument to method in eq-2
and it should be allowed to be called like a static method.
Question:- What is the explanation for not using static modifier for the method:
public <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2)
Thanks for the help.
The reason for this is the type parameter on the Util class and the inner class Pair is non-static. Because Pair is a non-static inner class, it can use the T type parameter of Util (even though in this case it does not). Therefore when Pair is used it is necessary to specify a T, either by accessing it within the context of a Util instance (where the T is implicitly available) or by qualifying by accessing it through a specific Util<T>
, e.g. Util<Integer>.Pair<String,Object>
. Another way to think of it is that the type of Pair depends on the type parameter of Util and Util<String>.Pair<K,V>
is not compatible with Util<Object>.Pair<K,V>
.
To keep the type parameter T on Util and keep Pair as a non-static inner class, you can change the signature of compare to
public static <T, K, V> boolean compare(Util<T>.Pair<K, V> p1, Util<T>.Pair<K, V> p2)
or
public static <K,V> boolean compare(Util<?>.Pair<K,V> p1, Util<?>.Pair<K,V> p2)
which is possible because the instantiation of T is not relevant to the body of the method.
As an alternative, since Pair does not refer to anything (non-static) inside of Util you can change the definition of Pair to be
public static class Pair <K, V> { /* ... */ }
Finally for completeness, if Util did not have a type parameter then
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2)
and
public class Pair<K, V> { /* ... */ }
would be just fine.
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