重载和覆盖
重载(overload):
对于类中的方法(包括从父类中继承的方法),方法名相同,参数列表不同,就可以构成重载关系。
参数列表不同,又可以分为参数类型、参数的个数、参数的顺序。
重载与访问权限修饰符和返回值无关。
覆盖(override):
发生在子父类中,当父类中的某些方法不能满足要求时,子类中改写父类的方法,当父类的方法被覆盖后,除非用super.方法名()来调用。
发生覆盖的条件:
1、三同一不低:
子类和父类的方法名,返回值类型和参数列表必须完全相同,而且子类方法的访问修饰符的权限不能比父类低。(其实子类的方法返回值可以返回父类方法返回值的子类,当调用时会产生多态现象,当父类方法返回Number时,子类覆盖的方法返回Integer类型)
2、被覆盖的方法不能使final类型的,因为final修饰的方法无法被覆盖。
3、被覆盖的方法不能是private,否则在其子类中只是重新定义了一个方法,并没有对其进行覆盖,因为私有,子类看不到,谈不上覆盖。
4、子类不能比父类抛出更多的异常,即子类方法所抛出的异常必须和父类所抛出的异常一致或者是其子类,或什么都不抛出。
5、被覆盖的方法不能是static,如果父类中方法是静态,子类中是非静态的,那么会发生编译错误。原因:
即使父类和子类的方法都是静态的,并满足覆盖条件,但仍不会发生覆盖,因为静态方法是在编译的时候把静态方法和类的引用类型进行匹配,可以理解成父类中的静态方法和父类绑定在一起,在继承的时候,子类中隐藏了父类的静态方法,调用的时候Fu f = new Zi(); f.show()当调用静态方法的时候,系统不在乎是哪个对象调用,而是直接看这个引用变量是什么类型的.
子类不会比父类抛出更多的异常,应该一样或者比父类小,原因:
父类抛出A异常,当Fu类有子类的时候,根据多态可以写成Fu f = new Zi(); 引用f指向子类对象,子类中把父类抛出的异常的方法进行覆盖,但是由于子类继承了父类,所以子类可以抛出异常的方法不能抛出新的异常,必须在父类抛出的异常范围之内,另外 父类的方法调用者已经做好了父类异常捕获的准备,用多态调用时,却出现捕获之外的异常,jvm只能使程序终止.
关于非静态内部类中为什么不能有静态成员(成员变量或方法)
非静态内部类依赖一个外部类的对象,对于外部类而言,非静态内部类只是一个成员,正常加载类时,先加载外部类-->创建外部类对象-->加载内部类-->初始化变量,但是jvm要求所有静态变量必须在对象创建之前完成加载,这就互相矛盾,对于非静态内部类而言,可以有static final int NUM = 3,原因:此时NUM属于java常量,存放于内存中的常量池中,加载常量和加载类的时机无关.
多态下的成员变量和成员方法调用
Fu f = new Zi();
字段:
新创建的Zi类对象中有2个num字段
image.png
引用为父类型的引用,他调用自己的成员变量,相当于继承的时候,父类的成员变量隐藏了(变量名想用,不管类型),简单来说,引用类型是谁的,就调用谁的成员变量.
编译运行都看左边
成员方法:
成员方法调用实际上是堆内存中的对象调用,但编译的时候要现在引用所属的类中检查是否有这个方法,没有就报错(编译器认为,Fu f调用的是父类中的方法),但运行时,尽管是f.show();Fu类型引用调用方法,但实际上是new Zi() 这个对象在调用,show()方法进行动态绑定在调用他的对象上,他会在子类中找有没有show()方法,如果没有就执行父类继承过来的方法.
编译看左边,运行看右边
静态方法:
对于静态方法调用是不需要对象的,系统在加载的时候直接把静态方法加载到数据共享区,每个静态方法都有自己的类所属,静态绑定,调用的时候直接看引用是什么类类型的就可以了
编译运行都看左边
静态属性,非静态属性,静态方法都可以被继承.然后会被隐藏,但是当子类中有没重名的成员变量或者静态方法,则调用父类的属性或方法,如果子类有,那么就调用子类的
非静态方法,调用就执行多态
继承时父类中有私有方法
因为private对类外面是不可见的,系统检查的时候看不到,子类对象转型为父类类型引用,检查任务f.show()调用的是父类方法,父类中如果是私有就报错(方法不可见),对于匿名对象调用方法,如果他所属的类中方法是私有,就编译失败,如果说在子类中或父类中定义了私有方法,因为在同一类中可见,所以编译通过,如果在父类中子类对象向上转型,f.show()调用的仍然是父类的私有方法(此时说的情况是main方法在子父类中)