继承的概念
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。Java中类只支持单继承,Java中可以多层(重)继承(继承体系),java.lang.Object类是所有类的父类。
生活中的继承:
兔子和羊属于食草动物类,狮子和豹属于食肉动物类。
食草动物和食肉动物又是属于动物类。
所以继承需要符合的关系是:is-a,父类更通用,子类更具体。
虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。
类的继承格式
class 父类 { } class 子类 extends 父类 { }
继承的注意事项
-
子类只能继承父类所有非私有的成员(成员方法和成员变量)
-
子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
-
不要为了部分功能而去继承
-
super关键字
1.在Java类中使用super来引用父类的(属性、方法和构造器) 2.super可用于访问父类中定义的属性 3.super可用于调用父类中定义的成员方法 4.super可用于在子类构造器中调用父类的构造器
-
调用父类构造器
1.在子类的构造器中一定要调用一次父类的构造器,系统默认调用的是父类无参数的构造器。2.如果子类构造器中既未显式调用父类构造器,而父类中又没有无参的构造器,则编译出错 3. 如果父类没有无参数的构造器,在子类的构造器中可使用语句super()调用父类相应有参数的构造器
常见面试题1:
class Test02_Extends {
public static void main(String[] args) {
Zi z = new Zi();
}
/*
1,jvm调用了main方法,main进栈
2,遇到Zi z = new Zi();会先将Fu.class和Zi.class分别加载进内存,再创建对象,当Fu.class加载进内存
父类的静态代码块会随着Fu.class一起加载,当Zi.class加载进内存,子类的静态代码块会随着Zi.class一起加载
第一个输出,静态代码块Fu,第二个输出静态代码块Zi
3,走Zi类的构造方法,因为java中是分层初始化的,先初始化父类,再初始化子类,所以先走的父类构造,但是在执行
父类构造时,发现父类有构造代码块,构造代码块是优先于构造方法执行的所以
第三个输出构造代码块Fu,第四个输出构造方法Fu
4,Fu类初始化结束,子类初始化,第五个输出的是构造代码块Zi,构造方法Zi
*/
}
class Fu {
static {
System.out.println("静态代码块Fu");
}
{
System.out.println("构造代码块Fu");
}
public Fu() {
System.out.println("构造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("静态代码块Zi");
}
{
System.out.println("构造代码块Zi");
}
public Zi() {
System.out.println("构造方法Zi");
}
}
执行顺序:父类>子类 静态>非静态
常见面试题2:
解析:父类的printB和printC都是私有的,子类不能重写,所以就调了父类的方法。
父类中的方法public void printABC()在子类中没有重写,所以在子类对象调用这个方法的时候,实际上是调用的父类里面的printABC()方法,父类里面的printABC()方法又会去调用父类里的三个方法printA(),printB(),printC(),这三个方法除非被覆盖,否则就还是输出父类里面定义的内容。
类的静态变量和静态方法能否被子类继承? 结论:java中静态属性和静态方法可以被继承,但是没有被重写(overwrite)而是被隐藏.
常见面试题3:向上转型
public class day01_1 {
public static void main(String[] args) {
Shape sh = new circle();
System.out.println(sh.name);
sh.printType();
sh.printName();
}
}
class Shape{
public String name = "shape";
public Shape(){
System.out.println("shape constructor");
}
public void printType() {
System.out.println("this is shape");
}
public static void printName() {
System.out.println("shape");
}
}
class circle extends Shape{
public String name = "circle";
public circle(){
System.out.println("circle constructor");
}
public void printType() {
System.out.println("this is circle");
}
public static void printName(){
System.out.println("circle");
}
}
解析:因为指向子类的引用向上转型变成了shape,所以他只能访问父类的属性和方法。当父类的引用指向子类时,使用对象调用静态方法或者静态变量,是调用的父类中的方法或者变量。注:在Java中,只能重写方法,不会重写成员变量,而是隐藏成员变量。
参考:1.https://blog.youkuaiyun.com/JavaCoder_juejue/article/details/81112692 2.https://www.cnblogs.com/qsymg/p/9870945.html 3.https://www.cnblogs.com/qsymg/p/9870945.html 4.https://blog.youkuaiyun.com/qdh186/article/details/79807057