Java—继承
目录
1、认识继承
编辑
2、权限修饰符
3、继承的特点
3.1Java中的类为什么不支持多继承?
3.2Java中的祖宗类Object
3.3继承后子类访问成员的特点:就近原则/super讲解
4、方法重写
4.1方法重写的使用场景
5、子类构造器的特点
5.1 子类构造器的应用场景
6、this(...)调用兄弟构造器
面向对象的三大特征:封装、继承、多态。上篇文章已经介绍过封装了,下面我们来看面向对象另一个重要特征、继承。
1、认识继承
继承是什么?
- 继承是面向对象编程的核心特性之一
- 允许一个类(子类)获得另一个类(父类)的属性和方法
- 实现代码重用和建立类之间的层次关系

上面的代码有相同的name成员变量,代码大量重复。那么怎么解决代码的重复呢?类的继承。提高代码的重用性,减少一些重复代码的书写。

Java中提供了一个关键字extends,用这个关键字,可以让一个类和另一个类建立起父子关系。

子类能继承啥?
- 子类能继承父类的非私有成员(成员变量,成员方法)。
继承后对象的创建
- 子类的对象是由子类,父类共同完成的。
接下来看代码:
People类、父类
//父类
//继承的好处
//1、代码复用性高
//2、减少代码量
public class People {private String name;private char sex;public String getName() {return name;}public void setName(String name) {this.name = name;}public char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}
}
Teacher 类、子类
//子类
public class Teacher extends People {private String skill;//技术//构造器public Teacher(){}public Teacher(String skill) {this.skill = skill;}public String getSkill() {return skill;}public void setSkill(String skill) {this.skill = skill;}
}
Consultant类、子类
//子类
public class Consultant extends People{private int number; //咨询人数//构造器public Consultant(){}public Consultant(String name, char sex, int number) {this.number = number;}public int getNumber() {return number;}public void setNumber(int number) {this.number = number;}
}
Test类:测试类
//子类
public class Test {public static void main(String[] args) {//创建老师对象//子类可以继承父类的非私有成员//子类对象其实是有由子类和多张设计图共同创建出来的对象,所以子类对象是完整的Teacher t = new Teacher();t.setName("张三");t.setSex('男');t.setSkill("java");System.out.println("姓名:" + t.getName() + " 性别:" + t.getSex() + " 技术:" + t.getSkill());}
}
2、权限修饰符
什么是权限修饰符?
就是用来限制类中的成员(成员变量、成员方法、构造器)能够被访问的范围。
3、继承的特点

3.1Java中的类为什么不支持多继承?

3.2Java中的祖宗类Object
- java中所有的类,要么直接继承了Object,要么默认继承了Object,要么间接继承了Object
- 因此,Object是所有类的祖宗类

3.3继承后子类访问成员的特点:就近原则/super讲解
- 在子类方法中访问其他成员变量(成员变量、成员方法),是按照就近原则的。
- 先子类局部范围找,然后子类成员范围找,然后父类成员范围找,如果父类范围还没有找到就报错。
如果子类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类的怎么办?
可以通过super关键字,指定访问父类的成员:
super.父类成员变量/父类成员方法。
Test类
public class Test {public static void main(String[] args) {Zi zi = new Zi();zi.show();}
}
class Fu{String name = "fu类的name";
}
class Zi extends Fu{String name = "zi类的name";public void show(){String name = "局部变量";System.out.println(name);//打印show方法的 nameSystem.out.println(this.name); //打印Zi类的 nameSystem.out.println(super.name); //打印Fu类的 name}
}
打印结果如下:
继承的特点小结:

4、方法重写
当子类觉的父类的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。
重写小技巧:使用Override注解,他可以指定Java编译器,检查我们方法重写的格式是否正确,代码可读性也更好。
下面看代码了解一下方法重写怎么来实现?
public class Test {public static void main(String[] args) {Dog newDog = new Dog();newDog.cry();//就近访问原则}
}class Dog extends Animal {//有时候子类继承父类,父类的方法不能满足子类的需求,这时就需要子类重写父类的方法// 方法重写:父类方法名、参数列表必须一致.@Override //方法重写的校验注解(标志):要求方法名、参数列表必须和父类的方法一致。否则报错public void cry() {System.out.println("汪汪汪~~~");}
}class Animal {public void cry() {System.out.println("动物会叫~~~");}
}/*代码输出结果:
汪汪汪~~~*/
注意:方法重写的其它注意事项
- 子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限(public > protected > 缺省)。
- 重写的方法返回值类型,必须与重写方法返回值类型一样,或者范围更小。
- 私有方法(私有方法不能被子类继承,所以不能被重写),静态方法不能被重写(静态方法属于类只有一份),如果重写会报错。
- 在使用的时候一般不会考虑上面的注意事项,但是我们要知道,重写的规范:声明不变,重新实现。
4.1方法重写的使用场景
方法重写在开发中的常见应用场景:子类重写Object类的toString()方法,以便返回对象的内容。
Test类实现上面的场景
public class Test {public static void main(String[] args) {//方法重写:子类重新Object类的toString()方法,以便于返回对象的内容。Student s = new Student("小王", 18, '男');System.out.println(s);System.out.println(s.toString());//注意1:直接输出对象时,默认调用的是Object类的toString()方法,返回对象的地址值。//注意2:输出对象的地址实际上没什么意义。在开发中更希望输出对象的内容信息,所以子列类需要重写toString()方法。//以便以后输出对象时默认就近调用子类重写的toString方法返回对象内容。}
}class Student{private String name;private int age;private char sex;public Student(String name,int age,char sex){this.name = name;this.age = age;this.sex = sex;}public Student(){}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}//重写Object类的toString()方法@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", sex=" + sex +'}';}
}
/*代码输出结果:
Student{name='小王', age=18, sex=男}
Student{name='小王', age=18, sex=男}*/
5、子类构造器的特点
子类的全部构造器,都会先调用父类的构造器,再执行自己。
Test类:演示上面的的话
public class Test {public static void main(String[] args) {//子类的全部构造器,都会先调用父类的构造器,再执行自己。Zi z = new Zi();}
}
class Fu{//Fu类的午参构造器public Fu(){System.out.println("Fu类的无参构造器");}
}class Zi extends Fu{public Zi(){System.out.println("Zi类的无参构造器");}
}
/*代码输出结果:
Fu类的无参构造器
Zi类的无参构造器*/
子类构造器是如何实现调用父类构造器的:
- 默认情况下,子类全部构造器的第一行代码都是super()(写不写都有),它会调用父类的无参数构造器。
- 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(),指定去调用父类的有参数构造器。
Test类
public class Test {public static void main(String[] args) {//子类的全部构造器,都会先调用父类的构造器,再执行自己。Zi z = new Zi();}
}
class Fu{//Fu类的午参构造器public Fu(int a){System.out.println("Fu类的有参构造器");}
}class Zi extends Fu{public Zi(){super(1);System.out.println("Zi类的无参构造器");}
}
/*代码输出结果:
Fu类的有参构造器
Zi类的无参构造器*/
5.1 子类构造器的应用场景

People父类
//父类
//继承的好处
//1、代码复用性高
//2、减少代码量
public class People {public People(){}public People(String name, char sex) {this.name = name;this.sex = sex;}private String name;private char sex;public String getName() {return name;}public void setName(String name) {this.name = name;}public char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}
}
Teacher 子类
public class Teacher extends People {private String skill;//技术//构造器public Teacher(){}public Teacher(String skill, String name, char sex) {//调用父类的构造器//子类构造器调用父类构造器super(name, sex);this.skill = skill;}public String getSkill() {return skill;}public void setSkill(String skill) {this.skill = skill;}
}
Test测试类
public class Test {public static void main(String[] args) {//创建老师对象//子类可以继承父类的非私有成员//子类对象其实是有由子类和多张设计图共同创建出来的对象,所以子类对象是完整的Teacher t = new Teacher("java", "张三", '男');System.out.println(t.getSkill());System.out.println(t.getName());System.out.println(t.getSex());}
}
/*
输出结果
java
张三
男*/
6、this(...)调用兄弟构造器
- 任意类的构造器中,是可以通过this(...)去调用该类的其他构造器。
Student类
public class Student {private String name;private int age;private String schoolName;//构造器public Student() {}//如果所以学生的学校名称都是上海大学,那么此时可以使用this(..)调用兄弟构造器public Student(String name, int age){this(name, age, "上海大学");}public Student(String name, int age, String schoolName) {this.name = name;this.age = age;this.schoolName = schoolName;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSchoolName() {return schoolName;}public void setSchoolName(String schoolName) {this.schoolName = schoolName;}//重写toString方法@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", schoolName='" + schoolName + '\'' +'}';}
}
Test类测试类
public class Test {public static void main(String[] args) {//所有的学生学校名称都是上海大学Student s1 = new Student("张三",18);Student s2 = new Student("吴京",51);System.out.println(s1);System.out.println(s2);}
}
注意:this(...)和super(...)都只能放在构造器的第一行,因此,有了this(...)就不能写super(...)l了反之亦然。说白了两者不能同时出现。



