2015-03-19 2 views
9

Я знаю, что я не могу это сделать:метод перегрузки с тем же общим параметром?

public abstract class DTODomainTransformer<T, S> { 

    public abstract S transform(T); 

    public abstract T transform(S); 

} 

Потому что я получаю компилятор жалобу:

Method transform(T) has the same erasure transform(Object) as another method in type Transformer<T,S> 

Я понимаю, что это потому, что как T и S может быть простирающийся же класса. Таким образом, делая это так, как я могу сказать ему: «Нет, они не то же самое, так что успокойтесь»

public interface Transformer<T extends AbstractDTO , S extends AbstractDomain> { 

    public abstract S transform(T object); 

    public abstract T transform(S object); 

} 

Тогда мой вопрос, есть ли способ, чтобы сообщить компилятору, что T и S расширения от различных классы, не сообщая, какие из них конкретны? Я имею в виду, что в этом последнем случае я указал, какие классы должны были быть T и S (соответственно). Но что, если я хочу, чтобы он был более общим и не указывал их? Я хотел бы сказать компилятору: «Эй, компилятор, T и S - это не одно и то же! Это разные классы. Я не знаю, какие именно классы они есть, но я уверен, что они разные».

+8

Нет, нет никакого способа сделать это, не давая явных границ. –

+0

Как вы можете - программист - обеспечить, чтобы пользователь вашего класса не нарушал это правило, если он использует исходный тип? – Mordechai

+0

Если это помогает, вы можете связать только один из них. '' – jas

ответ

3

Нет очевидного пути. (Хотя вы можете создать его, как я покажу ниже).

Это правило перегрузки связано с ограничением того, как супертип (в данном случае, интерфейс), объявляющий перегрузку, переводится (путем стирания) на байт-код.

Если есть общий параметр объявлен T, метод, который использует T в подписи будет иметь байткод генерируемый в качестве верхней границы T, например

class Generic<T> { 
    void work(T t) {} 
} 

будет получить стерты в

class Generic { 
    void work(Object t) {} 
} 

и

class Generic<T extends Number> { 
    void work(T t) {} 
} 

будет получить стерты в

class Generic { 
    void work(Number t) {} 
} 

Это как работает ограниченный пример, потому что перегружает стирать по-разному.

public interface Transformer { 
    public abstract AbstractDomain transform(AbstractDTO object); 
    public abstract AbstractDTO transform(AbstractDomain object); 
} 

Но без особых ограничений, какой стираемый байт-код должен быть сгенерирован для перегруженных методов?

Так что ваши T и S быть отличается от подтипа не то, что важно. Важно то, что известные объявленные оценки переходят на стираемый байт-код для класса супертипа.


Возможное решение может использовать интерфейсы маркеров.

interface TransformT {} 
interface TransformS {} 
interface Transformable extends TransformT, TransformS {} 

interface Transformer<T extends TransformT, S extends TransformS> 
    T transform(S s); 
    S transform(T t); 
} 

abstract class AbstractDTO implements Transformable {} 
abstract class AbstractDomain implements Transformable {} 

new SomeTransformerImpl<AbstractDTO, AbstractDomain>() 

Но я не обязательно рекомендую это делать. Мне кажется сложным, хотя и интересным. Это зависит от того, насколько сложна фактическая иерархия классов.

What Louis suggested in the comments намного проще: придать методам разные названия.

Смежные вопросы