关于Java中重载和重写的一些问题
重载:
概念:
指 在一个类中,多个方法(包括构造方法)的方法名相同,但是形参列表不同,即参数个数、类型、顺序不同。调用时,Java虚拟机(JVM)会根据传入的实参列表,去选择合适的方法执行。
重载,是一个类中 多态的表现;
注意:
1.不能对 访问权限、返回类型、抛出的异常 进行重载;
2.使用重载时只能通过不同的形参列表,且必须具有不同的列表;
3.异常的类型和数目不会影响重载;
举例:
1.返回类型不同 或者 参数类型相同,顺序不同,不能重载
public static int add(int a,int b){
return (a+b);
}
public static long add(int a,int b){
return (a+b);
}
2.参数类型,个数、顺序 不同 可以 重载(可以有不同的 访问权限,返回类型)
public static void main(String[] args) {
// 根据 传入实参不同 调用相应的方法
add(1,'s'); // 注意 此处 没有匹配到 方法,则会 隐式转换,就近原则转换。
add(1,2L);
add(1L,2);
}
// 测试 方法的重载
public static int add(int a,int b){
System.out.println("1.111");
return (a+b);
}
private static long add(int a,long b){
System.out.println("2.2222");
return (a+b);
}
protected static int add(long b,int a){
System.out.println("3.333");
return (int) (a+b);
}
重写:
概念:
首先,重写,是针对,继承关系的父类和子类之间关系的。
子类继承父类,继承了父类中所有(非私有,不同包则 非默认)属性和方法,
当子类可以根据需要修改父类的方法,扩展其功能,这样的操作就称为
重写,也叫覆写/覆盖.重写:是指子类中的方法与父类中继承的方法有完全相同的返回值类型、方法名、参数个数以及参数类型。
重写规则:
==”两同两小一大“规则==
”两同“:方法名,形参列表 相同;
“两小”:子类的 返回值类型,抛出的异常,小于父类;
比如:父类抛出IOException 则子类只能抛出 同类型以及 其子异常;
“一大”:子类的 访问权限,大于 父类的 访问权限;
比如:父类是 默认 权限,则子类只能是同权限或者 protected或者
public(注意,默认权限,异包子类不能访问)。
调用规则:
对于 父类对象:
调用的是 自身的 方法;
对于子类对象:
F s = new S();// 父类变量 指向 子类 实例
s.add();
调用的是 重写的 方法,当子类没有重写父类的 方法时 ,调用的是 父类的方法。
public static void main(String[] args) {
F f = new F();
f.add();// 调用自身 方法
F s = new S();
s.add();// 调用 重写 方法
s.add3();// 调用 父类 方法
}
class F{
void add(){
System.out.println("父类add方法");
}
protected void add2(){
System.out.println("父类add2方法");
}
public void add3(){
System.out.println("父类add3方法");
}
}
class S extends F{
public void add(){// 重写 时 访问权限 应 大于等于 父类
System.out.println("子类add2方法");
}
protected void add2(){
System.out.println("子类add2方法");
}
}
重载和重写的区别;
override(重写)
1、方法名、参数、返回值相同。
2、子类方法不能缩小父类方法的访问权限。
3、子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
4、存在于父类和子类之间。
5、方法被定义为final不能被重写。
overload(重载)
1、参数类型、个数、顺序至少有一个不相同。
2、不能重载只有返回值不同的方法名。
3、存在于父类和子类、同类中。
对于重写的一点深入探讨
先上代码:
public class Base {
private String baseName= "base";
public Base(){
callName();
}
public void callName(){
System.out.println(baseName);
}
static class Sub extends Base{
private String baseName = "sub";
public void callName(){
System.out.println(baseName);
}
}
public static void main(String[] args){
Base b = new Sub();
}
}
上述代码输出时什么?
分析:
1.首先,看结构,一个外部类,一个静态内部类,静态内部类继承了外部类,最后一个main方法测试。
2.我们看,main方法中 Base b = new Sub(); 父类变量 指向了 子类的引用,那么明显的,在方法中调用的是 子类的callName 方法。
这里我们要清楚调用顺序:
new Sub() 时 是先创建 父类对象,再去创建 子类对象,即,先会调用 父类的构造器,则会调用 callName() 方法,而 该方法 被 子类重写,则会调用 子类的callName() 方法,但是,此时 子类还没有构造,那么 这里的 baseName 就是 一个 null 值;
3.
执行 Base b = new Sub();时,由于多态 b编译时表现为Base类特性,运行时表现为Sub类特性,Base b = new Sub();不管是哪种状态都会调用Base构造器执行 callName()方法;执行方法时,由于多态表现为子类特性,所以会先在子类是否有 callName();而此时子类尚未初始化(执行完父类构造器后才会开始执行子类),如果有 就 执行(此时,因为还没有调用子类构造函数, 所以子类的 baseName 输出为 null),没有再去父类寻找。
如果是这样的:
public static void main(String[] args){
Base b = new Sub();
b.callName();
}
则会输出 :
null
sub
总的来说: