可以使用通用Java方法的泛型类型来强制执行参数类型吗?

时间:2015-05-13 14:03:31

标签: java generics types

我想使用泛型类型来确保方法的参数类型相同,如下所示:

public static <T> void x(T a, T b)

我认为传递给此方法的两个参数(a和b)必须始终具有相同的类型。但令我惊讶的是,我能够将任何类型的参数(甚至原语)传递给方法x,就像T被擦除为Object一样,无论传递什么参数。

到目前为止我发现的唯一解决方法是使用&#39; extends&#39;像这样:

public static <T, U extends T> void x(T a, U b)

但是虽然我能忍受它,但这不是我想要的。

有没有办法使用泛型类型来强制方法的所有参数的类型?

6 个答案:

答案 0 :(得分:29)

如果我理解正确,一种方法是explicitly specify the type of T而不是让编译器推断它的类型是最直接的超类,如果两个不同类型的对象作为参数传入。拿这样的东西,例如:

public class Test {
    public static void main(String[] args) {
        Test.x(5.0, 5);          // This works since type is inferred to be Number
        Test.<Integer>x(5, 5);   // This works since type is stated to be Integer
        Test.<Integer>x(5.0, 5); // This doesn't; type is stated to be Integer and Double is passed in
    }

    public static <T> void x(T a, T b) {
    }
}

答案 1 :(得分:21)

如果我理解你的问题,你想要这个:

x(10, "x");

在编译时失败。 现在考虑这样做:

Integer i = 10;
String s = "x";
Object o1 = i;
Object o2 = s;
x(o1, o2);

在这种情况下,它们都是对象 - 相同的类型。我认为没有任何方法可以真正强制执行您想要的操作 - 当您将参数转换为Object时,始终可以使用两种不同的类型调用它而不会出现任何警告/错误。

您可以像这样使用它来指定要使用的类型:

ClassName.<Type>x(obj1, obj2);

这可能是唯一的方法。

答案 2 :(得分:14)

为什么这首先成为问题对我来说有点模糊。我怀疑你反而误解了类型系统有用的方法。

<T> void x(T a, T b)我们可以做些什么?嗯,不是很多。在x的正文中,TObject相同,因此我们只能在toStringa上执行类似调用b的操作打印它们。

确实没有实际的原因 ab必须具有相同的类型。只是他们有一些共同的类型,那个类型是Object或它的子类型。事实上,<T> void x(T a, T b)实际上根本不需要是通用的,没有明确的理由。

  • 方法正文并不关心ab的实际类型,因为它无论如何也无法使用它们。
  • 呼叫网站并不关心ab的实际类型,因为x是一种void方法,所以它是黑色的孔。

获得结果的方法更为典型,例如<T> List<T> Arrays.asList(T...)

// This will cause a compile error because
// the type inferred must be compatible
// with the return assignment.
List<Integer> r = Arrays.asList(1, 1.0);

或绑定:

// We don't care what the actual types of
// a and b are, just that we can call bar()
// on them.
// Note: this method does not need to be generic.
<T extends Foo> void x(T a, T b) {
    a.bar();
    a.bar();
}

或者断言某种关系的界限:

// We don't care what the actual types of
// a and b are, just that we can compare
// them to each other.
<T extends Comparable<T>> T max(T a, T b) {
    return (a.compareTo(b) < 0) ? b : a;
}

答案 3 :(得分:12)

调用方法时,可以显式指定类型参数。例如:

 <String>x("hello", "world");

但是,如果你没有明确指定type-parameter并且只依赖于Java的类型推断功能,那么我认为你不仅可以泛型,但总的来说。

方法参数的类型不是具体类型,而是表示 适用类型集 的东西(即使这个< em> set 只能包含一种类型,例如final类。

例如,这种方法:

public void x(Something a) { }

表示一个方法,该参数应该是类型的类型,它与Something(即Something及其所有子类型)兼容。 / p>

同样适用于泛型。

答案 4 :(得分:10)

据推测,您并未以通用方式调用泛型方法,因此将其视为对x(Object a, Object b)的调用。在这个例子中:

public class Test {

  static <T> void x(T a, T b) {
  }

  public static void main(String[] args) {
    x(1, 2); // compiles
    Test.<String>x(1, 2); // does not compile
    Test.<String>x("a", "b"); // compiles
  }
}

第一次调用x并不是一般的,所以它编译。第二个调用将T等同于String,因此失败,因为12不是Strings。第三个调用编译因为它正确传入Strings

答案 5 :(得分:7)

这对我有用

public static <T> void x(T a, T b, Class<T> cls) {
}

现在编译

public static void main(String[] args) throws Exception {
    x(1, 2, Integer.class);
}

这不是

public static void main(String[] args) throws Exception {
    x(1, "", Integer.class);
}