Java—继承
目录
面向对象的三大特征:封装、继承、多态。上篇文章已经介绍过封装了,下面我们来看面向对象另一个重要特征、继承。
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方法的 name
System.out.println(this.name); //打印Zi类的 name
System.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()方法
@Override
public 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方法
@Override
public 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了反之亦然。说白了两者不能同时出现。
更多推荐



所有评论(0)