欢迎访问宙启技术站
智能推送

Java函数的重载和覆盖的概念及其区别

发布时间:2023-06-24 13:13:26

Java中的函数重载(Overloading)和函数覆盖(Override)是两种常用的函数特性,它们都是用于实现函数多态性的。

函数重载:在Java中,一个类可以定义多个同名但形参列表不同的函数,这就被称为函数重载。

例如,对于一个类C,我们可以定义两个同名但形参列表不同的函数f1和f2:

class C{
    public int f1(int x){
        return x+1;
    }
    
    public double f2(double y){
        return y+1;
    }
}

这里,函数f1和f2都是类C的成员函数,它们都有相同的函数名,但是它们的形参列表不同(一个接收int类型的参数,另一个接收double类型的参数),因此可以说它们构成了函数重载。当我们在调用这两个函数时,Java编译器会自动匹配实参的类型和形参列表,从而选择调用合适的函数。

例如,下面的代码调用了类C的成员函数f1和f2:

public class Test{
    public static void main(String[] args){
        C obj = new C();
        System.out.println(obj.f1(10));   // 输出11
        System.out.println(obj.f2(3.14)); // 输出4.14
    }
}

在调用obj.f1(10)时,Java编译器发现函数f1接收int类型的参数,实参是一个int类型的常量10,因此自动匹配调用f1函数,将返回值11输出;在调用obj.f2(3.14)时,Java编译器发现函数f2接收double类型的参数,实参是一个double类型的常量3.14,因此自动匹配调用f2函数,将返回值4.14输出。

函数覆盖:在Java中,当子类继承了父类的某个函数并且重新定义了该函数,这就被称为函数覆盖。

例如,对于一个父类P和一个子类S,我们可以定义一个父类函数f和子类函数g:

class P{
    public void f(){
        System.out.println("I am P");
    }
}

class S extends P{
    public void g(){
        System.out.println("I am S");
    }
    
    @Override
    public void f(){
        System.out.println("I am overridden by S");
    }
}

这里,类P定义了一个成员函数f,类S继承了类P并定义了自己的成员函数g,并重写了类P的函数f。注意,在类S中,我们使用了@Override注解来告诉Java编译器,我们正在对类P中的函数f进行覆盖。

当我们在调用S类的函数f时,会优先调用S类中的函数,因为S类已经重写了P类中的函数f。例如,下面的代码调用了S类的成员函数f和g:

public class Test{
    public static void main(String[] args){
        S obj = new S();
        obj.f(); // 输出 I am overridden by S
        obj.g(); // 输出 I am S
    }
}

在调用obj.f()时,Java编译器发现S类重写了函数f,因此自动匹配调用S类中的函数f,将字符串"I am overridden by S"输出;在调用obj.g()时,Java编译器发现S类定义了一个成员函数g,因此自动匹配调用S类中的函数g,将字符串"I am S"输出。

函数重载和函数覆盖的区别:

1. 形参列表不同。函数重载依赖于形参列表的不同,而对于函数覆盖,子类必须和父类有相同的函数名、返回值类型、形参列表和访问修饰符。

2. 发生时间不同。函数重载在编译时期就确定了,而函数覆盖是在运行时期才确定的,也就是说,函数重载的选择过程由编译器完成,而函数覆盖的选择过程由JVM执行,根据实际类型来确定调用哪个函数。

3. 目的不同。函数重载是为了提高程序的灵活性和可读性,对于不同的参数类型和参数个数,使用同一函数名,不至于让函数名过于复杂,同时也方便程序员使用。而函数覆盖则是为了实现多态性,在程序运行时根据实际类型来调用相应的子类函数。