为什么我不能在泛型类上静态引用内部类的静态方法?

时间:2014-05-23 14:59:29

标签: java generics static inner-classes

请仔细阅读整个问题以获得完整的想法。

首先让课程Box给出如下: -

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());
        }

}

通用课程Util如下: -

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();
    }  
}

上面的代码编译并执行得很好,我的不适就在于:

如果我们向方法

添加static修饰符
public <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2)    -------(1)
// called in method main1() 

并制作

public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2)     -------(2) 

然后编译器会抱怨无法对非静态类型对进行静态引用而类似方法

 public static <K> boolean cmp(Box<K> b1, Box<K> b2)    -------(3)

这也是静态但不抱怨。即使我们在<T>方法but中没有使用类型参数big but,我们在eq-1中讨论它所使用的参数来自内部类Pair (因此可以参考此功能解释我的歧义的推理)。

但仍然;从逻辑上讲,我觉得向static中的方法添加修饰符eq-1不应该生成编译时错误,因为无论调用eq-2中的方法,都应该使用正确的参数调用该方法到eq-2中的方法,应该允许它像静态方法一样被调用。

问题: - 不对该方法使用静态修饰符的解释是什么:

public <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2)

感谢您的帮助。

1 个答案:

答案 0 :(得分:9)

这样做的原因是Util类的类型参数和内部类Pair是非静态的。因为Pair是一个非静态内部类,所以它可以使用Util的T类型参数(即使在这种情况下它不会)。因此,当使用Pair时,必须通过在Util实例的上下文中访问它(T隐式可用)来指定T,或者通过通过特定Util<T>访问它来进行限定。 Util<Integer>.Pair<String,Object>。另一种思考方式是,Pair的类型取决于Util的类型参数,而Util<String>.Pair<K,V>Util<Object>.Pair<K,V>不兼容。

要保持Util上的类型参数T并将Pair保持为非静态内部类,您可以将compare的签名更改为

public static <T, K, V> boolean compare(Util<T>.Pair<K, V> p1, Util<T>.Pair<K, V> p2)

public static <K,V> boolean compare(Util<?>.Pair<K,V> p1, Util<?>.Pair<K,V> p2)

这是可能的,因为T的实例化与方法的主体无关。

作为替代方案,由于Pair不引用Util内部的任何内容(非静态),您可以将Pair的定义更改为

public static class Pair <K, V> { /* ... */ }

最后,为了完整性,如果Util没有类型参数,那么

public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2)

public class Pair<K, V> { /* ... */ }

会没事的。