微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在接口中使用泛型

如何解决如何在接口中使用泛型

我对编程还很陌生,我们有一个练习,我们必须使用 Consumer 接口,我们有一个具有 Consumer<T> 属性 (conAtt) 的通用类 (genClass)。在另一个类中,我们必须使用Consumer 的accept 方法,但不知何故它不起作用。我已经通读了 Consumer 接口的 Java API,但没有帮助。

错误信息说:

The method accept(capture#4-of ?) in the type Consumer<capture#4-of ?> is not applicable for the arguments (capture#5-of ?)

我知道它说不适用,但为什么不适用?

    public abstract class GenClass<T> {
        protected Consumer<T> conAtt;
        public abstract T getData();
    }
    
    class Otherclass{
        private List<GenClass<?>> helparray= new ArrayList<>();
    
    private void testmethod() {
            Iterator<GenClass<?>> hilfe = helparray.iterator();
            while (hilfe.hasNext()) {
                GenClass<?> help = hilfe.next();
                help.conAtt.accept(help.getData());//here is the problem
            }
        }
    }

public class thirdclass extends GenClass<Character> {

    @Override
    public Character getData() {
        return 't';//t is just an example

    }

}

解决方法

这实际上不是关于 Java 中的 Consumer 或其他接口如何工作的问题,而是关于 Generics 的问题。

泛型旨在简化编写代码的方式并避免代码重复。例如。您需要执行类似的任务,但对于不同的类型,您可以使用 Generics 编写一次,而不是一遍又一遍地编写,只需替换具体类型即可。

例如,有一天您需要跟踪 Strings 的列表。就这么简单,您继续并为此实施一个解决方案,其中第一个实施可能如下所示(注意:一个非常简化的示例,但它会显示目的):

public class CustomListString {

    private String[] elements = new String[10];
    
    public void add(String newElement) {
        int nextFreeIndex = findNextFreeIndex();
        elements[nextFreeIndex] = newElement;
    }
    
    public String get(int index) {
        return elements[index];
    }
}

因此,您可以在代码中使用上述 List 的实现,如下所示:

public static void main(String[] args) {
    CustomListString listOfStrings = new CustomListString();
    listOfStrings.add("A");
    listOfStrings.add("B");
}

简单、具体、充分!

但前几天,您还需要跟踪 Integers 的列表。现在该怎么办?

解决此问题的一种方法是重复您之前的方法,现在仅为 CustomList 实现另一个 Integers。相应的实现如下所示(CustomListString 的实现已被复制,所有出现的 String 已被 Integer 替换):

public class CustomListInteger {

    private Integer[] elements = new Integer[10];
    
    public void add(Integer newElement) {
        int nextFreeIndex = findNextFreeIndex();
        elements[nextFreeIndex] = newElement;
    }
    
    public Integer get(int index) {
        return elements[index];
    }
}

正如您现在已经可以想象的那样,这不灵活,将来可能会非常麻烦。这种方法将需要您将来要存储的每种类型的新实现。因此,您最终可能还会创建 CustomListDoubleCustomListCharacter、... 等实现,其中只有数组中元素的类型发生变化 - 没有其他重要的东西!

这还会导致这种情况,即您将复制大量类似的代码(如 findNextFreeIndex() 方法),并且在修复错误的情况下需要在很多地方对其进行调整,而不是只有一个。

为了解决这个问题并保持 CustomList.get 方法中的类型安全Generics 已被引入 Java!

使用 Generics 方法,您将能够创建 CustomList 的单一实现来存储所有数据类型,而无需重复任何共享的基本代码并保持类型安全

public class CustomList<T> {

    private Object[] elements = new Object[10]; // Java doesn't supprort easily support generic arrays,so using Object
                                                // here. But the compiler ensures only elements of the generic type T
                                                // will end up here

    public void add(T newElement) {
        int nextFreeIndex = findNextFreeIndex();
        elements[nextFreeIndex] = newElement;
    }

    @SuppressWarnings("unchecked")
    public T get(int index) {
        return (T) elements[index];
    }
}

按照 Generics 方法使用新列表,我们现在可以像这样使用它:

public static void main(String[] args) {
    CustomList<String> genericList = new CustomList<>();
    genericList.add("Hello World");
    genericList.add(5); // Compile error! Integer and String types cannot be mixed in
                        // a single instance of the list anymore => Nice,prevents errors!
    
    genericList.get(0).substring(6); // No compile error,also the compiler knows Strings
                                     // are contained in the list
}

泛型 CustomList 现在也可以重用于任何其他类型,并且仍然提供类型安全


这对您的实施意味着什么

您可以看到我们如何将 CustomList 类中的泛型类型指定为 T - 这类似于您使用 ? 指定它(可能您还想用 T 替换它,因为您稍后在使用 Consumer 时会遇到其他问题)。但是当我们在其他类中使用该实现时,就不可能再将其指定为 CustomList<T>CustomList<?>。我们需要决定并指定列表应该包含哪种确切类型的元素。这是 String 类,因此我们将其指定为 CustomList<String>

注意: ? 是一个通用通配符,意思是“我现在不知道类的真正类型,但我也会以后不知道了”。这就是为什么您很难在 Consumer 后面使用具体类型的原因。您将无法在其中的对象上调用任何具体方法。因此,应避免将 ? 作为泛型类型参数,而应使用诸如 T 之类的东西。 T 的意思是“我现在不知道类的真正类型,但稍后我会知道,只要你告诉我”。因此,您可以稍后在 Consumer 中对对象调用具体方法,这将大大简化您的工作。

对于您的代码,这意味着,无论您想在何处使用 GenClass<T> 的实现,您都需要指定该类将使用哪种确切类型的元素。在 String 的情况下,在 GenClass<String> Character 的情况下为 GenClass<Character>

因此,您需要替换出现的 GenClass<?> 的地方是您在 OtherclassOtherclass.testmethod 中引用它的任何地方。

您使用 Consumer 的方式很好

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。