具有复合键和通配符的 Java 泛型

标签 java generics wildcard

我有一个配对接口(interface),例如

public interface CompositeKeyType<K1, K2> {
    public K1 getKey1();
    public K2 getKey2();
}

以及实现:

package com.bcsg.creditcardrecords;

public class CompositeKeyImplementer<K1, K2> implements
    CompositeKeyType<K1, K2> {

    private K1 key1;
    private K2 key2;

    public CompositeKeyImplementer() {
        this.key1 = null;
        this.key2 = null;
    }

    public CompositeKeyImplementer(K1 key1, K2 key2) throws IllegalArgumentException {
        if (key1.equals(key2)){
            throw new IllegalArgumentException("both keys cannot be equal");
        }
        this.key1 = key1;
        this.key2 = key2;
    }

     @Override
     public K1 getKey1() {
        return this.key1;
    }

    @Override
    public K2 getKey2() {
        return this.key2;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof CompositeKeyImplementer<?, ?>)) {
            return false;
        }

        if (!(((CompositeKeyImplementer<?, ?>)     obj).getKey1().equals(this.key1))
            || !(((CompositeKeyImplementer<?, ?>) obj).getKey2()
                    .equals(this.key2))) {
            return false;
        }
        return true;
    }
}

现在......我还有一个抽象类:

public abstract class AbstractBankCardDetailsHolder<K, V> {

    private NavigableMap<K, V> cardData;

    public AbstractBankCardDetailsHolder() {
        cardData = new TreeMap<K, V>();
    }

    public AbstractBankCardDetailsHolder(K key, V value){
        cardData.put(key, value);
    }

    public NavigableMap<K, V> getCardData(){
        return this.cardData;
    }

    public void setCardData(NavigableMap<K,V> cadData){
        this.cardData.clear();
        this.cardData.putAll(cardData);
    }              
}

我在这里概括一下(它会出现错误):

public class CompositeKeyBasedCreditCardDetailsHolder<? extends K, ? extends V> extends
                AbstractBankCardDetailsHolder<? extends K, ? extends V> {

            private CompositeKeyImplementer<? extends K, ? extends K> numberProviderPair;

            // ....... TBC

}      

我的印象是?通配符意味着?TypeUnknown?它将解析类型@Runtime。然而,我注意到在写这个问题时,我的 CompositeKeyImplementer.java 类的 equals 方法中也有通配符。这是我无法实现的事情吗,因为 JVM 无法在运行时解析不同的通配符排列(例如这个)?

最佳答案

根据我可以从您的示例代码中得出的结果:

1) 您的CompositeKeyImplementer需要通用。它实现了一个通用接口(interface),稍后您将其称为通用类型。

public class CompositeKeyImplementer<K1, K2> implements CompositeKeyType<K, V> {
  ...

2) 您想要 CompositeKeyImplementor<K1, K2>具有 K 子类型的任何类型参数作为 CompositeKeyBasedCreditCardDetailsHolder 中的一个字段类(class)。

因此,您在调用 CompositeKeyImplementor 时使用通配符作为类型参数。您不要在 CompositeKeyBasedCreditCardDetailsHolder 的泛型类型声明中将它们用作类型参数

public class CompositeKeyBasedCreditCardDetailsHolder<K, V> extends
AbstractBankCardDetailsHolder<K, V> {

    private CompositeKeyImplementer<? extends K, ? extends K> numberProviderPair;

    // ....... TBC

}

你的意思是:

  1. 我正在声明一个通用 CompositeKeyBasedCreditCardDetailsHolder带类型参数 K, V .
  2. 该类型有一个名为 numberProviderPair 的字段
  3. 它本身就是一个泛型类型 CompositeKeyImplementer<K1, K2>
  4. 事实上它本身可以是任何 CompositeKeyImplementer<K1, K2>其中类型参数K1, K2K 的子类型(包括)
  5. 即它们的上限由类型参数 K 决定。由 CompositeKeyBasedCreditCardDetailsHolder 定义

请注意 K1, K2 的类型参数不限于同一类型。例如:这是可能的:

// note the arguments for K1, K2. Both extend Number
CompositeKeyImplementer<Integer, Double> cki = 
    new CompositeKeyImplementer<Integer, Double>();
// note the argument for K is Number
CompositeKeyBasedCreditCardDetailsHolder<Number, String> cdh = 
    new CompositeKeyBasedCreditCardDetailsHolder<Number, String>(cki);

我建议(重新)阅读 the java tutorials在通配符上,也可能 Angelika Langer on wildcard type arguments因为他们有很多关于通配符用途和使用方式的信息。

关于具有复合键和通配符的 Java 泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28253016/

相关文章:

c# - 类型 T 的动态通用声明

bash - mv操作中引用通配符

java - 'int' 类型的大数组需要传递给通用数组和集合

java - 嵌入式tomcat与spring集成

java - 如何在 Tomcat 中拥有独立服务?

java - 我的 log4j java.lang.ClassNotFoundException : =org. apache.log4j.RollingFileAppender 问题

c# - 非常奇怪的 C# 泛型问题

class - 当基类隐含时是否应该有关联?

javascript - 可以使用通配符调用 Javascript 中的变量吗?

scala - 在 Scala 中,使用 `_` 和使用命名标识符有什么区别?