2013-08-09 2 views
7

Простите меня, если этот вопрос в основном основан на мнениях, но у меня такое ощущение, что это не так, и есть веская причина для выбора. Итак, вот пример. К сожалению, это очень долго, но очень просто:Компилятор интерпретации переопределения и перегрузки

Интерфейс:

public interface Shape 
{ 
    double area(); 
} 

Реализация класса 1:

import static java.lang.Math.PI; 

public class Circle implements Shape 
{ 
    private double radius; 

    public Circle(double radius) 
    { 
     this.radius = radius; 
    } 

    public double area() 
    { 
     return PI*radius*radius; 
    } 
} 

Реализация класса 2:

public class Square implements Shape 
{ 
    private double size; 

    public Square(double sideLength) 
    { 
     size = sideLength; 
    } 

    public double area() 
    { 
     return size*size; 
    } 
} 

Driver:

Shape[] shapes = new Shape[]{new Circle (5.3), new Square (2.4)}; 

System.out.println(shapes[0].area()); //prints 88.247... 
System.out.println(shapes[1].area()); //prints 5.76 

Работает с .area() по умолчанию Circle и Square. Теперь, вот где мой вопрос действительно начинается. Допустим, что водитель имеет следующие методы:

public static void whatIs(Shape s) 
{ 
    System.out.println("Shape"); 
} 

public static void whatIs(Circle s) 
{ 
    System.out.println("Circle"); 
} 

public static void whatIs(Square s) 
{ 
    System.out.println("Square"); 
} 

Если мы называем:

whatIs(shapes[0]); //prints "Shape" 
whatIs(shapes[1]); //prints "Shape" 

Это происходит потому, что Java интерпретирует объекты как Shape с и не Circle и Square. Конечно, мы можем получить желаемый результат через:

if (shapes[0] instanceof Circle) 
{ 
    whatIs((Circle) shapes[0]); //prints "Circle" 
} 
if (shapes[1] instanceof Square) 
{ 
    whatIs((Square) shapes[1]); //prints "Square" 
} 

Теперь, когда у нас есть фон мой вопрос: «Форма»
Какие причины внесли вклад в разработку компилятора/языка, например, что whatIs(shapes[0]); будет печатать Как и в, почему компилятор Java точно различает переопределенные методы для связанных объектов, но не перегруженные методы? Более конкретно, если только методы, которые водитель должен доступ являются:

public static void whatIs(Circle s) 
{ 
    System.out.println("Circle"); 
} 
public static void whatIs(Square s) 
{ 
    System.out.println("Square"); 
} 

и мы пытаемся назвать,

whatIs(shapes[0]); 
whatIs(shapes[1]); 

мы получим две ошибки (один для Square и один для Circle) с указанием что:

  • метод Driver.whatIs (площадь) не применяется
    • фактический аргумент Форма не может быть преобразована в площадь путем преобразования вызова метода

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

+0

Кроме того, если у кого-то есть лучшая идея для названия, пожалуйста, сделайте предложение или отредактируйте его, я знаю, что он, вероятно, не самый лучший, но не мог придумать ничего лучшего. Спасибо всем, кто сделал это через этот пост! –

+4

Я предлагаю вам пройти через [JLS Section 15.2.2] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2) (Перегрузка) и [JLS Section 8.4.8.1] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.1) (Переопределение) –

+1

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

ответ

4

Почему компилятор Java точно различает переопределенные методы для связанных объектов, но не перегружает методы?

Не может.

Он проверяет строго по типу, который он может видеть. & гарантия. Если ваш код равен shapes[0].area(), он проверит, что Shape имеет метод area и скомпилирует его для «вызова области() на этом объекте». У конкретного объекта, который существует во время выполнения, теперь гарантирован этот метод. Какая версия, из которой фактически используется класс, динамически разрешается во время выполнения.

Вызов перегруженных методов работает одинаково. Компилятор видит Shape и компилирует это в «вызов whatis() в базовой версии Shape». Если вы хотите изменить это (и даже не иметь базовой версии Shape), вам нужно будет определить тип во время компиляции.

Но AFAIK невозможно создать компилятор, который может определить тип, который будет иметь объект во время выполнения в этой точке. Например, например:

final Shape[] shapes = new Shape[] { new Circle(5.3), new Square(2.4) }; 
    new Thread() { 
     public void run() { 
      shapes[0] = new Square(1.5); 
     } 
    }.start(); 
    whatIs(shapes[0]); 

Вы должны выполнить этот код, чтобы узнать.

Компилятор может автоматически генерировать код, как

if (shapes[0] instanceof Circle) 
{ 
    whatIs((Circle) shapes[0]); //prints "Circle" 
} 

для вас для достижения динамического вызова метода во время выполнения, но это не делает. Я не знаю причины, но иногда было бы аккуратно. Хотя instanceof часто является признаком плохого дизайна класса - вы не должны смотреть извне на различия, пусть класс ведет себя по-другому, поэтому внешнему не нужно знать.

+0

Я думаю, теперь мой вопрос такой же, как у вас, как в том, почему компилятор не сгенерирует код в последнем примере. Тем не менее, вы ответили на мой первоначальный вопрос. Спасибо. –

2

Отправка в один из методов whatIs определяется компилятором во время компиляции. Вызов одного из методов area определяется во время выполнения на основе фактического класса объекта, на который делается ссылка.

5

Java, с объектно-ориентированными функциями, поддерживает полиморфизм, поэтому вызов area вызовет метод area конкретного экземпляра, что бы это ни было. Это определяется во время выполнения.

Однако этот полиморфизм не поддерживается перегруженными методами. Java Language Specification, Section 8.4.9 покрывает это:

Когда метод вызывается (§15.12), число фактических аргументов (и любые явные аргументы типа) и типов во время компиляции этих аргументов используются, во время компиляции , для определения сигнатуры метода , который будет вызываться (§15.12.2). Если метод, который должен быть вызван , является методом экземпляра, фактический метод, который будет вызываться, будет определяться во время выполнения, определяемым во время выполнения, с использованием динамического поиска методов (§15.12.4).

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

1

В: Почему компилятор Java точно различает переопределенные методы для связанных объектов, но не перегружает методы ... почему Java не может обрабатывать такую ​​ситуацию?

A: У вас есть вопрос назад.

Java РАЗРЕШЕНИЕ вы должны различать «перегрузку» и «переопределение».

Он не пытается угадать, что вы означает, он дает вам возможность использовать тот или иной.

1

Ну, как глупый ответ, вы могли бы получить функцию Whatis оштрафовать работать таким образом (без проверки типа)

class Shape{ 
    public abstract String whatIs(); 
} 

class Square{ 
    public String whatIs(){ return "Square"; } 
} 
class Circle{ 
    public String whatIs(){ return "Circle"; } 
} 

А потом называть их как этот

Shape square = new Square(); 
Shape circle = new Circle(); 

System.out.println(square.whatIs()) //prints 'square' 
System.out.println(circle.whatIs()) //prints 'circle 

Не на весь ответ на вопрос, который вы задали ... Но я не мог устоять.

+0

Вы правы в том, что это не то, что я просил, но, тем не менее, это интересно, и я уверен, что это поможет кому-то. +1 –

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