从零开始的Java学习生活(15)


前言

在前篇文章中我们讲解了Java三大特性之一的封装性,本篇文章中我们将继续对面向对象编程的学习,了解并学习剩下的两大特性之一的继承性。

一、继承

**继承(inherit)**也是面向对象三大特性之一。

生活中的继承:某某继承了父亲百亿资产;某某继承了家族产业等等。

简单来看,继承就是获得了原本不属于自己的东西。在Java中亦是如此。

举个栗子:

某公司正在开发一款高校教学、教务管理系统。其中涉及到教师(Teacher)、辅导员(Assistant)、学生(Student)的信息管理。抛开教师、辅导员、学生的增删改查,如何用Java类表示教师、辅导员、学生?

通过分析:我们需要3个类Teacher、Assistant、Student

Teacher类有姓名、性别、年龄、职称,能授课、能管理学生。

Assistant类有姓名、性别、年龄,能管理学生。

Student类有姓名、性别、年龄,能学习。

通过观察,你会发现这3个类有部分特征和行为是相同的。都有姓名、性别、年龄属性,都有对应的setter、getter方法。如果要完整的表示这3个类,会更多的属性,更多的setter、getter方法。

如果一个项目比较大,有几百个类,要写多少代码?能不能优化?

保留这个疑问我们继续往下看。

二、使用继承

Java提供了继承(inherit)功能。继承可以解决我们上述的问题。

父类:在继承关系里,被继承的类叫做父类,也叫基类或超类。

子类:在继承关系里,继承别的类的类叫子类,也叫派生类。

而父类和子类是相对而言的。

1.继承的语法

public class 类名 extends 父类名{
    //属性
    //方法
}

通过继承,我们可以将上述案例中相同的特征和行为进行抽取,放到一个单独的类中,把这个类作为父类,再让现有的类继承于这个单独的类,这样就可以继承父类中的特征和行为。

上代码:

公共父类Person

public class Person {
	//属性
	private String name;	//姓名
	private String sex;		//性别
	private int age;		//年龄
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

Teacher类

public class Teacher extends Person{
	//属性
	private String title;	//职称
	
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	
	//构造方法
	public Teacher() {

	}
	
	public Teacher(String name, String sex, int age, String title) {
		this.setName(name);
		this.setSex(sex);
		this.setAge(age);
		this.title = title;
	}
	
	//方法
	public void teach() {
		System.out.println(this.getName() + "老师正在认真的讲课");
	}
	
	public void manageStudents() {
		System.out.println("管理学生");
	}
    
    public void showInfo() {
		System.out.println(this.getName() + "," + this.getSex() + "," + this.getAge() + "," + title);
	}
}

Assistant类:

public class Assistant extends Person{
	//属性
	
	//构造方法
	public Assistant() {
		
	}
	
	public Assistant(String name, String sex, int age) {
		this.setName(name);
		this.setSex(sex);
		this.setAge(age);
	}
	
	//方法
	public void manageStudents() {
		System.out.println("管理学生");
	}
    
    public void showInfo() {
		System.out.println(this.getName() + "," + this.getSex() + "," + this.getAge());
	}
}

Student类

public class Student extends Person{
	//属性
	
	//构造方法
	public Student() {
		
	}
	
	public Student(String name, String sex, int age) {
		this.setName(name);
		this.setSex(sex);
		this.setAge(age);
	}
	
	//方法
	public void study() {
		System.out.println("Good good study, day day up");
	}
    
    public void showInfo() {
		System.out.println(this.getName() + "," + this.getSex() + "," + this.getAge());
	}
}

测试代码自编即可。

通过继承,我们发现代码明显少了很多,而且能实现继承前全部的功能。但美中不足的地方是,构造方法赋值比较麻烦,那能不能优化呢?

2.父类、子类构造方法

子类可以从父类中继承属性和方法,无法继承构造方法,但可以调用父类中的构造方法为我们继承过来的属性赋值

比如在父类Person中添加构造方法如下:

//父类构造方法
	public Person() {
		
	}
	public Person(String name, String sex, int age) {
		this.name = name;
		this.sex = sex;
		this.age = age;
	}

在不同的子类中就可以按照如下的格式修改构造方法:

Teacher类:

//构造方法
	public Teacher() {

	}
	
	public Teacher(String name, String sex, int age, String title) {
		super(name, sex, age);
		this.title = title;
	}

Assistant类

public Assistant() {
		
	}
	
	public Assistant(String name, String sex, int age) {
		super(name, sex, age);
	}

显然,修改之后,代码仍然能正确的运行。我们可以发现在子类构造方法中有一个新的关键字——super;

3.super关键字

super是一个特殊的关键字,这个关键字用于访问父类中的方法和属性(super相当于父类类名)。

注:private修饰的属性和方法无法直接访问(super.属性名或者super.方法名())。因为private修饰的属性和方法只能在本类中访问。

虽然不能访问,但肯定是继承了。

如果理解了可以直接跳过下面内容,没有的话我们一起写一个样例练习来加深了解。

定义2个类,Son类和Father类,Son继承于Father。

Father类代码:

public class Father {
	//属性
	int a;
	private int b;
	
	//getter、setter
	public int getB() {
		return b;
	}
	public void setB(int b) {
		this.b = b;
	}
	//构造方法
	public Father() {
		
	}
	public Father(int a, int b) {
		this.a = a;
		this.b = b;
	}
	
	//打印对象信息
	public void showInfo() {
		System.out.println("a = " + a + ",b = " + b);
	}
	
	//私有方法--私有方法只能在类内部供类中别的方法调用,例如在publicMethod方法中访问
	private void privateMethod() {
		System.out.println("这是私有方法");
	}
	
	//公开方法,在这个方法中调用私有方法。
	public void publicMethod() {
		privateMethod();//等价于this.privateMethod();
	}
}

Son类代码:

public class Son extends Father {
	//属性
    private int a;
	private int c;
	
	//setter、getter
    public int getA() {
		return a;
	}

	public void setA(int a) {
		this.a = a;
	}
	public int getC() {
		return c;
	}

	public void setC(int c) {
		this.c = c;
	}

	//构造方法
	public Son() {
		super();
	}

	public Son(int a, int b) {
		super(a, b);
	}

	public Son(int a, int b, int c) {
		super(a, b);
		this.c = c;
	}
	
	//打印自身信息
	public void showInfo() {
		System.out.println("a = " + a + ",b = " + this.getB() + ",c = " + c);
	}
	
	//测试super调用父类方法
	public void testSuperMethod() {
		super.showInfo();
	}
	
	//测试super调用父类属性
	public void testSuperProperty() {
		System.out.println(a);
		System.out.println(this.a);
		System.out.println(super.a);
		//私有属性不能直接访问,因为private修饰的属性,只能在本类中直接访问。我们可以通过方法间接访问。
		//System.out.println(super.b);//报错
		System.out.println(super.getB());
	}
	
	//测试调用父类中的 私有方法
	public void testSuperPrivateMthod() {
		//私有方法不能直接访问,因为private修饰的方法,只能在本类中直接方法。我们可以通过方法间接访问。
		//super.privateMethod();//报错
		super.publicMethod();
	}
}

测试类代码:

	public static void main(String[] args) {
		Son son = new Son(10,20,30);
		son.showInfo();//如果子类和父类有同名方法,调用的是自身的方法,不是父类继承过来的方法。
		son.testSuperMethod();//测试super调用父类方法
		son.testSuperPrivateMthod();//测试super调用父类私有方法
		son.testSuperProperty();//测试super调用父类属性
		son.publicMethod();//调用继承过来的方法
		son.setB(100);//调用继承过来的setter方法
		son.showInfo();
	}

总结一下:

  1. 通过super访问父类构造方法。语法:super(参数列表); 主要作用:给继承过来的属性赋初始值。通过super调用父类构造方法时,代码必须写在第一行。
  2. 通过super访问父类中的其他方法(非私有)。语法:super.方法名(参数列表);
  3. 通过super访问父类中的属性(非私有)。语法:super.属性名;

4. this关键字

前面的文章,我们讲了this关键是一个特殊的对象,代指当前对象,即随调用方法,this就是谁。this可以用于区分实例变量和局部变量。

this除了用于区分实例变量和局部变量之外,还有以下2个功能:

  1. this调用本类的其他构造方法。语法:this(参数列表); 通过this调用本类构造方法时,代码必须写在第一行。
  2. this调用本类中其他的方法。(this可省略)

5. this和super的区别

比较事项thissuper
访问实例变量this.实例变量
访问本类中的实例变量
super.实例变量
访问父类中的实例变量(非私有)
访问实例方法this.实例方法(…)
访问本类中的实例方法
super.实例方法(…)
访问父类中的实例方法(非私有)
访问构造方法this(…)
调用本类中的构造方法,写在构造方法的第一行
super(…)
调用父类中的构造方法,写在构造方法的第一行
是否是对象是对象,代表当前对象不是对象,只是关键字

继承中构造方法的访问特点:如果子类构造方法中没有明确写出调用哪个父类构造方法,会默认调用父类的无参构造方法,即super(); -----即使你没有写super(),系统也会默认在第一行代码中调用super()。如果父类不提供无参构造方法,提供有参数的构造方法,子类会报错。

继承中实例方法的访问特点:1.首先在子类中查找要调用的方法,如果有直接调用;2.如果没有,在父类中查找要调用的方法,如果有就执行;3.如果没有,继续向上找父类,如果更上一级父类中有要调用的方法,就执行,如果没有继续向上找,直到根类Object,如果Object中也没有,就报错。

6. 方法重写

方法重写:在继承关系里,如果子类中的某个方法和父类中的方法相同(方法名和参数也要相同),称为子类重写了父类的方法。子类重写父类方法往往是因为父类的方法满足不了子类的需求,所以子类才需要自己实现这个方法。

方法重写、方法重载的区别:

方法重载:在同一个类中,如果多个方法具有相同的方法名,但是参数个数或者参数类型不同(或都不同),这称为方法的重载。

方法重写:在继承关系里,父类的实现满足不了子类的需求,子类可以重新实现父类中定义的方法,这是方法重写。

如果子类重写了父类的方法,我们习惯上在重写的方法上面添加@Override注解。—注解是我们后面要学习的内容。@Override注解的作用是检测方法是否和父类中的方法相同。


总结

1. Java中继承的特点

  1. 一个类只能有一个父类。----不允许多继承
  2. 子类会继承父类全部的属性和方法(私有的也能继承,只是不能直接访问),无法继承构造方法。
  3. 如果要访问父类中的属性、方法、构造方法使用super关键字。
  4. 子类可以重写父类的方法。调用时默认调用子类的方法。
  5. 可以多层继承。A extends B,B extends C,这样A将拥有B和C中的内容
  6. 所有类的根类是Object。如果一个类没有继承任何类,默认继承Object类。
  7. 通常在子类的构造方法中调用父类的构造方法。
  8. 根类:没有父类的类。已经是最顶层的类了。

2. 继承的好处和弊端

继承的好处:

  1. 提高了代码的复用性(多个类相同的内容可以放到同一个类中)。
  2. 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)。

继承弊端:

  1. 继承让类与类之间产生了关联,类的耦合性增强了,当父类发生变化时,子类也不得不跟着变化,削弱了子类的独立性。

什么时候使用继承?

  1. 继承体现的关系是: is a (是一个)
  2. 如果两个类A和B,如果他们在逻辑上满足A是B的一种,或者B是A的一种,就说明他们是继承关系,这个时候可以使用继承来体现,否则就是滥用继承。
  3. 例如:苹果和水果,苹果属于水果,可以让苹果类继承于水果类。再例如:苹果手机和手机,苹果手机是手机的一种,可以让苹果手机类继承于手机类。再例如:猫和狗,不能让猫继承于狗,也不能让狗继承于猫,而是定义一个动物类,他们都继承于动物。

本篇文章我们讲解了三大特性之一的继承性,继承的存在极大的方便了多个类时的代码书写,并且帮助我们理清类于类之间的关系(可以参考UML类图)。下一篇文章我们将学习最后一大特性——多态性,感谢大家的观看。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值