Java 确定泛型类中列表的类类型

问题描述 投票:0回答:2

我是 Java 泛型的新手,我目前一直在确定列表中 Pair 对象(apache 的)的类型。

我有两个类 A 和 B,它们都有一个方法执行完全相同的操作(代码重复)。

方法是这样的:

private List<Pair<String, A>> deduplicateItems(List<Pair<String, A>> list) {
   
   List<Pair<String, A>> deduplicatedItems = new ArrayList<>();
   list.forEach(item-> {
     //do something
     deduplicatedItems.add(item);
   });

}

完全相同的方法在B类中(Value in Pair的类型是B)。

我想创建一个通用的抽象类来处理这个操作。

我到目前为止:

public abstract class AbstractHelper<V> {
     
      private List<Pair<String, V>> deduplicateItems(List<Pair<String, V>> list) {
      
      List<Pair<String, V>> deduplicatedItems = new ArrayList<>();
    
      //problem here determining the type of class for this generic
   });

      }
}

我想确定 V 的类型并将其转换为能够访问 get() 方法。

使用

list.get(0) instanceof A
是正确的做法吗?我觉得这可能太天真了,但我在这里可能是错的。

java generics abstract-class
2个回答
0
投票

使方法通用:

private <T> List<Pair<String, T>> deduplicateItems(List<Pair<String, T>> list) {
   List<Pair<String, T>> deduplicatedItems = new ArrayList<>();
   list.forEach(item-> {
     //do something
     deduplicatedItems.add(item);
   });
   return deduplicatedItems;
}

如果 A 和 B 都实现了相同的接口或扩展了一个共同的父类,并且您希望“做某事”以这种方式与元素交互,请在 T 上设置一个界限:

private <T extends MyCommonType> List<Pair<String, T>> deduplicateItems(List<Pair<String, T>> list) {

0
投票

你不应该检查类型。你绝对不应该写像

if (element instanceof A) { } else if (element instanceof B) { } else if
之类的东西

问题是你的方法不知道如何检查类型 V 的两个实例是否相等。由于您的方法没有该信息,您应该强制调用者提供该信息:

private List<Pair<String, V>> deduplicateItems(
                    List<Pair<String, V>> list,
                    BiPredicate<? super V, ? super V> equalityChecker) {

    List<Pair<String, V>> deduplicatedItems = new ArrayList<>();
    List<V> existingValues = new ArrayList<>();

    for (Pair<String, V>> pair : list) {
        V value = pair.getValue();
        if (existingValues.stream().noneMatch(
            v -> equalityChecker.test(v, value)) {

            existingValues.add(value);
            deduplicatedItems.add(pair);
        }
    }

    return deduplicatedItems;
}

BiPredicate 是一个测试两个值并返回基于它们的布尔值的接口。一个示例用法可能是:

List<Pair<String, String>> numbers = new ArrayList<>();
numbers.add(Pair.of("1", "ONE"));
numbers.add(Pair.of("1", "one"));
numbers.add(Pair.of("2", "TWO"));
numbers.add(Pair.of("2", "two"));
numbers.add(Pair.of("3", "THREE"));
numbers.add(Pair.of("3", "three"));

List<Pair<String, String>> uniqueNumbers =
    deduplicateItems(numbers, String::equalsIgnoreCase);

如果 V 将代表的每个类都定义了可靠的 equals 方法,则不需要第二个参数,并且可以使用 Set 来更有效地检查重复值:

private List<Pair<String, V>> deduplicateItems(List<Pair<String, V>> list) {

    List<Pair<String, V>> deduplicatedItems = new ArrayList<>();
    Set<V> existingValues = new HashSet<>();

    for (Pair<String, V>> pair : list) {
        if (existingValues.add(pair.getValue())) {
            deduplicatedItems.add(pair);
        }
    }

    return deduplicatedItems;
}

上面的工作因为Set.add方法保证了:

退货:

true
如果这个集合还没有包含指定的元素

当然,你也可以同时定义上面的两个deduplicateItems方法,让调用代码决定在给定的情况下哪个合适。

© www.soinside.com 2019 - 2024. All rights reserved.