当前位置: 首页 > 知识库问答 >
问题:

在泛型声明中使用“”extends“时,可以避免Java中的参数不匹配吗?

张坚白
2023-03-14

我正在尝试制作一个处理(可比)元素排序列表的函数。因此,我使用通用

public static <T extends List<? extends Comparable>> T intersect (T A, T B) {
    T C = (T) A.getClass().newInstance();
    int posA = 0;
    int posB = 0;
    while(posA<A.size()&&posB<B.size()) {
        if (A.get(posA).compareTo(B.get(posB))>0) posB++;
        else if (A.get(posA).compareTo(B.get(posB))<0) posA++;
        else if (A.get(posA).equals(B.get(posB))) {
            C.add((Comparable)(A.get(posA)));
            posA++; posB++;
        }
    }
    return C;
}

我应该如何告诉编译器A. get(posA)是有效类型?扩展可比?显然强制转换不起作用,我希望例程接受并返回任意可比对象的列表(整数、字符串、自定义对象等)


共有2个答案

施永贞
2023-03-14

这是一个典型的泛型问题。

您是说您接受扩展可比的每个对象列表。

因此,如果另一个方法将列表传递给您的方法,这将是非常好的。

当然,不应该允许您在代码中将数字添加到该列表中,即使它会扩展可比!

您可以通过向方法签名中添加另一个泛型参数(而不是“?”)来修复代码中的此问题。然后可以在代码中强制转换到该参数。

尚景焕
2023-03-14

难道您没有注意到代码中的所有不安全类型语句,其中包括多个不安全强制转换吗<你真的有很多。这通常意味着总体方法并不正确。

事实上,如果您了解泛型如何在Java中工作,事情就不会那么复杂了
这可以帮助您:

  • https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html

根据您的实际代码,以下是您应该考虑的主要事项:1)不要使用原始类型,例如<代码>列表

通过遵循这些想法,您可以编写如下代码:

public static <T extends Comparable<T>> List<T> intersect (List<T> A, List<T> B) {
    List<T> list = new ArrayList<>();       
    int posA = 0;
    int posB = 0;
    while(posA<A.size()&&posB<B.size()) {
        if (A.get(posA).compareTo(B.get(posB))>0) posB++;
        else if (A.get(posA).compareTo(B.get(posB))<0) posA++;
        else if (A.get(posA).equals(B.get(posB))) {
            list.add(A.get(posA));
            posA++; posB++;
        }
    }
    return list;
}

这是我最初的方法,但这里的问题是,并非所有两个非ArrayList列表的交集都是ArrayList。

如果您为参数声明List,则在编译时不会知道List的类型。因此,您将不可避免地以不安全的强制转换结束。
例如:

@SuppressWarnings("unchecked")
public static <T extends Comparable<T>, L extends List<T>> L intersect(L A, L B)  {

    if (A.getClass() != B.getClass()) {
        throw new IllegalArgumentException("not same type between ...");
    }
    List<T> list = A.getClass()
                    .newInstance(); // uncheck

    int posA = 0;
    int posB = 0;
    while (posA < A.size() && posB < B.size()) {
        if (A.get(posA)
             .compareTo(B.get(posB)) > 0)
            posB++;
        else if (A.get(posA)
                  .compareTo(B.get(posB)) < 0)
            posA++;
        else if (A.get(posA)
                  .equals(B.get(posB))) {
            list.add(A.get(posA));
            posA++;
            posB++;
        }
    }
    return (L) list; // uncheck
}
 类似资料:
  • 当试图将一个对象强制转换为与其实际类型不兼容的类型时,会抛出 ClassCastException 异常。 问题代码如下:

  • 问题内容: 是否可以在String方法中使用默认参数。代码如下所示: 上面的代码生成错误。有可能纠正吗? 问题答案: 不,您通常这样做的方法是重载这样的方法:

  • 这样可以采用类型或类型(但是,我不希望的类型可能是或或在我的程序中没有意义的东西)。 这可能吗?

  • 可以使用泛型将返回类型与参数类型匹配吗? 实例案例: 我有一个抽象类,可以从不同的POJO导入数据,这个类包含一个abstract方法importData。 importData返回的对象必须与传递给该方法的对象类型相同。 由于抽象方法的每个实现的对象类型不同,并且类型不扩展另一个,如何定义抽象方法,以便实现返回类型和传递类型必须匹配? 经过考验: 结果: 方法的返回类型不必与传递的对象类型匹配。

  • 问题内容: 有人可以解释一下这是什么意思吗? 这似乎是一个循环定义,至少可以说让我感到困惑。 问题答案: Java Generics FAQ中 有很好的解释。 从末尾开始: 概括起来,声明可以解密为:是仅可为其子类型实例化的泛型类型,并且这些子类型将继承一些有用的方法,其中一些方法具有子类型特定的参数(否则取决于子类型)。 (尽管我确实很同情-递归的泛型声明很痛苦。但是,我的协议缓冲端口到C#的情

  • 问题内容: 是否可以在Gradle中声明一个可在Java中使用的变量?基本上,我想在build.gradle中声明一些var,然后在构建时(显然)获取它。就像C / C ++中的预处理器宏一样… 一个声明的例子就是这样: 有没有办法做这样的事情? 问题答案: 生成Java常量 你可以使用 产生Android资源 你可以使用或以通常的方式访问它们