简单谈谈方法重载和方法重写(编译时多态和运行时多态)
这篇文章来聊一聊方法重载和重写到底是有什么区别,重载实现的是编译时多态,而方法重写实现的是运行时多态,那什么又是编译时多态和运行时多态呢?
定义一个Animal类,
public class Animal {
public void say(int age){
System.out.println("我的年龄是" + age);
}
public void say(int age, int weight){
System.out.println("我的年龄是" + age + ", 体重是" + weight);
}
public void say(String name){
System.out.println("我的姓名是" + name);
}
}
这边写了3个say方法,同名方法为什么可以同时存在,这边就要说到重载的机制了。对方法而言只要参数列表不同,那么就可以定义为同名方法,在编译时编译器会判断要调用的到底是哪一个方法,这也就是编译时多态。参数列表是什么?参数列表就是方法括号后面那一串,只要参数个数或者类型不同,那么就可以实现重载。注意:参数列表和返回类型没有任何关系,哪怕返回类型是int,String或者其他类型,都不能改变参数列表,这边是个容易理解错的地方。
下面情况不属于方法重载,而且编译无法通过,会直接报错
public class ParamsList {
public String display(String temp){
return "ABC";
}
public int display(String temp){
return 1024;
}
}
换个角度想想:你上面的方法传一个String,下面的传的也是String,谁知道你要干嘛
?谁知道你要调哪个方法?
所以改变返回类型是无法实现重载的,所以它也不属于参数列表的一部分。
测试一下刚才的Animal例子,
public class OverTest {
public static void main(String[] args) {
Animal animal = new Animal();
animal.say(18);
animal.say(24, 50);
animal.say("john");
}
}
得到的结果如下
我的年龄是18
我的年龄是24, 体重是50
我的姓名是john
可以看到方法的确都被正确的调用了,这边就是实现方法重载的办法。
那么方法重写呢?又是怎么回事,下面定义一个图形Shape类,包含圆形Circle和长方形Rectangle。圆形和长方形明显是图形的子类,图形是抽象的,是一个概念,而圆形和长方形是具体的,有具体的规则约定。
Shape
public class Shape {
public void run(){
System.out.println("这是一个图形");
}
}
Circle
public class Circle extends Shape{
@Override
public void run() {
System.out.println("这是一个圆形");
}
}
Rectangle
public class Rectangle extends Shape{
@Override
public void run() {
System.out.println("这是一个长方形");
}
}
Circle和Rectangle继承了Shape类,并定义了run方法,子类定义了和父类同名并且参数相同的方法,这种行为就叫做方法重写。在运行时会根据对象来判断是需要调用哪一个方法,下面测试一下。
public class OverTest {
public static void main(String[] args) {
Shape shape = new Shape();
Shape circle = new Circle();
Shape rectangle = new Rectangle();
start(shape);
start(circle);
start(rectangle);
}
public static void start(Shape shape){
shape.run();
}
}
start方法会根据我们运行时创建的对象来判断,到底调用哪一个run方法。测试结果如下
这是一个图形
这是一个圆形
这是一个长方形
可以看到run方法都被正确调用,这就是实现运行时多态的流程。
方法重写和方法重载有什么用呢?
方法重载可以避免方法名因为不能冲突而思考怎么定义一大堆同名方法的问题,更加便捷,同时也提升了代码可读性,简化代码。
方法重写提高了代码的可扩展性,例如图形其实是一个抽象的概念,可以把塔延伸为具体的图形,比如圆形,长方形,但不止于此,还有三角形,多边形... 例如在传参时,可以把类型定义为Shape类,那么调用的时候Shape本身和所有继承自Shape的类都可以传入,并自动识别需要调用的run方法。