Вызов неоднозначно перегруженного конструктора в Java - PullRequest
2 голосов
/ 17 апреля 2011

Я только что увидел этот вопрос C # и подумал, может ли что-то подобное случиться в Java. Может, с

class A<T> {
    A(Integer o) {...}
    A(T o) {...}
}

звонок

new A<Integer>(43);

неоднозначно, и я не вижу способа как это решить. Есть ли?

Ответы [ 3 ]

3 голосов
/ 17 апреля 2011

Вы можете отбросить генерики во время построения (и подавить предупреждение):

A<Integer> a = new A(42);

или, менее предпочтительно, использовать отражение (где вам снова придется подавлять предупреждения)

Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);
2 голосов
/ 17 апреля 2011

Да, члены параметризованного типа JLS3 # 4.5.2 могут закончиться конфликтами, которые исключаются в обычном объявлении класса (# 8.4.8). Довольно много примеров такого рода.

А в Java ни один конструктор в вашем примере не является более конкретным, чем другой, потому что между T и Integer нет отношения подтипов. см. также Ссылка на дженерики неоднозначна

Если перегрузка метода создает такую ​​двусмысленность, мы обычно можем использовать разные имена методов. Но конструкторы не могут быть переименованы.


Больше софистики:

Если <T extends Integer>, то действительно T является подтипом Integer, тогда 2-й конструктор более специфичен, чем 1-й, и будет выбран 2-й.

На самом деле javac не позволил бы этим двум конструкторам сосуществовать. В текущей спецификации языка Java нет ничего, что запрещало бы их, но ограничение в байт-коде заставляет javac запрещать их. см. Стирание и перегрузка типов в Java: почему это работает?

Еще один момент: если <T extends Integer>, поскольку Integer равно final, T может быть только Integer, поэтому Integer также должен быть подтипом T, поэтому не является вторым конструктором конкретнее 1-го?

Нет. final не учитывается в отношениях подтипов. Фактически можно удалить final с Integer за один день, и Java даже указывает, что удаление final не нарушает бинарную совместимость.

2 голосов
/ 17 апреля 2011

Действительно, это неоднозначно, и поэтому не компилируется, если вы попытаетесь new A<Integer>(new Integer(0)).

...