java基础--覆盖与重载

  1. 云栖社区>
  2. 博客列表>
  3. 正文

java基础--覆盖与重载

fribble_zwj 2018-11-09 20:43:42 浏览201 评论0

摘要: java基础

导语
昨天看spring源码时发现重载和覆盖用的很多,又想起之前面试实习居然混淆了,平时不爱看书,又不总结,对于基础知识感觉懂又不全懂。

直接看代码

一个简单的例子:

public interface Animal {
    default Animal getInstance() {return this;}
    default void perform(){System.out.println("default perform...");}
}
public class Dog implements Animal {   
    @Override
    public void perform() {System.out.println("dog is in the performance...");}
}
public class Cat implements Animal {
    @Override
    public Cat getInstance() {return this;}
}
public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.perform();
    }
}

这个例子很简单,但还是要拿出来,主要是Cat复写getInstance时,改变了其返回值,依旧是覆盖。但是如果改成不是原返回值类型的子类时则会报错,不是重载也不是继承,直接是函数重名错误。那么就可以推广到,一个类无法实现了有方法重名且返回值没有继承关系的两个接口。

复杂点的例子:

public abstract class AbstractAnimal implements Animal{
    @Override
    """
    记住,我们是商人.
    """
    public abstract Animal getInstance() throws Exception;
    @Override
    public final void perform (){
        try {
            this.getInstance().perform();
        } catch (Exception e) {
            System.out.println("Animals are missing...");
        }
    }
    protect abstract buyAnimals();
}

public class Zookeeper extends AbstractAnimal {

    public static int times = 0;
    List<Animal> animals;
    public Zookeeper() {
        this.buyAnimals();
    }
    @Override
    public Animal getInstance() throws Exception {
        if(animals== null || animals.size()==0)
            throw new Exception("Zookeeper has no animals...");
        times++;
        return animals.get(times % animals.size());
    }
    public final void perform(int index) {
        if(animals.size() <= index)
            super.perform();
        else
            this.animals.get(index).perform();
    }
    public void perform(Class type) {
        for(Animal a: animals) {
            if(a.getClass() == type) {
                a.perform();
                return;
            }
        }
        System.out.println("no such animals: " + type.getClass().getSimpleName()) ;
    }
    /**
    public Animal perform(int index) {
        if(animals.size() <= index)
            index = animals.size();
        Animal animal = animals.get(index);
        animal.perform();
        return animal;
     }
     */
    @Override
    public void buyAnimals() {
        if(animals == null)
            animals = new ArrayList<>();
        this.animals.add(new Cat());
        this.animals.add(new Dog());
        this.animals.add(new Cat());
    }
}
public class Main {
    public static void main(String[] args) {
        Animal zookeeper = new Zookeeper();
        zookeeper.perform();
        //  zookeeper.perform(3);  无法使用
        zookeeper.perform();
        Zookeeper zookeeper1 = new Zookeeper();
        zookeeper1.perform();
        zookeeper1.perform();
        zookeeper1.perform(2) 
    }
}

Zookeeper继承自AbstractAnimal,而它的父亲AbstractAnimal很聪明,它把getInstance()覆盖为抽象方法,出于害怕把buyAnimals()权限设置成protect,并且覆盖Animal中的perform方法并规定perform无法再被它子类覆盖。继承后的Zookeeper知道父亲的用意,但公开地购买很多的Animal,实现了父亲的getInstance,让买来的Animal轮流替他perform,并且又重载出很多花样的perform。

重载和覆盖做了什么?

个人觉得:
覆盖做的是去掉层层继承与实现中会被java虚拟机认为是同一个函数的。
重载做的是如何让虚拟机认识这两个函数虽然名称相同,但实质不同。
我们看一行很常用的代码:a.f(argv), 其中a为某个实例对象,f为方法名,argv为若干个参数或者空
假如我们重写父类中的方法不会被覆盖掉,按照继承可以获得父类所有可访问的方法,那么子类中将会有两个方法假设名为f,且参数列表相同,那么调用f时该如何抉择呢?显然只给的a,f,argv三个参数虚拟机无法去抉择,必须覆盖掉一个。但是我们确实有写几个名称相同的方法的需求,此时a和f都是相同的,那么只有通过argv来区分了,这个过程大概就是重载吧。
先看函数名相同各种的情况:

  1.参数列表(参数列表指参数类型顺序,个数)
  2.final修饰
  3.权限修饰符
  4.返回值类型
  5.abstract修饰

函数重载时可以发生在本类中和本类与父类中,本类与父接口的默认方法中,参数列表必定不同,和final修饰,权限修饰,返回值类型,abstract修饰无关系。
方法覆盖只能发生在子类与父类或子类与父接口的默认方法间,函数名相同,参数列表相同,返回值类型可以不同但必须是其原类型的子类,不能覆盖final修饰的方法,abstract修饰符符合java规范即可。

几种特别注意的函数名相同:
1.子类覆盖父类方法do()时,提高了该方法的权限:

      Father f = new Son();
      f.do()    // 因为Son中权限的提高导致do()无法调用

2.参数列表相同,但返回值不是父类中定义类型或其子类

     Father f = new Son()  方法重名。
     A a = f.getA()  //因为被Son覆盖为返回B类型,这不是坑爹吗?

3.参数列表相同,返回值是父类中定义类型的子类

    此时Father f = new Son()
    A a = f.getA() 形如A a = new B() 形如Father f = new Son() ,没毛病.

4.抽象实现, 将父类方法改为抽象实现

    此时子类必定是个抽象类,其抽象实现的父类方法将由子类的子类实现。没毛病。

5.与父类方法参数列表不同,返回值相同。

    我给你三个参数,你却去调用父类两个参数的方法?显然是重载。 

总结


一个对象实例中有名称相同的两个方法,若参数列表相同,且两方法不在同一类中,要么是覆盖要么是不符合java规范;若参数列表不同,要么是重载,要么是不符合java规范。
【云栖快讯】你想见的Java技术专家都在这了,向大佬提问,有问题必答  详情请点击

网友评论