【问题标题】:Why can't I statically reference an inner class's static method on a generic class?为什么我不能在泛型类上静态引用内部类的静态方法?
【发布时间】:2014-07-13 00:09:03
【问题描述】:

请浏览整个问题以获得完整的想法。

首先让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) 

然后编译器会抱怨 不能对非静态类型 Pair 进行静态引用,而类似的方法

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

这也是静态的,但不会抱怨。即使我们在butbig but 两种方法中都没有使用类型参数&lt;T&gt;,但在我们从eq-1 谈论的方法中,它使用的参数来自内部类Pair(因此可以解释我的模棱两可的原因参考此功能)。

但还是;从逻辑上讲,我觉得在eq-1 中的方法中添加修饰符static 不应该产生编译时错误,因为无论在哪里调用eq-2 中的方法,该方法都将负责以正确的参数调用eq-2 中的方法并且应该允许像静态方法一样调用它。

问题:- 方法中不使用 static 修饰符的解释是什么:

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

感谢您的帮助。

【问题讨论】:

    标签: java generics static inner-classes


    【解决方案1】:

    原因是 Util 类的类型参数和内部类 Pair 是非静态的。因为 Pair 是一个非静态内部类,它可以使用 Util 的 T 类型参数(尽管在这种情况下它没有)。因此,当使用 Pair 时,有必要指定一个 T,或者通过在 Util 实例的上下文中访问它(其中 T 是隐式可用的),或者通过通过特定的Util&lt;T&gt; 访问它来限定它,例如Util&lt;Integer&gt;.Pair&lt;String,Object&gt;。另一种理解是Pair的类型取决于Util的类型参数,Util&lt;String&gt;.Pair&lt;K,V&gt;Util&lt;Object&gt;.Pair&lt;K,V&gt;不兼容。

    要在 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> { /* ... */ }
    

    会很好的。

    【讨论】:

    • ,谢谢伙计。我相信你几乎涵盖了所有部分。我有一种解决问题的方法,但你给出的保持类型参数 T 的第一个解释部分消除了我的疑问。但是我仍然无法理解编译器抱怨没有使用静态修饰符。你说引用 因此必须在有特定 T 可用的上下文中使用 Pair 取消引用。正如我在我的问题中所说(我相信,我可能错了),在创建 Pair 类的对象时,T 信息将可用(在方法 中) main1() 这是非静态的)。
    • 正如我上面所说的调用方法 main1() 需要参数(值)来输入参数,因此类 Pair 的对象将自动具有 b>T ,类 Pair 的对象可以使用(即使在这里他们没有使用)。因此,请在此处阐明这个问题,以便消除我的困惑。
    • @zeal 你说得对,有点不清楚,我改变了答案的那句话。希望它现在更有意义。我还添加了一些关于以前缺少的通用通配符的注释。
    • 感谢 Geoff,编辑(使用通配符>)确实有助于消除疑虑,甚至使用 Util. 作为前缀 Pair 现在有意义了。再次非常感谢您。
    猜你喜欢
    • 2018-09-20
    • 1970-01-01
    • 2021-11-06
    • 2010-11-01
    • 1970-01-01
    • 2015-10-07
    • 2010-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多