Java Basics series (a) - Overload (Overload) and rewritable (Override)

First, the method signature

  • In Java, the so-called method signature is the method name + parameter type
  • For example a method public void fun(int a) throws IOException{ }, the method signature is herefun(int)
  • Note: The return type is not part of the method signature

Second, the method overloading (Overload)

  • First, let's look at the definition of method overloading

Method overloading refers to a class defined in the method a plurality of the same name , but the number of methods have different requirements for each type of parameter or parameters . When calling overloaded method, Java compiler to check the method invoked by the type and number of parameters to select an appropriate method. Method overloading often used to create a complete set of similar tasks but in a different order number or type of parameters or parameters of the process parameters. [1] Java method overloaded, that is, can create a plurality of class methods, they may have the same name, but must have different parameters, i.e. parameters or a different number or different types of parameters . DETAILED to decide which method to use them by passing different number and type of parameters, and the order of the parameters passed when calling the method

  • Then we come to discuss the following situations if the count method overloading?

2.1 method of the same name and the same parameter list, but different return values?

  • If a class has int fun(int a)and double fun(int a)two methods, the calculation method overloading it? Directly on the code
public class MyOverload {
    public void fun(int a) {

    }

    public double fun(int a) {

        return 0.0;
    }
}
  • operation result
    • Compilation error , the error message is: 'fun(int)' clashes with 'fun(int)'; both methods have same erasure 'fun(int)' is already defined in 'thinking.about_override_overload.MyOverload'probably meaning that the class have the same method signaturefun(int)
    • 01. Overload same return value different from the parameter list
  • in conclusion
    • If the two methods method name and parameter list the same , but the return value is not the same , then this is not overloaded . Because the same method name and parameter list, is the method signature of the same , and the same class is not allowed to have two identical method signatures exist

2.2 method of the same name, but the list of parameters and return values ​​differ?

  • If the above example of code changes as follows
public class MyOverload {
    public void fun(int a) {

    }

    public double fun(int a, int b) {

        return 0.0;
    }
}
  • operation result
    • Compiled by
  • in conclusion
    • If the two methods method same name , but the list of parameters and return values are different , then this is part of method overloading . Because method overloading nothing to do with the return value , two different methods since the parameter list, then it represents the different method signature (same method names), it belongs to reload.

2.3 method of the same name and same argument list, but an exception is thrown different?

  • Directly on the code
public class MyOverload {
    public void fun(int a) throws IOException {

    }

    public void fun(int a) throws CloneNotSupportedException {

    }
}
  • In fact, from the above two examples can be launched answer. Because no matter how you change the thrown exception, these two methods method signature is the same , certainly not by the compiler, so I do not belong to reload.
  • 02. Overload thrown different

2.4 Summary

  • The method constitutes overloading, only with the method name and parameter list, which is the method signature. When the same method name and parameter list is not the same, then it constitutes a heavy load. Remember that method overloading nothing to do with the following:
    • Method overloading and independent return value
    • Method overloading and being thrown unrelated
    • 方法重载与 参数名称无关
  • 对于为什么方法重载只和方法名和参数列表有关,而和返回值无关呢?在《Java编程思想(第4版)》中有这么一段话:

5.2.3 以返回值区分重载方法
读者可能会想:“在区分重载方法的时候,为什么只能以类名和方法的参数列表作为标准呢?能否考虑用方法的返回值来区分?”
比如下面两个方法,虽然它们有同样的名字和形式参数,但却很容易区分他们:
void f(){}
it f(){return 1;}
只要编译器可以根据语境明确判断出语义,比如在int x=f()中,那么的确可以据此区分重载方法。不过,有时你并不关心方法的返回值,你想要的是方法调用的其他效果(这常被称作为“为了副作用而调用”),这时你可能会调用方法而忽略其返回值。所以,如果像下面这样调用方法:
f();
此时Java如何才能判断该调用那一个f()呢?别人该如何理解这中代码呢?
因此 ,根据方法的返回值来区分重载方法是行不通的。

  • 也就是说,假如Java允许一个类中有两个具有相同方法签名而返回值不同的方法存在,那么当我们忽略返回值而调用方法的时候,JVM将不知道调用哪个方法,所以这是不允许的。

三、方法重写(Override)

  • 我们一样先来看一下方法重写的定义
  • 在Java和其他一些高级面向对象的编程语言中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
  • 若子类中的方法与父类中的某一方法 具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。 如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
  • 了解完定义后,我们来验证以下情况是否符合方法重写

3.1 重写父类方法是否可以更改参数列表?

  • 首先定义父类A,其中的方法声明为 protected void fun(int a, int b)
public class A {
    protected void fun(int a, int b) {
    
    }
}
  • 定义类B继承类A,并将其方法声明改为 protected void fun(int a)
public class B extends A {
    @Override
    protected void fun(int a) {
    
    }
}
  • 运行结果
    • 如果有@Override注解的话会编译报错,错误信息为Method does not override method from its superclass 大概意思是说该方法不是从父类所继承,所以不能加@Override注解03. The method of rewriting changes the parameter list
  • 结论
    • 重写父类方法不可以更改参数列表,编译报错的原因是加上了@Override注解,而此时的方法签名与父类方法签名不一致,所以出错。去掉@Override的话不报错,但是由于方法签名不一致,已经不算重写了

3.2 重写父类方法是否可以更改返回值?

  • 从上面的例子我们不妨大胆猜想,如果返回值与父类不一致,那么在加上@Override的情况下就会报错。真实情况是否是这样呢?我们来验证一下
  • 第一种情况:当返回值是基本数据类型时,更改子类B的代码如下,将其返回值改为void
public class B extends A {
    @Override
    protected double fun(int a, int b) {
    	
    	return 0.0;
    }
}
  • 运行结果
    • 编译报错,错误信息为'fun(int, int)' in 'thinking.about_override_overload.B' clashes with 'fun(int, int)' in 'thinking.about_override_overload.A'; attempting to use incompatible return type,大概意思是说B类中的fun()与A类中的fun()返回类型冲突04. Rewrite the return value changes
  • 结论
    • 当返回值是基本数据类型时方法重写不可以更改返回值
  • 第二种情况:当返回值不是基本数据类型,也就是引用数据类型时,更改A类和B类的代码如下
public class A {
    protected A fun(int a, int b) {

        return new A();
    }
}
public class B extends A {
    @Override
    protected A fun(int a, int b) {

        return new A();
    }
}
  • 运行结果
    • 编译通过
  • 继续修改子类B,将其返回值改为B(B 是 A 的子类)
public class B extends A {
    @Override
    protected B fun(int a, int b) {

        return new B();
    }
}
  • 运行结果
    • 程序一样编译通过
  • 继续修改子类B,将其返回值修改为 Object (Object 是 A 的父类)
public class B extends A {
    @Override
    protected Object fun(int a, int b) {

        return new Object();
    }
}
  • 运行结果
    • 编译报错,提示类型冲突。
  • 结论
    • 从上面的例子我们可以得出,重写方法时是否可以更改返回值 由根据父类方法的返回值决定*
      • 如果父类方法返回值是基本数据类型,那么子类重写父类方法时 不可以更改其返回值
      • 如果父类方法返回值是引用数据类型,那么子类重写父类方法时 可以更改其返回值,但是前提是子类方法的返回值类型必须与父类方法的返回值类型一致,或者子类方法的返回值类型是父类返回值类型的子类

3.3 重写父类方法是否可以更改访问权限修饰符?

  • 父类A的fun()的访问权限修饰符为protected,将子类B的fun()的访问权限修饰符改为private,直接上代码
public class B extends A {
    @Override
    private void fun(int a, int b) {
       
    }
}
  • 运行结果
    • 编译报错,错误信息为'fun(int, int)' in 'thinking.about_override_overload.B' clashes with 'fun(int, int)' in 'thinking.about_override_overload.A'; attempting to assign weaker access privileges ('private'); was 'protected',大概意思是说子类使用了更严格的访问权限05. Rewrite change access modifiers
  • 结论
    • 方法重写可以更改访问权限修饰符,但是前提是子类的访问权限不能比父类更严格。也就是说,如果父类使用的是public,那么子类就不可以使用protected、default、private;如果父类使用的是protected,那么子类就不可以使用default、private。以此类推…
  • 说明
    • 访问权限的范围从大到小依次是:public > protected > default(包访问权限) > private

3.4 重写父类方法是否可以更改所抛出异常?

  • 修改父类A,为其抛出 IOException
public class A {
    protected void fun(int a, int b) throws IOException {

    }
}
  • 修改子类B,为其抛出 IOException 和 CloneNotSupportedException
public class B extends A {
    @Override
    protected void fun(int a, int b) throws IOException, CloneNotSupportedException {
        
    }
}
  • 运行结果
    • 编译报错,出错信息为'fun(int, int)' in 'thinking.about_override_overload.B' clashes with 'fun(int, int)' in 'thinking.about_override_overload.A'; overridden method does not throw 'java.lang.CloneNotSupportedException',意思是说类B的fun()不能抛出CloneNotSupportedExceptionHere Insert Picture Description
  • 继续修改子类B,将抛出的异常全部去除
public class B extends A {
    @Override
    protected void fun(int a, int b) {
        
    }
}
  • 运行结果
    • 编译通过
  • 继续修改子类B,为其抛出 Exception
public class B extends A {
    @Override
    protected void fun(int a, int b) throws Exception {

    }
}
  • 运行结果
    • 编译不通过,因为抛出的 Exception是IOException的父类
  • 继续修改子类B,为其抛出 IOException 和 FileNotFoundException
public class B extends A {
    @Override
    protected void fun(int a, int b) throws IOException, FileNotFoundException {

    }
}
  • 运行结果
    • 编译通过,因为 FileNotFoundException是IOException的子类
  • 结论
    • 方法重写可以更改抛出的异常,但是前提是子类方法所抛出的异常不能比父类方法所抛出的异常范畴更大
    • 也就是说,假如父类抛出IOException,那么子类不能抛出Exception (因为其是IOException的父类),也不可以多抛出CloneNotSupportedException (因为CloneNotSupportedException并不是IOException的子类),但是可以多抛出一个FileNotFoundException (因为其是IOException的子类)

3.5 小结

  • 对于方法重写来说,需要注意以下几点
    • 发生方法重写的两个方法 返回值、方法名、参数列表必须完全一致 (子类重写父类的方法)
    • 子类抛出的异常下 不能超过父类相应方法抛出的异常 (子类异常不能大于父类异常)
    • 子类方法的 访问级别不能比父类相应方法的访问级别更严格 (子类访问级别不能低于父类访问级别)
    • 子类重写父类方法的 返回值类型不能大于父类方法的返回值类型,即是说 子类方法的返回值必须和父类方法的返回值相同或是其子类

4. 重载和重写的区别

  • 从定义来说
    • 重载是函数名称相同,参数的类型或者个数不同
    • 重写是函数名称、参数类型及个数完全相同
  • 从范围来说
    • 重载是发生在一个类中
    • 重写是发生在继承关系中
  • 从限制来说
    • 重载没有访问权限和返回值的限制
    • 重写不能拥有比父类更严格的访问权限,不能抛出比父类范畴更大的异常,返回值不能是父类方法返回值的父类
Released four original articles · won praise 2 · Views 127

Guess you like

Origin blog.csdn.net/a1092882580/article/details/103493047