Java中调用了哪个重载方法
Posted
技术标签:
【中文标题】Java中调用了哪个重载方法【英文标题】:Which Overloaded Method is Called in Java 【发布时间】:2018-10-05 10:44:17 【问题描述】:我有一个基本的继承情况,超类中有一个重载的方法。
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;
main 方法只是简单地创建一个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
作为参数的Person 中的重载方法。由于我对此显然错了,我打开了一个调试器,假设在Person
类中的getWorkDetail(this)
行中对“this”的引用必须已经变形为它的超类。然而,这不是我发现的。
显然此时代码this
是一个Employee
对象,但是它仍然选择执行重载方法getWorkDetail(Person p)
。谁能解释这种行为?
【问题讨论】:
恕我直言,父类不应该对子类一无所知。我的意思是Person
类中没有getWorkDetail(Employee e)
方法的位置...
@zlakad 我认为这些功能应该是静态的?
@StarWeaver,静态与否,这个特定问题有什么区别?
类Person
中的this
是静态类型Person
。
正如@zlakad 所暗示的,这个类结构的结构很差。 this
是一种隐含的非静态方法。在这里将this
传递给成员方法确实没有任何意义。
【参考方案1】:
与方法重载不同,方法重载是基于静态类型链接的。而在这种情况下,Person
中的getWorkDetail(this)
只知道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");
【讨论】:
@Ernest Kiwele 谢谢!我不知道 Java 不为方法重载提供动态行为。这样就搞定了。 您可能还需要注意,JVM 首先查找具有您指定的签名的非重写方法,然后再查找与您的签名匹配的重写方法。但理想情况下,您希望利用 Java 的继承机制来重构您的代码,就像 @Ernest 展示的那样【参考方案2】:重载解决发生在编译时,而不是运行时。
因此,当您调用 getWorkDetails(this)
时,this
被假定为 Person
(这是静态类型),因此称为相应的重载。
注意:在 Employee
类中使用 this
会使其成为 Employee
类型。您可以像这样在Employee
中重载work()
来验证这一点。
class Employee extends Person
...
public void work()
getWorkDetails(this); // This should print "This person is an Employee"
【讨论】:
【参考方案3】:问题具体解决方案
在某些语言中,参数被解析为它们的动态类型,但在 java 中不是。编译器已经在编译时确定了您的getWorkDetail(this);
的去向。 this
的类型为 Person
,因此会调用 getWorkDetail(Person e)
。在您的具体情况下,解决方案非常明显。正如其他人已经指出的那样,您需要在 Employee
类中覆盖 getWorkDetail()
。
将方法解析为其动态参数类型
要解决在运行时解析参数类型的一般问题,应避免使用instanceof
运算符,因为它通常会导致代码不干净。
如果您有两个不同的类,那么上述简单的解决方案将不再可能。在这些情况下,您必须使用visitor pattern。
考虑以下类:
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!"
遵循访问者模式,调用Animal.eat
将调用Food.eatenBy
,由Meat
和Vegetables
实现。这些类将调用更具体的eatMeat
或eatVegetables
方法,它们使用正确的(动态)类型。
【讨论】:
【参考方案4】:通话偏好
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()
方法,看看输出是什么。
这是原始数据类型中的首选项层次结构。现在来派生类型声明一个类 FooChild
像这样
class FooChild extends Foo
并在Foo
中创建两个新方法
static void testChild(Foo foo) System.out.println("Foo");
static void testChild(FooChild fooChild) System.out.println("FooChild");
然后在 main 方法中尝试像这样testChild(new FooChild());
调用testChild
。
【讨论】:
【参考方案5】:getWorkDetail(this) 不知道子类是什么。改为调用 getWorkDetail。
【讨论】:
以上是关于Java中调用了哪个重载方法的主要内容,如果未能解决你的问题,请参考以下文章