Java的多态通过重载和重写体现。
重载(overload)
重载是在一个类中多态性的一种体现;指方法名相同,但是参数类型和参数的顺序不同。
- 重载是通过参数列表不同来区分的。(不同的参数个数、参数类型、参数顺序)
- 不能通过访问权限、返回值类型、抛出的异常类型来进行方法的重载
重写(覆盖)(override)
重写:派生类覆盖基类的函数
-
派生类中的覆盖方法必须要和基类中被覆盖的函数的方法有相同的函数名和参数;
-
子类返回类型 小于等于 父类方法的返回类型;
-
子类抛出的异常 小于等于 父类方法抛出的异常;
-
子类访问权限 大于等于 父类的方法的访问权限。
方法重载和重写的区别
-
重写(覆盖)是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,属于水平关系;
-
重写要求参数列表相同;重载要求参数列表不同;
-
重写方法中,根据对象的类型来调用方法体;而重载关系是根据调用时的实参列表和形参列表来选择方法体。
示例代码
子类访问权限 大于等于 父类的方法的访问权限。
package Test_9;
//父类
class Base{
public void fun(){
}
}
//子类
public class Test extends Base {
//方法重写
// private void fun(){//编译出错
//
// }
// void fun(){//编译出错,默认访问权限为default小于父类的public
//
// }
// protected void fun(){//编译出错
//
// }
// public void fun(){//编译通过
//
// }
public static void main(String[] args) {
}
}
运行时多态
父类引用指向子类实例1
package Test_9;
//基类
class Base
{
public void method()
{
System.out.println("Base");
}
}
//子类
class Son extends Base
{
//方法重写
public void method()
{
System.out.println("Son");
}
public void methodB()
{
System.out.println("SonB");
}
}
public class Test{
public static void main(String[] args) {
//Son son = (Son) new Base();
Base base = new Son();//父类对象调用了子类创建了Son对象
base.method();
//base.methodB();//编译出错
}
}
运行结果:
Son
base调用的method()方法就是调用了子类重写的method()方法。
而此时base还是属于Base对象,base调用methodB()时Base对象里没有这个方法,所以编译不通过。要想调用的话需要先通过SON son=(SON)base;强制转换,然后用son.methodB()调用就可以了。
父类引用指向子类实例2
package dong.test;
class Father{
public void test(){
System.out.println("father");
}
public void testFathetr(){
System.out.println("testFather");
}
}
class Son extends Father{
public void test(){
super.test();
System.out.println("son");
}
}
class Daughter extends Father{
}
public class Test {
public static void main(String[] args){
// Father father = new Father();
// Son son = (Son) father;//抛出ClassCastException
Father father2 = new Son();
father2.test();
Son son = new Son();
son.test();
}
}
运行结果:
father
son
father
son
使用super关键字首先调用的是父类的方法,再调用子类
父类引用指向子类实例3
package test11;
//基类
class Base{
private String baseName = "base"; //1:加载父类普通成员变量
public void callName(){ //2
System.out.println(baseName);
}
public Base(){ //2.执行父类的构造函数
//注意此时执行的是子类的callName()方法
callName();
}
}
//子类
class Sub extends Base{
private String baseName = "Sun"; //3.加载子类的普通成员变量
//方法重写
public void callName(){
System.out.println(baseName);
}
public Sub(){ //4.执行子类的构造函数
callName();
}
}
public class ExtendsTest {
public static void main(String[] args) {
Base base = new Sub();//多态:将父类的引用执行子类的对象
}
}
运行结果:
null
Sun
Base b = new Sub();它为多态的一种表现形式,声明是Base,实现是Sub类, 理解为 b 编译时表现为Base类特性,运行时表现为Sub类特性。
当子类覆盖了父类的方法后,意思是父类的方法已经被重写,题中父类初始化调用的方法为子类实现的方法,子类实现的方法中调用的baseName为子类中的私有属性。 此时子类中的baseName还没有被初始化。所以此时 baseName为空。 所以为null。