Можно ли использовать универсальный тип универсального метода Java для принудительного применения типа аргументов?



Я хотел бы использовать универсальный тип, чтобы убедиться, что аргументы метода имеют один и тот же тип, например:



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


Я бы предположил, что два аргумента (a и b), которые передаются этому методу, всегда должны быть одного и того же типа. Но к моему удивлению я смог передать аргументы любого типа (даже примитивы) в метод x, как будто T стирается в объект, независимо от того, какие аргументы передаются.



единственная работа вокруг я нашел до сих пор, чтобы использовать расширяется такой:



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




есть ли способ использовать универсальный тип для принудительного типа всех аргументов метода?

586   6  

6 ответов:

Если я правильно понял ваш вопрос, вы хотите этого:

x(10, "x");

сбой во время компиляции. Теперь подумайте об этом:

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

в данном случае это оба объекта - одного типа. Я не думаю, что есть какой - либо способ действительно обеспечить то, что вы хотите-когда вы бросаете свой аргумент в объект, всегда можно вызвать его с двумя разными типами без каких-либо предупреждений/ошибок.

вы можете указать тип, который вы хотите использовать, используя его как это:

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

и это, вероятно, единственный способ сделать это.

Если я правильно понял, один из способов сделать это - явно укажите тип 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) {
    }
}

почему это должно быть проблемой в первую очередь, для меня туманно. Я подозреваю, что вы вместо этого неправильно поняли что-то о том, как система типов полезна.

что мы можем сделать с <T> void x(T a, T b)? Ну, не совсем много. Внутри тела x,T это то же самое, что Object, так что мы могли только сделать что-то вроде вызова toString on a и b печатать их.

там действительно нет практической причинаa и b должен иметь тот же тип. Просто у них есть какой-то общий тип, и этот тип Object или его подтип. На самом деле, нет никакой ясной причины, почему <T> void x(T a, T b) на самом деле должен быть общим вообще.

  • тело метода не заботится о том, что фактические типы a и b потому что он не мог использовать их в любом случае.
  • сайт вызова не заботится о том, какие фактические типы 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);

или связанный:

// 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;
}

при вызове метода можно явно указать параметр type. Например:

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

однако, если вы не укажите тип-параметр явно и полагайтесь только на функцию вывода типа Java, тогда я не думаю, что вы можете, не только в дженериках, но и в целом.

тип параметра метода не является конкретным типом, но это скорее то, что обозначает набор применимых типов (даже этот set может состоять только из одного типа, в случае final классы, например).

например, такой способ:

public void x(Something a) { }

обозначает метод, параметр которого должен иметь тип из набор типов, которые совместимы с Something (т. е. Something и все его подтипы).

то же самое относится и к дженерикам.

предположительно, вы не вызываете свой общий метод в общем виде, поэтому он рассматривается как вызов 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, Так что это не удается, потому что 1 и 2 не Strings. Третий вызов компилируется, потому что он правильно проходит в Strings.

Это сработало для меня

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);
}

Comments

    Ничего не найдено.