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

sys*_*738 55 java generics types

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

public static <T> void x(T a, T b)
Run Code Online (Sandbox Code Playgroud)

我假设传递给此方法的两个参数(a和b)总是必须是相同的类型.但令我惊讶的是,我能够将任何类型的参数(甚至原语)传递给方法x,就好像T被擦除为Object,无论传递什么参数.

到目前为止,我发现的唯一解决方法是使用'extends',如下所示:

public static <T, U extends T> void x(T a, U b)
Run Code Online (Sandbox Code Playgroud)

但是虽然我可以忍受它,但这不是我想要的.

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

TNT*_*TNT 30

如果我理解正确,一种方法是显式指定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) {
    }
}
Run Code Online (Sandbox Code Playgroud)


bar*_*s2x 22

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

x(10, "x");
Run Code Online (Sandbox Code Playgroud)

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

Integer i = 10;
String s = "x";
Object o1 = i;
Object o2 = s;
x(o1, o2);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它们都是对象 - 相同的类型.我认为没有办法真正实现你想要的东西 - 当你将你的参数转换为Object时,总是可以用两种不同的类型调用它而不会有任何警告/错误.

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

ClassName.<Type>x(obj1, obj2);
Run Code Online (Sandbox Code Playgroud)

它可能是唯一的方法.


Rad*_*def 14

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

我们可以做些什么<T> void x(T a, T b)?嗯,不是很多.身体内部x,T是一样的Object,所以我们只能做一些事情,如呼叫toStringab打印它们.

实际上没有任何实际原因 a,b必须具有相同的类型.只是他们有一些共同的类型,那个类型Object或它的子类型.事实上,没有明确的理由说明为什么<T> void x(T a, T b)实际上需要通用.

  • 该方法的主体不关心实际的类型ab是因为它无论如何也使用它们.
  • 呼叫网站不关心实际的类型是什么a以及b是因为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);
Run Code Online (Sandbox Code Playgroud)

或绑定:

// 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();
}
Run Code Online (Sandbox Code Playgroud)

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

// 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;
}
Run Code Online (Sandbox Code Playgroud)


Kon*_*kov 12

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

 <String>x("hello", "world");
Run Code Online (Sandbox Code Playgroud)

但是,如果您没有明确指定type-parameter并且仅依赖于Java的类型推断功能,那么我认为您不仅可以在泛型中使用,而且通常也可以.

方法参数的类型不是具体类型,而是表示一组适用类型的东西(例如,在类的情况下,该集合只能包含一种类型final).

例如,这种方法:

public void x(Something a) { }
Run Code Online (Sandbox Code Playgroud)

表示一种方法,该参数应该是来自类型集的类型,其与Something(即Something及其所有子类型)兼容.

同样适用于泛型.


Gri*_*Dog 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
  }
}
Run Code Online (Sandbox Code Playgroud)

对x的第一次调用不是一般的,所以它编译.第二个调用等同TString,因此失败因为12不是Strings.第三个调用编译因为它正确传入Strings.


Evg*_*eev 7

这对我有用

public static <T> void x(T a, T b, Class<T> cls) {
}
Run Code Online (Sandbox Code Playgroud)

现在这个编译

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

而这不是

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

  • @Radiodef,但在这种情况下,两个args都是对象 (2认同)
  • 是的,但是,重点仍然是它不会强迫`a`和`b`具有相同的类型.这仍然是不可能的.我们仍然可以通过我们想要的任何东西. (2认同)