个人博客:www.letus179.com
概念
-
重载Overload
-
重载发生在
一个类
中,同名的方法
如果有不同的参数列表
(参数类型不同
、参数个数不同
或者二者都不同
)。- 访问修饰符:重载与访问修饰符
无关
- 返回类型: 重载与返回值
无关
- 方法名: 重载方法名需
完全一致
- 参数列表: 重载参数列表需
完全不同
- 访问修饰符:重载与访问修饰符
-
重写Override
-
发生在
子类与父类
之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型
,比父类被重写方法更好访问
,不能
比父类被重写方法声明更多的异常
(里氏代换原则)。- 访问修饰符:子类的访问修饰符权限
>=
父类的访问修饰符权限 - 返回类型: 子类的返回类型
<=
父类的返回类型 - 方法名: 方法名应
完全一致
- 参数列表: 参数列表应
完全一致
- 访问修饰符:子类的访问修饰符权限
举例String类
重载例子
String
类的构造器重载
:
public String() {
this.value = new char[0];
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
String
类的valueOf()
方法的重载:
public static String valueOf(char data[]) {
return new String(data);
}
public static String valueOf(char data[], int offset, int count) {
return new String(data, offset, count);
}
重写例子
ArrayList
继承了AbstractList
类
public class ArrayList<E> extends AbstractList<E>
AbstractList
类中有方法add()
:
public boolean add(E e) {
add(size(), e);
return true;
}
ArrayList
类中有重写了add()
方法:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
多态
面向对象编程有三大特性:封装
、继承
、多态
。
概念
指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
实现多态的技术称为:动态绑定(dynamic binding)
多态存在的三个必要条件
1. 要有继承;
2. 要有重写;
3. 父类引用指向子类对象。
根据何时确定
执行多态方法中的哪一个,多态分为两种情况:编译时多态
和运行时多态
。顾名思义,如果在编译时能够确定执行多态方法中的哪一个,称为编译时多态,否则称为运行时多态。
编译时多态
重载都是编译时多态
,从上面的分析可以看到,只要确定了方法参数的数据类型
,个数
,次序
就能确定调用哪一个方法。
运行时多态
重写有两种多态性,当对象引用本类
实例,此时为编译时多态
,能在编译期确定调用哪个方法;否则为运行时多态
。
举例分析
package test;
public class Test {
}
class Animal{
public String getName() {
return "Animal";
}
}
class Dog extends Animal {
public String getName() {
return "Dog";
}
}
1.执行下面的main方法
public static void main(String[] args) {
Animal animal = new Animal();
Dog dog = new Dog();
System.out.println(animal.getName());
System.out.println(dog.getName());
}
输出结果:
Animal
Dog
Animal
和Dog
引用的都是本类的实例
Animal animal = new Animal();
Dog dog = new Dog();
2.若是这样呢?输入结果是多少
public static void main(String[] args) {
Animal animal = new Dog();
System.out.println(animal.getName());
}
此时输出:
Dog
程序在运行时,会从实例所属的类
开始寻找匹配的方法来执行,若是找不到匹配的方法,会按照继承关系
逐层向上查找,直到超级父类Object类
。
该例子animal.getName()
执行过程是:
查找匹配执行方法流程
3.修改Animal
类, 空类
class Animal{
}
此时执行方法:
public static void main(String[] args) {
Animal animal = new Dog();
System.out.println(((Dog) animal).getName());
}
需要显示地转换下((Dog) animal).getName()
,因为Animal
类中没有定义getName()
方法。
4.修改Animal
,Dog
类的getName()
方法为静态方法
,并增加一成员变量name
class Animal {
public String name = "a";
public static String getName() {
return "Animal";
}
}
class Dog extends Animal {
public String name = "d";
public static String getName() {
return "Dog";
}
执行main方法:
public static void main(String[] args) {
Animal animal = new Dog();
System.out.println(animal.getName());
System.out.println(animal.name);
}
输出结果为:
Animal
a
结果解释:
1.重写只使用于实例方法
,不能用于静态方法
,对于static方法
,只能隐藏
,重载,继承
;
2.在利用引用animal
访问对象的属性name
或静态方法getName()
时,是引用类型决定了实际上访问的是哪个对象(Animal
)的成员,而不是当前引用代表的那个类(new Dog()
);
由此可知,子类静态方法并不能
重写(覆盖
)父类的静态方法;故而输出的结果都是父类的成员结果。
为什么不能根据返回类型来区分重载
假设下面的重载方法update
能编译通过
public class Test {
public void update() {
}
public int update() {
return 0;
}
}
当调用new Test().update()时,不需要返回值, 这样就不能区分具体是调用哪个方法了。
方法的返回值
,只能作为方法运行之后得一个状态
,它是保持方法的调用者与被调用者进行通信的关键,并不能作为某个方法的标示
.