Какой перегруженный метод вызывается в Java
у меня есть базовая ситуация наследования с перегруженным методом в суперклассе.
public class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex){
name = theName;
dob = birth;
gender = sex;
}
public void work(){
getWorkDetail(this);
}
public void getWorkDetail(Employee e){
System.out.println("This person is an Employee");
}
public void getWorkDetail(Person p){
System.out.println("This person is not an Employee");
}
}
следующее Employee класс расширяет Person классом выше:
public class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex){
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
}
основной метод просто создает Employee объект (как статический, так и динамический тип) и вызовы .work() на:
public static void main(String[] args){
Employee e1 = new Employee("Manager1", 1976, "Female");
e1.work();
}
это заканчивается печатью
This person is not an Employee
просматривая это, я думал, что так как оба статический и динамический тип объекта e1 и Employee он будет вызывать перегруженный метод лично, который принимает Employee в качестве параметра. Поскольку я явно ошибаюсь в этом, я открыл отладчик, предполагая ссылку на " это " в строке getWorkDetail(this) на Person класс, должно быть, превратился в супер класс. Однако это не то, что я нашел.

ясно в этот момент в коде this это Employee объект, однако он все же решил выполните перегруженный метод getWorkDetail(Person p). Кто-нибудь может объяснить такое поведение?
5 ответов:
В отличие от переопределений методов, перегрузки методов связаны на основе статического типа. И в этом случае,
getWorkDetail(this)наPersonтолько знает оPersonтип.перегрузка метода не предназначена для обеспечения динамического поведения во время выполнения.
чтобы воспользоваться динамической привязкой, вам может потребоваться изменить свой код, чтобы переопределить методы, вместо этого:
public static void main(String[] args) throws IOException { new Employee("Manager1", 1976, "Female").getWorkDetail(); new Person("Manager1", 1976, "Female").getWorkDetail(); }и изменить поведение на основе реализации классов. Конечно, вы можете перегружать методы, как если вы также позаботитесь о переопределении перегруженных методов, если это необходимо.
class Person { private String name; private int dob; private String gender; public Person(String theName, int birth, String sex) { name = theName; dob = birth; gender = sex; } public void getWorkDetail() { System.out.println("This person is not an Employee"); } } class Employee extends Person { String department; double salary; public Employee(String theName, int birth, String sex) { super(theName, birth, sex); department = "Not assigned"; salary = 30000; } public void getWorkDetail() { System.out.println("This person is an Employee"); } }
разрешение перегрузки происходит во время компиляции, а не во время выполнения.
Итак, когда вы звоните
getWorkDetails(this),thisсчитаетсяPerson(который является статическим типом) и поэтому называется соответствующей перегрузкой.Примечание: С Помощью
thisвнутриEmployeeкласс сделал бы егоEmployeeтип. Вы можете проверить это, перегружаяwork()наEmployeeтакой.class Employee extends Person { ... public void work() { getWorkDetails(this); // This should print "This person is an Employee" } }
конкретное решение проблемы
в некоторых языках параметры разрешаются к их динамическому типу, но не в java. Компилятор уже определяет во время компиляции, где ваш
getWorkDetail(this);пойдет.thisтипаPerson, так чтоgetWorkDetail(Person e)называется. В вашем конкретном случае решение вполне очевидно. Как уже указывали другие, вам нужно будет переопределитьgetWorkDetail()наEmployeeкласса.методы разрешения для их динамического параметра типы
для решения общей проблемы разрешения типы параметров во время выполнения, используя
instanceofоператора следует избегать, так как это обычно приводит к нечистому коду.если у вас есть два разных класса, решение, столь простое, как указано выше, больше невозможно. В этих случаях вам придется использовать шаблон Visitor.
рассмотрим следующие классы:
public interface Animal { default void eat(Food food) { food.eatenBy(this); } void eatMeat(Meat meat); void eatVegetables(Vegetables vegetables); } public class Shark implements Animal { public void eatMeat (Meat food) { System.out.println("Tasty meat!"); } public void eatVegetables (Vegetables food) { System.out.println("Yuck!"); } } public interface Food { void eatenBy(Animal animal); } public class Meat implements Food { public void eatenBy(Animal animal) { animal.eatMeat(this); } } public class Vegetables implements Food { public void eatenBy(Animal animal) { animal.eatVegetables(this); } }который вы можете назвать как это:
Animal animal = new Shark(); Food someMeat = new Meat(); Food someVegetables= new Vegetables(); animal.eat(someMeat); // prints "Tasty meat!" animal.eat(someVegetables); // prints "Yuck!"после шаблон Visitor вызов
Animal.eatбудем называтьFood.eatenBy, который реализуется какMeatиVegetables. Эти классы будут называть более конкретныеeatMeatилиeatVegetablesметод, который использует правильные (динамические) типы.
предпочтение вызовов
class Foo { static void test(int arg) { System.out.println("int"); } static void test(float arg) { System.out.println("float"); } static void test(Integer arg) { System.out.println("Integer"); } static void test(int... arg) { System.out.println("int..."); } public static void main(String[] arg) { test(6); } }выход будет int печатается на консоль. Теперь вы комментируете первый
test()метод и посмотреть, что на выходе идет.это предпочтение hirarchey в примитивных типах данных. Теперь перейдем к производным типам объявить класс
FooChildтакойclass FooChild extends Foo { }и создать два новых метода в
Fooкакstatic void testChild(Foo foo) { System.out.println("Foo"); } static void testChild(FooChild fooChild) { System.out.println("FooChild"); }затем в основном методе попробуйте вызвать
testChildтакойtestChild(new FooChild());.
Comments