【问题标题】:Is it better to use generics or Object type for a static helper class in Java?在 Java 中使用泛型或对象类型作为静态帮助器类更好吗?
【发布时间】:2015-06-19 04:56:56
【问题描述】:

前几天我正在编写一个程序,要求我:获取ArrayList<String> 中特定对象的频率,删除给定项目的所有出现等,等等。List 接口未指定.我决定编写自己的辅助类,并希望使其尽可能可重用。我决定将List 指定为集合的参数类型,这样我就可以将它用于任何实现List 接口的类。但是这些类通常是使用泛型定义的,我不知道要删除的项目是什么类类型。所以我要么必须定义静态辅助方法,因为静态类不能显式包含泛型类型,要么将要删除的对象的类类型定义为Object。我以两种方式实现了它,见下文,但我想知道使用其中一种方式是否有任何好处。

关于该主题的一些进一步问题:

  1. 为什么我可以通过在方法头而不是类头中定义泛型类型来解决静态上下文中的泛型引用?
  2. 当使用这个静态方法时,为什么我必须在其使用中声明类Type?即ListTools_V2.getFrequencyOf(ArrayList<String> items, String s) 仍然有效。

使用 Object 类类型实现

import java.util.List;

/** General utility class for performing frequently needed operations
    on any class implementing the List interface **/ 
public class ListTools {

    public static void removeAllOccurrences(List items, Object o) {
        while(items.contains(o)) {
            items.remove(o);
        }
    }

    public static int getFrequencyOf(List items, Object o) {
        int frequency = 0;
        for(Object item : items) {
            if(item.equals(o)) {
                frequency++;
            }
        }
        return frequency;
    }

}

使用泛型实现

import java.util.List;

/** General utility class for performing frequently needed operations
    on any class implementing the List interface. This implementation
    uses generics to maximize reusability. **/ 
public class ListTools_V2 {

    public static <E> void removeAllOccurrences(List<E> items, E o) {
        while(items.contains(o)) {
            items.remove(o);
        }
    }

    public static <E> int getFrequencyOf(List<E> items,E o) {
        int frequency = 0;
        for(E item : items) {
            if(item.equals(o)) {
                frequency++;
            }
        }
        return frequency;
    }

}

【问题讨论】:

标签: java list object generics


【解决方案1】:

这两个操作都在给定对象引用和列表内元素之间的相等 (.equals()) 上进行操作,并且相等不限于相同类型的对象,因此您不应将 o 限制为相同type 作为列表的类型参数。

但是,原始类型不好,因此您不应该使用原始类型List。当不需要针对任何东西约束类型变量时,您应该使用通配符对其进行参数化:

public static void removeAllOccurrences(List<?> items, Object o)
public static int getFrequencyOf(List<?> items, Object o)

【讨论】:

    【解决方案2】:

    Generic 更好,因为它会在编译时检测类型相关问题。
    在运行时“擦除”发生并且泛型没有“意义”。

    例如:

    List apples = new ArrayList();
    apples.add(new Apple());
    apples.add(new Mango()); //compiles, but this is wrong
    apples.add(new Chair()); //compiles, but this is wrong
    



    您当然必须意识到通用机制的各种“陷阱”。 我很容易想到的例子是:
    List&lt;Mango&gt; 不扩展 List&lt;Fruit&gt; ,所以你应该使用 List&lt;? super Fruit&gt;List&lt;? extends Fruit&gt;

    你不能这样做:

    T.getClassName()
    

    【讨论】:

    • 由于您可能会遇到运行时问题,如果您要尝试执行检索到的对象的转换,例如 - 访问苹果列表,尝试获取对象,将其转换为 Apple,以及有 ClassCastException 因为错误地添加了芒果。如果使用泛型,此类错误将在编译时避免。
    • 本题没有检索。
    【解决方案3】:

    泛型是实现此类类的推荐方式。它们可用于向您的用户(使用此类的任何人)提供一些隐式信息。 例如:

    List<Cat> cats = ...;
    ListTools.removeAllOccurrences(cats, new Dog());
    

    这是没有意义的,因为猫列表中不能有任何狗。但是用户可以执行这段代码并想象他已经从猫列表中删除了一些狗。另一方面,通用版本会通知用户这个不恰当的调用。

    List<Cat> cats = ...;
    ListTools_V2.removeAllOccurrences(cats, new Dog()); // Compile time error because it is pointless
    

    此外,还有性能提升。如果猫列表包含数千只猫,你真的要在大量的猫列表中搜索那条狗吗? (contains 方法实际上是搜索整个列表)还是只是想在编译时避免它? ;)

    【讨论】:

    • “没有意义,因为猫列表中不能有任何狗。”不对。 Dog 可以等于(如在.equals() 中)与Cat,这取决于DogCat 是如何实现的,并且对于删除而言,平等很重要。
    • 你是对的。我没有提供 Cat 和 Dog 的代码,假设它们完全是两个不同的类。
    【解决方案4】:

    您的 getFrequencyOf() 方法主体在这两种情况下基本相同,除了在一种情况下您传递原始 List 而在另一种情况下您将其参数化以接受任何类型。

    1-

    public static int getFrequencyOf(List items, Object o) {
            int frequency = 0;
            for(Object item : items) {
                if(item.equals(o)) {
                    frequency++;
                }
            }
            return frequency;
        }
    

    这里的 List 是一个原始类型。对泛型类型 List 的引用应该被参数化,而不是。但它适用于任何类型的列表(整数、长整数、字符串等)

    2-

    public static <E> int getFrequencyOf(List<E> items,E o) {
            int frequency = 0;
            for(E item : items) {
                if(item.equals(o)) {
                    frequency++;
                }
            }
            return frequency;
        }
    

    这里的 List 不是原始类型。对泛型类型 List 的引用应该被参数化,它是。这也适用于任何类型的列表(整数、长整数、字符串等)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-15
      • 1970-01-01
      • 1970-01-01
      • 2011-05-31
      相关资源
      最近更新 更多