前文咱们了解了面向对象的三大特征:封装、继承、多态。html
那么在Java中是如何展示继承的特性呢?对于子类继承于父类时,又有什么限制呢?数据结构
在此解答这些问题以后,咱们再了解下类的加载过程,加深对继承的了解。ide
(若文章有不正之处,或难以理解的地方,请多多谅解,欢迎指正)this
假如咱们有两个类:生物类、猫类。spa
生物类:.net
class Animal{ private String name; public void setName(String name){ this.name = name; } public String getName(){ return this.name; } }
猫类:code
class Cat{ private String name; private String sound; public void setName(String name){ this.name = name; } public void setSound(String sound){ this.sound = sound; } public String getName(){ return this.name; } public String getSound(){ return this.sound; } }
咱们知道,猫也是属于生物中的一种,生物有的属性和行为,猫按理来讲也是有的。但此时没有继承的概念,那么代码就得不到复用,长期发展,代码冗余、维护困难且开发者的工做量也很是大。htm
继承就是子类继承父类的特征和行为,使得子类对象(实例)具备父类的实例域和方法,或子类从父类继承方法,使得子类具备父类相同的行为。
简单来讲,子类能吸取父类已有的属性和行为。除此以外,子类还能够扩展自身功能。子类又被称为派生类,父类被称为超类。对象
在Java中,若是要实现继承的关系,可使用以下语法:blog
class 子类 extends 父类{}
继承的基本实现以下:
class Animal{ private String name; public void setName(String name){ this.name = name; } public String getName(){ return this.name; } } class Cat extends Animal{} public class Test{ public static void main(String[] args){ Cat cat = new Cat(); cat.setName("猫"); System.out.println(cat.getName()); } }
运行结果为:
猫
咱们能够看出,子类能够在不扩展操做的状况下,使用父类的属性和功能。
继承的基本实现以下:
class Animal{ private String name; public void setName(String name){ this.name = name; } public String getName(){ return this.name; } } class Cat extends Animal{ private String sound; public void setSound(String sound){ this.sound = sound; } public String getSound(){ return this.sound; } } public class Test{ public static void main(String\[\] args){ Cat cat = new Cat(); cat.setName("NYforSF") cat.setSound("我不是你最爱的小甜甜了吗?"); System.out.println(cat.getName()+":"+cat.getSound()); } }
运行结果为:
NYforSF:我不是你最爱的小甜甜了吗?
咱们能够看出,子类在父类的基础上进行了扩展,并且对于父类来讲,子类定义的范围更为具体。也就是说,子类是将父类具体化的一种手段。
总结一下,Java中的继承利用子类和父类的关系,能够实现代码复用,子类还能够根据需求扩展功能。
为何子类不能多继承?举个栗子。
class ACat{ public void mewo(){...} } class BCat{ public void mewo(){...} } class CCat extends ACat, BCat{ @Override public void mewo(){...?} //提问:这里的mewo()是继承自哪一个类? }
虽然说Java只支持单继承,可是不反对多层继承呀!
class ACat{} class BCat extends ACat{} class CCat extends BCat{}
这样,BCat就继承了ACat全部的方法,而CCat继承了ACat、BCat全部的方法,实际上CCat是ACat的子(孙)类,是BCat的子类。
总结一下,子类虽然不支持多重继承,只能单继承,可是能够多层继承。
对于子类来讲,父类中用private修饰的属性对其隐藏的,但若是提供了这个变量的setter/getter接口,仍是可以访问和修改这个变量的。
class ACat { private String sound = "meow"; public String getSound() { return sound; } public void setSound(String sound) { this.sound = sound; } } class BCat extends ACat { } public class Test { public static void main(String[] args) { BCat b = new BCat(); b.setSound("我不是你最爱的小甜甜了吗?"); System.out.println(b.getSound()); } }
父类已经定义好的final修饰变量(方法也同样),子类能够访问这个属性(或方法),可是不能对其进行更改。
class ACat { final String sound = "你是我最爱的小甜甜"; public String getSound() { return sound; } public void setSound(String sound){ this.sound = sound; //这句执行不了,会报错的 } } class BCat extends ACat { }
总结一下,用private修饰的变量能够经过getter/setter接口来操做,final修饰的变量就只能访问,不能更改。
在实例化子类对象时,会调用父类的构造方法对属性进行初始化,以后再调用子类的构造方法。
class A { public A(){ System.out.println("我不是你最爱的小甜甜了吗?"); } public A(String q){ System.out.println(q); } } class B extends A { public B(){ System.out.println("你是个好姑娘"); } } public class Test { public static void main(String[] args) { B b = new B(); } }
运行结果为:
我不是你最爱的小甜甜了吗? 你是个好姑娘
从结果咱们能够知道,在实例化子类时,会默认先调用父类中无参构造方法,而后再调动子类的构造方法。
那么怎么调用父类带参的构造方法呢?只要在子类构造方法的第一行调用super()方法就好。
class A { public A(String q){ System.out.println(q); } } class B extends A { public B(){ super("我是你的小甜甜?"); System.out.println("你是个好姑娘"); } } public class Test { public static void main(String\[\] args) { B b = new B(); } }
运行结果为:
我是你的小甜甜? 你是个好姑娘
在子类实例化时,默认调用的是父类的无参构造方法,而若是没有父类无参构造方法,则子类必须经过super()来调用父类的有参构造方法,且super()方法必须在子类构造方法的首行。
总结一下,Java继承中有三种继承限制,分别是子类只能单继承、父类中private修饰的变量不能显式访问和final修饰的变量不能改变,以及实例化子类一定会先调用父类的构造方法,以后才调用子类的构造方法。
(此处只是粗略介绍类加载的过程,想了解更多可参考《深刻理解Java虚拟机》)
类加载过程包括三个大步骤:加载、链接、初始化。
这三个步骤的开始时间仍然保持着固定的前后顺序,可是进行和完成的进度就不必定是这样的顺序了。
总结一下,类加载的过程当中,首先会对Class文件中的类提取并转换成运行时数据结构,而后对类的父类和这个类的数据信息进行检验以后,为类中的类变量分配内存而且设置初始值,接着将Class文件中与这个类有关的符号引用转换成直接引用,最后再执行类构造器。
并且咱们能够从第二步看出,在加载类的时候,会先去检查这个类的父类的信息,而后再检查这个类的方法体,也就是说,在加载类的时候,会先去加载它的父类。
初学Java的时候知道这些概念,但只是浅尝而止。如今跟着Hollis大佬的《Java 工程师成神之路!》,从新回顾这些知识的时候,发现若是本身只是像之前同样片面了解,那岂不是没有成长?因此在写文章的过程当中,尝试写得更加深刻且尽可能易懂。固然,本人水平有限,若有不正之处,欢迎指正。
若是本文对你有帮助,请点一个赞吧,这对我来讲是最大的动力~
参考资料: