Не происходит автораспаковка в методе String.valueOf(), при использовании в качестве аргумента метода - возвращаемое значение обобщенного метода

Рейтинг: 3Ответов: 2Опубликовано: 04.06.2023

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

Ответы

▲ 3Принят

Обобщённый метод всегда возвращает объект и никогда примитив. Из всех перегрузок 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 конкретный целевой тип не известен (много перегрузок) - автораспаковки не будет.

▲ 1

В данном случае обобщённый тип <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[].