【问题标题】:Java implicit Generic parameters from superclass来自超类的 Java 隐式通用参数
【发布时间】:2014-08-22 16:05:56
【问题描述】:

编辑:我让这个例子变得更简单了

我想创建一个具有泛型参数的类,该类扩展具有泛型参数 X 的类型,并且我想引用该类型 X 而不明确声明它。

我不确定这是否也回答了这个问题Why can't I use a type argument in a type parameter with multiple bounds?

class Fruit<T> {}

// I don't want to have to redefine T e.g. <F extends Fruit<T>,T>
// because T should be implicit for Fruit (see Example of instance below)
// the below will not compile, but is roughly what I'd like
class Box<F extends Fruit<T>> {
    T get( F fruit ) { return null; }
}

实例示例

class Apple extends Fruit<String>

// this is what I would like, but this won't compile with above definiton
class AppleBox extends Box<Apple> {
    // String get( Apple apple ) should be implicit
}

我不想声明

class AppleBox extends Box<Apple,String>

因为字符串是这里唯一可用的选项,应该隐式知道

【问题讨论】:

    标签: java


    【解决方案1】:

    Fruit 类内的泛型类型的范围在 Fruit 类本身内。该泛型类型变量无法在类之外访问。

    因此,您必须定义 T 来代替泛型类型,并且由于您在其他地方使用变量 T,因此您也不能将其省略。

    所以重申一下 Fruit 中的类型 T 仅在类型 fruit 中可见,因此要在 Box 中使用它,您需要在某处再次定义该类型:

    public class Outer {
    
      class Fruit<T> {
        T body;
      }
    
      abstract class Box<F extends Fruit<T>, T> {
        abstract T get( F fruit );
      }
    }
    

    如果您希望 T 对 Fruit 隐含,则不要在 Fruit 类中定义泛型参数 T,而是在外部类中定义。

    public class Outer<T> {
    
      class Fruit {
        T body;
      }
    
      abstract class Box<F extends Fruit> {
        abstract T get( F fruit );
      }
    }
    

    这个范围问题的一个类比是下面的代码:

    for (int i = 0; i < 10; i++) {
      // stuff
    }
    for (int i = 0; i < 20; i++) { // i from previous loop is not visible here
      // stuff
    }
    System.out.println(i); // variable not defined: i
    

    【讨论】:

    • 泛型类型的范围在类内,但我相信任何可以看到类定义的人都可以看到
    • No 即使Box在水果旁边,也看不到水果的类型t。
    【解决方案2】:

    解决方案编辑:

    interface Fruit<T> {
        T get();
    }
    
    class Box<F extends Fruit<?>> {
    
        <R> R get(F fruit) { 
            @SuppressWarnings("unchecked")
            R ret = (R) fruit.get();
    
            return ret;
        }
    }
    
    class Apple implements Fruit<String> {
        @Override
        public String get() {
            return "Apple";
        }
    }
    
    class Something implements Fruit<String> {
        @Override
        public String get() {
            return "Something";
        }
    }
    
    //this is what I would like, but this won't compile with above definiton
    class AppleBox extends Box<Apple> {
        // ...
    }
    
    class Main {
        public static void main(String[] argv) {
    
            Apple apple = new Apple();
            Something something = new Something();
    
            AppleBox ab = new AppleBox();
    
            System.out.println( ab.get(apple) );
            // this will fail
            System.out.println( ab.get(something) );)
        }
    }
    

    如果你想要更多关于 Box.get() 返回类型的类型安全性,只需使用静态方法,因为上面的 Box.get() 返回 Object,而不是 T。

    interface Fruit<T> {
        T get();
    }
    
    class Box<F extends Fruit<?>> {
    
        <R> R get(F fruit) { 
            @SuppressWarnings("unchecked")
            R ret = (R) fruit.get();
            return ret;
        }
    
        public static <P, Q extends Fruit<P>> P get(Box<Q> box, Q fruit) {
            return box.get(fruit);
        }
    }
    
    class Apple implements Fruit<String> {
        @Override
        public String get() {
            return "Apple";
        }
    }
    
    class Something implements Fruit<String> {
        @Override
        public String get() {
            return "Something";
        }
    }
    
    //this is what I would like, but this won't compile with above definiton
    class AppleBox extends Box<Apple> {
        // ...
    }
    
    class Main {
        public static void main(String[] argv) {
    
            Apple apple = new Apple();
            Something something = new Something();
    
            AppleBox ab = new AppleBox();
    
            System.out.println( AppleBox.get(ab, apple) );      
            System.out.println( AppleBox.get(ab, something) );  // this will fail
    
            Apple p = AppleBox.get(ab, apple); // fail: return type mismatch
        }
    }
    

    【讨论】:

    • 不完全是,我应该规定 inspectEngine 是抽象的,暗示它要在进一步的类中实现,他们不应该选择实现返回与其 Car 类型不匹配的 Engine 类型
    • 我修改了上面的答案。我认为这将是最符合您需求的解决方案。
    猜你喜欢
    • 2012-05-12
    • 2012-04-08
    • 1970-01-01
    • 1970-01-01
    • 2016-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多