Можно ли использовать универсальный тип универсального метода 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)
есть ли способ использовать универсальный тип для принудительного типа всех аргументов метода?
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, так что мы могли только сделать что-то вроде вызоваtoStringonaи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