Java中 方法覆盖 和 方法隐藏 详解

实例方法

如果子类中存在实例方法A的方法签名与父类中实例方法B的相同,则称方法A覆盖了方法B。这里说的方法签名包括方法名、参数的个数和类型、方法的返回值类型。

子类可以通过方法覆盖的方式来修改父类中功能差不多的方法,以满足自身需要。新方法与被覆盖的方法具有相同的名称

参数个数、参数类型和返回值类型。不过,返回值类型不必一模一样,可以是源类型的子类型。比如原方法返回值类型为java.util.List,那么新方法可以返回java.util.ArrayList。这种返回类型也就是术语中的“协变返回类型”。

在写方法覆盖的时候最好加上@Override注解,来告诉编译器你在进行方法覆盖操作。如果编译器发现你写的代码并不是方法覆盖操作,则会抛出错误。

 

static方法

如果子类中存在静态方法staticA的方法签名与父类中静态方法staticB的相同,则称staticA隐藏了staticB。

静态方法的“隐藏”和实例方法的“覆盖”具有不同的效果:

  • 实例方法依据实例类型来调用
  • 静态方法依据声名类型来调用

下面用一个例子来说明一下静态方法与实例方法调用时遵循的规则。Animal类中包含一个静态方法和一个实例方法:

public class Animal{
	public static void testClassMethod(){
		System.out.println("The static method in Animal.");
	}
	public void testInstanceMethod(){
		System.out.println("The instance method in Animal.");
	}
}

下面Cat类是Animal的子类:

public class Cat extends Animal{
    public static void testClassMethod() {
        System.out.println("The static method in Cat.");
    }
    public void testInstanceMethod(){
        System.out.println("The instance Method in Cat.");
    }
    
    public static void main(String[] agrs){
        Cat myCat = new Cat();
        Animal myAnimal = myCat;
        Animal.testClassMethod();
        myAnimal.testInstanceMethod();
    }
}

运行结果如下:

The static method in Animal.

The instance method in Cat.

 

接口方法

接口的默认实现方法与抽象方法的覆盖原理与类的实例方法相同。但是当子类同时既继承了父类又实现了多个父接口时,情况就有些复杂了。根据不同的情形,有如下几种不同的继承策略。

  • 类的实例方法优先于接口的默认实现方法

class Horse{
    public String identifyMyself(){
       return  "I am a horse.";
    }
}
interface Flyer{
    default public String identifyMyself(){
        return "I am able to fly.";
    }
}
interface Mythical {
    default public String identityMyself(){
        return "I am a mythical creature";
    }
}
public class Pegasus extends Horse implements Flyer, Mythical{
    public static void main(String[] args) {
        Pegasus myApp = new Pegasus();
        System.out.println(myApp.identifyMyself());
    }
}

以上程序运行的结果为:

I am a horse.

 

  • 已经被重写过得方法将不再被重写
interface Animal{
    default public String identifyMyself(){
        return "I am an animal.";
    }
}
interface EggLayer extends Animal{
    default public String identifyMyself(){
        return "I am able to lay eggs.";
    }
}
interface FireBreather extends Animal{ }
public class Dragon implements EggLayer, FireBreather{
    public static void main(String[] args) {
        Dragon myApp = new Dragon();
        System.out.println(myApp.identifyMyself());
    }
}

以上程序的运行结果为:

I am able to lay eggs.

分析:在Dragon的继承链中,Animal中的identifyMyself方法已经被继承链中的其他方法覆盖过了,所以要排除在候选方法外,则很显然只剩下了EggLayer中的identifyMyself方法。

 

  • 果以上两点排除完后还有冲突的方法存在,那么子类需要指明要重写的究竟是哪个父类方法
interface OperateCar{
    default public String startEngine(){
        return "operate engine.";
    }
}
interface FlyCar{
    default public String startEngine(){
        return "fly engine.";
    }
}
public class FlyingCar implements OperateCar, FlyCar{
    public String startEngine(){
        return OperateCar.super.startEngine() + FlyCar.super.startEngine();
    }

    public static void main(String[] args) {
        FlyingCar myApp = new FlyingCar();
        System.out.println(myApp.startEngine());
    }
}

以上程序的输出结果为:

operate engine.fly engine.

分析:使用 接口名.super的方式可以指定需要调用的方法。

你可能感兴趣的:(编程语言)