Java继承问题
在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写(Override)。方法重写又称方法覆盖。
重写只针对方法,子类和父类中的同名属性只是子类覆盖了父类的相同属性;
父类中的所有属性和方法都会被子类继承(private修饰的属性方法只是拥有,只能使用子类中的方法调用),子类在继承的时候,子类外部可以调用从父类中继承下来的属性和方法(私有的除外),另外 final方法、私有方法、static方法是不能重写的,但私有方法和static方法可以使用同名同参方法重新定义,但没有多态的特性。
/**
* 测试Java的继承
* @author liuhongjun
* @create 2020-11-23 20:34
*/
public class ExtendsTest {
public static void main(String[] args) {
Z z = new Z();
System.out.println("===========子类对象调用属性=============");
System.out.println(z.defaultField); //子类未定义该属性,调用的是从父类中继承的缺省属性
System.out.println(z.finalField);
System.out.println(z.protectedField);
System.out.println(z.staticField);
System.out.println(z.extendField);
System.out.println("===========子类对象调用方法=============");
z.defaultMethod();
z.protectedMethod();
z.finalMethod(); //final类型不能被重写、重定义,调用的是从父类继承的final方法
z.extendMethod();
z.staticMethod(); //调用的是子类重定义的static方法
System.out.println("=============调用属性===========");
F f = new Z(); //多态性
//调用的都是父类的属性
System.out.println(f.defaultField);
System.out.println(f.protectedField);
System.out.println(f.finalField);
System.out.println(f.staticField);
System.out.println("============调用方法============");
// 被重写的方法在编译期看左边进行调用,运行期看右边
f.protectedMethod(); //调用子类重写方法
f.staticMethod(); //子类不会重写静态方法,调用的是父类的方法,子类也有同名方法,但是不属于重写,无法调用
f.defaultMethod(); //调用子类重写方法
f.finalMethod(); //子类不会重写final方法,调用的是父类的final方法
f.method(); //调用子类重写的方法,这个是返回值类型不同
System.out.println("============强转之后调用子类属性方法============");
//需要转型,才能使用子类特有方法属性
Z zz = ((Z) f);
System.out.println(zz.extendField); //调用子类特有的属性
System.out.println(zz.protectedField); //调用子类重新定义的属性
System.out.println(zz.defaultField); //调用从父类中继承的属性
zz.extendMethod(); //调用子类特有的方法
zz.staticMethod(); //调用的是子类重定义的static方法
zz.finalMethod(); //子类不会重写final方法,调用的是父类的final方法
zz.defaultMethod(); //调用子类重写的方法
}
}
class F {
public final String finalField = "父类final属性";
public static String staticField = "父类static属性";
String defaultField = "父类缺省属性";
protected String protectedField = "父类protected属性";
private String privateField = "父类私有属性";
public static void staticMethod(){
System.out.println(">>>>>>>>>>>>>>>>>>>父类static方法");
}
//不能被重写
public final void finalMethod(){
System.out.println(">>>>>>>>>>>>>>父类final方法");
}
void defaultMethod(){
System.out.println(">>>>>>>>>>>>>>>父类缺省方法");
}
protected void protectedMethod(){
privateMethod();
System.out.println(">>>>>>>>>>>>>>>父类protected方法");
}
private void privateMethod(){
System.out.println(privateField);
System.out.println(">>>>>>>>>>>>>>>父类private方法");
}
public F method(){
System.out.println("父类返回值类型不同的重写");
return new F();
}
}
class Z extends F {
//把从父类中继承的同名属性重定义,属性没有重写的概念
public final String finalField = "子类final属性";
public static String staticField = "子类static属性";
//String defaultField = "子类缺省属性";
protected String protectedField = "子类protected属性";
private String privateField = "子类私有属性";
public String extendField = "子类扩展的属性";
public static void staticMethod(){
//静态方法中不能使用this、super关键字,这两个关键字属于对象
//this.privateMethod();
//super.defaultMethod();
System.out.println(">>>>>>>>>>>>>>>>子类static方法(重定义)");
}
//子类方法的返回值必须【小于等于】父类方法的返回值范围(父类返回值或其子类,父类为void 基本数据类型,子类就需要一致)
//子类方法的权限必须【大于等于】父类方法的权限修饰符
//子类方法的异常必须【小于等于】父类方法的异常
void defaultMethod(){
System.out.println(">>>>>>>>>>>>>>>>>>子类缺省方法(重写)");
}
protected void protectedMethod(){
System.out.println(">>>>>>>>>>>>>>>子类protected方法(重写)");
}
private void privateMethod(){
System.out.println(">>>>>>>>>>>>>>>>>>>子类private方法(重定义)");
}
//继承之后不能重写
// public final void finalMethod(){
// System.out.println(">>>>>>>>>>>>>子类final方法");
// }
public final void finalMethod(String param){
System.out.println(">>>>>>>>>>>>>子类final方法,同名不同参");
}
public Z method(){
System.out.println("子类返回值类型不同的重写");
return new Z();
}
public void extendMethod(){
System.out.println("子类中的扩展方法");
//子类通过super调用父类方法或属性
System.out.println("****************子类通过super调用父类方法或属性*******************");
super.staticMethod();
super.defaultMethod();
super.finalMethod();
super.protectedMethod();
System.out.println("********************************************************");
//调用从父类中继承下来的final方法
System.out.print("子类方法内部,调用从父类中继承下来的final方法:");
this.finalMethod();
this.finalMethod("123213");
System.out.print("子类方法内部,子类把继承过来的private方法进行了重定义:");
this.privateMethod();
}
}
在Java中,如果父类中含有一个静态方法,且在子类中也含有一个返回类型、方法名、参数列表均与之相同的静态方法,那么该子类实际上只是将父类中的该同名方法进行了隐藏,而非重写。换句话说,父类和子类中含有的其实是两个没有关系的方法,它们的行为也并不具有多态性。
正如同《Java编程思想》中所说:“一旦你了解了多态机制,可能就会认为所有事物都可以多态地发生。然而,只有普通方法的调用可以是多态的。”这也很好地理解了,为什么在Java中,static方法和final方法(private方法属于final方法)是前期绑定,而其他所有的方法都是后期绑定了。
补充:
1、权限修饰符:重写的方法的权限必须大于等于被重写的方法的权限
2、抛异常:重写的方法抛出的异常必须小于等于被重写的方法的异常
3、返回值:
1)被重写的方法为void、基本数据类型 ,则重写的方法为void、基本数据类型
2)重写的方法的返回值类型可以为被重写方法的子类(不能为父类)
代码块:由父及子,静态先行
public class Test {
public void test(){
Son son = new Son();
}
/*
父类静态代码块
子类静态代码块
父类非静态代码块
父类构造器
子类非静态代码块
子类构造器
*/
}
class Parent {
public Parent(){
System.out.println("父类构造器");
}
{
System.out.println("父类非静态代码块");
}
static{
System.out.println("父类静态代码块");
}
}
class Son extends Parent {
public Son(){
System.out.println("子类构造器");
}
{
System.out.println("子类非静态代码块");
}
static{
System.out.println("子类静态代码块");
}
}