java Перегрузка методов и generic

144
01 марта 2018, 12:45

У меня есть следующий код:

import java.util.*;
public class Exmp {
    public static void main(String[] args) {
        List<Integer> integerList = Arrays.asList(1,2,3);
        Gen gen = new Gen();
        gen.m(integerList);
    }
    static class Gen<T>{
        <T> void m(Collection<T> collection){
            for (T s: collection) {
                System.out.println(s);
            }
        }
        void m(List<String> list){
            for (String s: list) {
                System.out.println(s);
            }
        }
    }
}

Никак не могу понять почему вызывается метод со списком строк. Может кто ткнет носом?

Answer 1

Это поведение действительно является наследием до-дженериковой эры и относится к т.н. raw type:

To facilitate interfacing with non-generic legacy code, it is possible to use as a type the erasure (§4.6) of a parameterized type (§4.5) or the erasure of an array type (§10.1) whose element type is a parameterized type. Such a type is called a raw type.

More precisely, a raw type is defined to be one of:

  • The reference type that is formed by taking the name of a generic type declaration without an accompanying type argument list.

  • An array type whose element type is a raw type.

  • A non-static member type of a raw type R that is not inherited from a superclass or superinterface of R.

JLS 4.8

Raw type - это дженерик, использованный без указания типов; в данном случае raw type - это Gen<T>, который вы создаете как просто Gen. Т.к. вы не указываете тип, компилятор обрабатывает этот класс по-другому, "сбрасывая" всю generic-информацию, которую может найти:

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

JLS 4.8

В том числе сбрасывается информация о List<String> и Collection<T>, методы теперь выглядят как просто m(List) и m(Collection). При выборе из этих двух методов компилятор выберет более подходящий - m(List), и получится ровно та ситуация, которую мы наблюдаем. Чтобы избежать этого, достаточно вывести Gen из-под понятия "raw type" - это можно сделать, либо указав произвольный тип (хватит даже Gen<?>), либо вообще его убрав - у вас и так параметризованный метод, поэтому параметр класса в принципе не нужен.

READ ALSO
Обработка NaN и Infinite при вычислении в Java

Обработка NaN и Infinite при вычислении в Java

Есть метод для возведения числа в степень

157
Правильно распарсить файл

Правильно распарсить файл

Есть такая программа, которая парсит файл и вытаскивает из нее нужные данные (Вопрос, ответы и категории) и полученные данные выгружает в ExcelНо...

202
Ошибка AudioRecord и запись потока в файл в Android

Ошибка AudioRecord и запись потока в файл в Android

При нажатии кнопки StartRead вылетает с ошибкойВ чем проблема? И еще вопрос, как эти данные из потока записать в музыкальный файл?

164
Вызов glCallList в list compile

Вызов glCallList в list compile

Можно ли вызывать прорисовку скомпилиного листа glCallList между glNewList(list, GL_COMPILE) и glEndList()? Не будет ли ошибка?

169