Перегрузка метода / конструктора супер / подтипами - PullRequest
3 голосов
/ 17 октября 2010

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

Случай 1:

public void someMethod(Object obj){
    System.out.println("Object");
}
public void someMethod(InputStream is){
    System.out.println("InputStream");
}
public void someMethod(FilterInputStream fis){
    System.out.println("FilterInputStream");
}

Я знаю, что если я передам ему String, он напечатает «Объект».Однако, что если я передам ему InputStream?Это становится более запутанным, если я передаю ему что-то вроде BufferedInputStream.Будет ли это вызывать Object one, InputStream one или FilterInputStream one?Имеет ли значение порядок появления методов?

Случай 2:

Это немного сложнее, поскольку он использует преимущества наследования нескольких интерфейсов.Ни BlockingQueue, ни Deque не являются подтипами / супертипами друг друга, но оба они являются супертипами BlockingDeque.Sun добавила множественное наследование с интерфейсами, потому что им не нужна древовидная структура.Объявление для BlockingDeque:
public interface BlockingDeque extends BlockingQueue, Deque {.

public void someMethod(BlockingQueue bq){
    System.out.println("BlockingQueue");
}
public void someMethod(Deque bq){
    System.out.println("Deque");
}
public void someCaller(){
     BlockingDeque bd = new LinkedBlockingDeque();
     someMethod(bd);
}

Будет ли это Call someMethod (BlockingQueue) или someMethod (Deque)?

Случай 3:

YouМожно объединить эти два с этим:

public void someMethod(Queue q){
    //...
}
public void someMethod(Deque q){
    //...
}
public void someMethod(List p){
    //...
}
public void someCaller(){
    someMethod(new LinkedList());
}

Тот же вопрос: someMethod (очередь), someMethod (Deque) или someMethod (список)?

Случай 4:

Вы также можете усложнить ситуацию, введя два аргумента:

public void someMethod(Collection c1, List c2){
    //...
}
public void someMethod(List c1, Collection c2){
    //...
}
public void someCaller(){
    someMethod(new ArrayList(), new ArrayList());
}

Будет ли это вызывать someMethod (Коллекция, Список) или наоборот?

Случай 5:

Хуже, когда у них разные типы возвращаемых данных:

public Class<?> someMethod(BlockingQueue bq){
    return BlockingQueue.class;
}
public String someMethod(Deque bq){
    return "Deque";
}
public void someCaller(){
     BlockingDeque bd = new LinkedBlockingDeque();
     System.out.println(someMethod(bd));
}

Они могут быть довольно плохими.Что будет печатать SomeCaller в этом случае?someMethod (BlockingQueue) .toString () или someMethod (Deque)?

Ответы [ 3 ]

6 голосов
/ 17 октября 2010

В общем, Java будет вызывать самое узкое не однозначное определение, поэтому для первых нескольких случаев, если вы передадите узкий тип, он вызовет самую узкую функцию, если вы передадите более широкий тип (скажем InputStream), вы получите более широкий тип функция (в случае 1 для InputStream это метод 2). Вот простой тест , и отметим, что даункастинг будет расширять тип, и вызовем метод более широкого типа .

Основная проблема заключается в том, может ли Java разрешить уникальную функцию для вызова. Таким образом, это означает, что если вы предоставляете определение, имеющее несколько совпадений, вам необходимо либо соответствовать самому высокому известному типу, либо уникально соответствовать более широкому типу без , также совпадающему с более высоким типом. В основном: если вы сопоставляете несколько функций, одна из них должна быть выше по иерархии, чтобы Java разрешала различие, в противном случае соглашение о вызовах будет окончательно неоднозначным.

Java вызывает ошибку компиляции, когда сигнатуры методов неоднозначны. На мой взгляд, случай 4 является канонически худшим примером этого, поэтому я написал быстрый тест и действительно получил ожидаемую ошибку компиляции, жалуясь на неоднозначное соответствие для вызываемых функций.

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

Итак, краткое резюме:

  1. Ошибка компиляции из-за неоднозначного вызова при вызове с простым InputStream, вызываемого с помощью FilteredInputStream, использует 3-е определение, вызывается с чем-то, что реализует InputStream, но не FilteredInputStream использует 2-е определение, что-либо еще, 1-е определение

  2. 2-е определение

  3. неоднозначно, приведет к ошибке компиляции

  4. неоднозначно, приведет к ошибке компиляции

  5. неоднозначно, приведет к ошибке компиляции

Наконец, если у вас есть сомнения в том, что вы вызываете определение, которое, по вашему мнению, должно быть, вам следует рассмотреть возможность изменения кода для устранения неоднозначности или работы, чтобы указать аргументы правильного типа для вызова «правильной» функции. , Java скажет вам, когда она не может принять умное решение (когда вещи действительно неоднозначны), но лучший способ избежать любой из этих проблем - это последовательные и однозначные реализации. Не делайте странных вещей, таких как случай 4, и у вас не возникнет странных проблем.

2 голосов
/ 17 октября 2010

В случае перегруженных функций вызывается метод, который имеет наиболее ограниченный, но совместимый тип аргумента со ссылкой на передаваемый объект. Также следует отметить, что привязка перегруженного метода определяется во время компиляции, а не по типу объекта, определенному во время выполнения.e.g.

Случай 1: если во время компиляции ввод имеет тип InputStream, то будет вызван 2-й метод. BufferedInputStream перейдет во 2-й метод.

Случай 2. Сбой во время компиляции, потому что тип ссылки BlockingDeque неоднозначен, и аргумент может соответствовать любому из двух методов, так как он расширяет оба этих типа

вариант 3: здесь нет проблем, третий метод, поскольку Linkedlist не совместим ни с одним из двух других аргументов

Случай 4: неоднозначно, потому что с этими аргументами я могу получить любой из этих двух методов, и нет никакого способа различить

Случай 5: возвращаемые типы не играют роли в перегруженных методах. Дело 2 верно.

0 голосов
/ 17 октября 2010

Это немного касательно вопроса о перегруженных аргументах, но есть довольно четкая причина, по которой случай 5 «хуже».

В случае 5 вы используете языковую функцию, называемую ко-вариантными типами возврата. Изначально этого не было в Java, но я добавил его в версии 1.5 (частично из-за этой проблемы). Если компилятор не может определить, какой тип возвращаемого значения правильный, это был сбой, и именно это происходит в этом случае.

...