Не происходит автораспаковка в методе String.valueOf(), при использовании в качестве аргумента метода - возвращаемое значение обобщенного метода
Когда пытаюсь использовать в качестве аргумента метода String.valueOf(), возвращаемое значение из обобщенного метода <T> T testMet1(int a), то получаю ошибку:
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class [C (java.lang.Integer and [C are in module java.base of loader 'bootstrap') at test.main(test.java:4)`
Исходный код:
class test {
public static void main(String[] args) {
test2 tstOb = new test2();
String tstStr = String.valueOf(tstOb.testMet1(1));
}
}
class test2 {
@SuppressWarnings("unchecked")
<T> T testMet1(int a) {
Integer tstInt = 5;
return (T) tstInt;
}
}
То что возвращает метод <T> T testMet1(int a) можно понять выполнив следующий код:
class test {
public static void main(String[] args) {
test2 tstOb = new test2();
Class tstCl = tstOb.testMet1(1).getClass();
System.out.print(tstCl);
}
}
class test2 {
@SuppressWarnings("unchecked")
<T> T testMet1(int a) {
Integer tstInt = 5;
return (T) tstInt;
}
}
Результат выполнения будет следующий:
class java.lang.Integer
Следовательно метод String.valueOf(tstOb.testMet1(1)) получает объект типа Integer в качестве аргумента и должен вести себя так, как если бы в него напрямую передали данный объект, но такого не происходит.
Ответы (2 шт):
Обобщённый метод всегда возвращает объект и никогда примитив. Из всех перегрузок String.valueOf только две работают с объектами:
public static String valueOf(Object obj) public static String valueOf(char[] data)
Компилятор должен выбрать из них один. По правилам он выбирает наиболее конкретный тип - это char[]. Вы получаете ошибку приведения Integer к char[].
Поправить можно указав нужный тип (Object) явно:
String.valueOf((Object)tstOb.testMet1(1))
P.S. Автораспаковка работает когда известен конкретный целевой тип. В случае String.valueOf конкретный целевой тип не известен (много перегрузок) - автораспаковки не будет.
В данном случае обобщённый тип <T> используется для метода экземпляра класса test2, но сам этот тип остаётся неизвестным для компилятора.
Можно либо указать, что класс test2 является обобщённым и создать сырой экземпляр, как в начальном коде:
class test2<T> {
// ...
}
test2 tstOb = new test2();
String tstStr = String.valueOf(tstOb.testMet1(1));
Также можно указать любой тип (кроме char[]) при вызове метода в необобщённом классе:
String tstStr = String.valueOf(tstOb.<Integer>testMet1(1));
// ...
class test2 {
@SuppressWarnings("unchecked")
<T> T testMet1(int a) {
Integer tstInt = 5;
return (T) tstInt;
}
}
По сути этот тип требуется только для компилятора, а кастинг как таковой выполняться не будет, и будет вызван общий метод String.valueOf(Object o), а не для массива char[].