用一句话概括就是:事物在运行过程中存在不同的状态。
一、重写与重载
1.重写(Override)
从字面上看,重写就是 重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的。
例如:
public class Father
{
public static void main(String[] args)
{
// TODO Auto-generated method
stubSon s = new Son();
s.sayHello();
}
public void sayHello()
{
System.out.println("Hello");
}
}
class Son extends Father
{
@Override
public void sayHello()
{
// TODO Auto-generated method stub
System.out.println("hello by ");
}
}
重写 总结:
1.发生在父类与子类之间
2.方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常
2.重载(Overload)
在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。
例如:
public class Father
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
Father s = new Father();
s.sayHello();
s.sayHello("wintershii");
}
public void sayHello()
{
System.out.println("Hello");
}
public void sayHello(String name) {
System.out.println("Hello" + " " + name);
}
}
public class Dog {
Dog()
{
this.bark();
}
void bark()//bark()方法是重载方法
{
System.out.println("no barking!");
this.bark("female", 3.4);
}
void bark(String m,double l)//注意:重载的方法的返回值都是一样的,
{
System.out.println("a barking dog!");
this.bark(5, "China");
}
void bark(int a,String n)//不能以返回值区分重载方法,而只能以“参数类型”和“类名”来区分
{
System.out.println("a howling dog");
}
public static void main(String[] args) {
Dog dog = new Dog();
//dog.bark();
//dog.bark("male", "yellow");
//dog.bark(5, "China");
}
}
重载、重写总结:
1.重载Overload是一个类中多态性的一种表现;重写是父类与子类之间多态性的一种表现。
2.重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序);重写要求同名方法的参数列表也相同。
3.重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。4.同一类中的方法可以相互重载,但不能相互重写。子类对父类方法可以重载也可以重写。
二、运行时多态
多态的存在有三个前提:
1、有继承关系
2、子类要重写父类的方法
3、父类引用指向子类对象
先定义一个父类Animal,一个子类Cat
父类Animal
public class Animal {
int num = 10;
static int age = 20;
public void eat() {
System.out.println("动物在吃饭");
}
public static void sleep() {
System.out.println("动物在睡觉");
}
public void run() {
System.out.println("动物在奔跑");
}
}
子类Cat
public class Cat extends Animal
{
int num = 80;
static int age = 90;
public void eat() {
System.out.println("猫在吃饭");
}
public static void sleep() {
System.out.println("猫在睡觉");
}
public void catchMouse() {
System.out.println("猫在抓老鼠");
}
}
测试类test_DuoTai
public class test_DuoTai {
public static void main(String[] args) {
// TODO Auto-generated method stub
Animal animal = new Cat();
//Cat animal = new Cat();
animal.eat();
animal.sleep();
animal.run();
System.out.println(animal.num);
System.out.println(animal.age);
}
}
运行结果:
猫在吃饭
动物在睡觉
动物在奔跑
10
20
以上的三段代码充分体现了多态的三个前提,即:
1、存在继承关系Cat类继承了Animal类
2、子类重写父类方法子类重写了父类的两个成员方法eat(),sleep()。其中eat()方法是非静态的,sleep()方法是静态的。
3、父类数据类型的引用指向子类
对象测试类中Animal animal = new Cat();语句在堆内存中创建了子类(Cat)的对象,并把栈内存中的父类(Animal)的引用指向了这个Cat对象。
根据以上运行结果可以总结出多态成员访问的特点:
成员变量
编译看左边(父类),运行看左边(父类)
成员方法
编译看左边(父类),运行看右边(子类)。动态绑定
静态方法
编译看左边(父类),运行看左边(父类)。
(静态和类相关,算不上重写,所以,访问还是左边的)
只有非静态的成员方法,编译看左边,运行看右边