黑马程序员_JavaSE基础知识总结八:继承、覆盖、抽象类和接口

------ android培训java培训、期待与您交流! ----------


一、继承的知识点

1.继承是实现软件可重用性的重要手段,如:A 继承B,A 就拥有了B 的所有特性,如现实世界中的儿子继承父亲的财产,儿子不用努力就有了财产,这就是重用性

2.java 中只支持类的单继承,也就是说A 只能继承B,A 不能同时继承C

3.java 中的继承使用extends 关键字,语法格式:

[修饰符]  class  子类 extends  父类{

}

<span style="font-size:18px;color:#666666;">public class ExtendsTest02 {
	public static void main(String[] args) {
		Student student = new Student();
		student.setId(1001);
		student.setName("张三");
		student.setSex(true);
		student.setAddress("北京");
		student.setAge(20);
		student.setClassesId(10);
		System.out.println("id=" + student.getId());
		System.out.println("name=" + student.getName());
		System.out.println("sex=" + student.getSex());
		System.out.println("address=" + student.getAddress());
		System.out.println("age=" + student.getAge());
		System.out.println("classid=" + student.getClassesId());
		System.out.println("");
		System.out.println("");
		Employee emp = new Employee();
		emp.setId(1002);
		emp.setName("李四");
		emp.setSex(true);
		emp.setAddress("上海");
		emp.setAge(30);
		emp.setWorkYear(10);
		System.out.println("id=" + emp.getId());
		System.out.println("name=" + emp.getName());
		System.out.println("sex=" + emp.getSex());
		System.out.println("address=" + emp.getAddress());
		System.out.println("age=" + emp.getAge());
		System.out.println("workYear=" + emp.getWorkYear());
	}
}

class Person {
	// 姓名
	private String name;
	// 性别
	private boolean sex;
	// 地址
	private String address;
	// 年龄
	private int age;

	// 设置学号
	public void setId(int studentId) {
		id = studentId;
	}

	// 读取学号
	public int getId() {
		return id;
	}

	public void setName(String studentName) {
		name = studentName;
	}

	public String getName() {
		return name;
	}

	public void setSex(boolean studentSex) {
		sex = studentSex;
	}

	public boolean getSex() {
		return sex;
	}

	public void setAddress(String studentAddress) {
		address = studentAddress;
	}

	public String getAddress() {
		return address;
	}

	public void setAge(int studentAge) {
		if (studentAge >= 0 && studentAge <= 120) {
			age = studentAge;
		}
	}

	public int getAge() {
		return age;
	}
}

class Student extends Person {
	// 学号
	private int sid;
	// 班级编号
	private int classesId;

	public void setClassesId(int classesId) {
		this.classesId = classesId;
	}

	public int getClassesId() {
		return classesId;
	}
}

class Employee extends Person {
	// 编号
	private int eno;
	// 工作年限
	private int workYear;

	public void setWorkYear(int workYear) {
		this.workYear = workYear;
	}

	public int getWorkYear() {
		return workYear;
	}
}</span>


二、方法的覆盖

首先看一下方法重载(Overload),回顾方法重载的条件:

方法名称相同

方法参数类型、个数、顺序至少有一个不同

方法的返回类型可以不同,因为方法重载和返回类型没有任何关系

方法的修饰符可以不同,因为方法重载和修饰符没有任何关系

方法重载只出现在同一个类中

 

方法的覆盖(Override)的条件:

必须要有继承关系

覆盖只能出现在子类中,如果没有继承关系,不存在覆盖,只存在重载

在子类中被覆盖的方法,必须和父类中的方法完全一样,也就是方法名,返回类型

参数列表,完全一样

子类方法的访问权限不能小于父类方法的访问权限

子类方法不能抛出比父类方法更多的异常,但可以抛出父类方法异常的子异常

父类的静态方法不能被子类覆盖

父类的私有方法不能覆盖

覆盖是针对成员方法,而非属性

 

为什么需要覆盖?

目的在于要改变父类的行为。

 

1.对成员方法覆盖

<span style="font-size:18px;color:#666666;">public class OverrideTest02 {
	public static void main(String[] args) {
		Student student = new Student();
		student.setId(1001);
		student.setName("张三");
		student.setSex(true);
		student.setAddress("北京");
		student.setAge(20);
		student.setClassesId(10);
		student.printInfo();
		System.out.println("");
		Employee emp = new Employee();
		emp.setId(1002);
		emp.setName("李四");
		emp.setSex(true);
		emp.setAddress("上海");
		emp.setAge(30);
		emp.setWorkYear(10);
		emp.printInfo();
	}
}

class Person {
	// 学号
	private int id;
	// 姓名
	private String name;
	// 性别
	private boolean sex;
	// 地址
	private String address;
	// 年龄
	private int age;

	public void printInfo() {
		System.out.println("id=" + id + ", name=" + name + ",sex=" + sex
				+ ", address=" + address + ", age=" + age);
	}

	// 设置学号
	public void setId(int studentId) {
		id = studentId;
	}

	// 读取学号
	public int getId() {
		return id;
	}

	public void setName(String studentName) {
		name = studentName;
	}

	public String getName() {
		return name;
	}

	public void setSex(boolean studentSex) {
		sex = studentSex;
	}

	public boolean getSex() {
		return sex;
	}

	public void setAddress(String studentAddress) {
		address = studentAddress;
	}

	public String getAddress() {
		return address;
	}

	public void setAge(int studentAge) {
		if (studentAge >= 0 && studentAge <= 120) {
			age = studentAge;
		}
	}

	public int getAge() {
		return age;
	}
}

class Student extends Person {
	// 班级编号
	private int classesId;

	public void setClassesId(int classesId) {
		this.classesId = classesId;
	}

	public int getClassesId() {
		return classesId;
	}

	public void printInfo() {
		System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ",
				address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
}
}

class Employee extends Person {
	// 工作年限
	private int workYear;

	public void setWorkYear(int workYear) {
		this.workYear = workYear;
	}

	public int getWorkYear() {
		return workYear;
	}

	public void printInfo() {
		System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ",
				address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
}
}</span>

以上子类对父类的方法进行了覆盖,改变了父类的行为,当我们new 子类的时候,它不会

再调用父类的方法了,而直接调用子类的方法,所以我们就完成了对父类行为的扩展。

 

三、抽象类

看我们以前示例中的PersonStudent Employee,从我们使用的角度来看主要对Student

Employee 进行实例化,Person 中主要包含了一些公共的属性和方法,而Person 我们通常不会实例化,所以我们可以把它定义成抽象的:

在java 中采用abstract 关键字定义的类就是抽象类,采用abstract 关键字定义的方

法就是抽象方法

抽象的方法只需在抽象类中,提供声明,不需要实现

如果一个类中含有抽象方法,那么这个类必须定义成抽象类

如果这个类是抽象的,那么这个类被子类继承,抽象方法必须被重写。如果在子类

中不复写该抽象方法,那么必须将此类再次声明为抽象类

抽象的类是不能实例化的,就像现实世界中人其实是抽象的,张三、李四才是具体

抽象类不能被final 修饰

抽象方法不能被final 修饰,因为抽象方法就是被子类实现的

抽象类中可以包含方法实现,可以将一些公共的代码放到抽象类中,另外在抽象类中可以定

义一些抽象的方法,这样就会存在一个约束,而子类必须实现我们定义的方法,如:teacher

必须实现printInfo 方法,Student 也必须实现printInfo 方法,方法名称不能修改,必须为printInfo,这样就能实现多态的机制,有了多态的机制,我们在运行期就可以动态的调用子类的方法。所以在运行期可以灵活的互换实现。


1、采用abstract声明抽象类

<span style="font-size:18px;color:#666666;">public class AbstractTest01 {
	public static void main(String[] args) {
		// 不能实例化抽象类
		// 抽象类是不存在,抽象类必须有子类继承
		Person p = new Person();
		// 以下使用是正确的,因为我们new 的是具体类
		Person p1 = new Employee();
		p1.setName("张三");
		System.out.println(p1.getName());
	}
}

// 采用abstract 定义抽象类
// 在抽象类中可以定义一些子类公共的方法或属性
// 这样子类就可以直接继承下来使用了,而不需要每个
// 子类重复定义
abstract class Person {
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	// 此方法各个子类都可以使用
	public void commonMethod1() {
		System.out.println("---------commonMethod1-------");
	}
}

class Employee extends Person {
}

class Student extends Person {
}</span>


2、抽象的方法只需在抽象类中,提供声明,不需要实现,起到了一个强制的约束作用,要求子类必须实现

<span style="font-size:18px;color:#666666;">public class AbstractTest02 {
	public static void main(String[] args) {
		// Person p = new Employee();
		// Person p = new Student();
		// Person p = new Person();
		p.setName("张三");
		p.printInfo();
	}
}

abstract class Person {
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	// 此方法各个子类都可以使用
	public void commonMethod1() {
		System.out.println("---------commonMethod1-------");
	}

	// public void printInfo() {
	// System.out.println("------Person.printInfo()--------");
	// }
	// 采用abstract 定义抽象方法
	// 如果有一个方法为抽象的,那么此类必须为抽象的
	// 如果一个类是抽象的,并不要求具有抽象的方法
	public abstract void printInfo();
}

class Employee extends Person {
	// 必须实现抽象的方法
	public void printInfo() {
		System.out.println("Employee.printInfo()");
	}
}

class Student extends Person {
	// 必须实现抽象的方法
	public void printInfo() {
		System.out.println("Student.printInfo()");
	}
}</span>


3、如果这个类是抽象的,那么这个类被子类继承,抽象方法必须被覆盖。如果在子类中不覆盖该抽象方法,那么必须将此方法再次声明为抽象方法

<span style="font-size:18px;color:#666666;">public class AbstractTest03 {
	public static void main(String[] args) {
		// 此时不能再new Employee 了
		Person p = new Employee();
	}
}

abstract class Person {
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	// 此方法各个子类都可以使用
	public void commonMethod1() {
		System.out.println("---------commonMethod1-------");
	}

	// 采用abstract 定义抽象方法
	public abstract void printInfo();
}

abstract class Employee extends Person {
	// 再次声明该方法为抽象的
	public abstract void printInfo();
}

class Student extends Person {
	// 实现抽象的方法
	public void printInfo() {
		System.out.println("Student.printInfo()");
	}
}</span>


4、抽象类不能被final修饰

<span style="font-size:18px;color:#666666;">public class AbstractTest04 {
	public static void main(String[] args) {
	}
}

// 不能采用final 修改抽象类
// 两个关键字是矛盾的
final abstract class Person {
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	// 此方法各个子类都可以使用
	public void commonMethod1() {
		System.out.println("---------commonMethod1-------");
	}

	// 采用abstract 定义抽象方法
	public abstract void printInfo();
}

class Employee extends Person {
	// 实现抽象的方法
	public void printInfo() {
		System.out.println("Student.printInfo()");
	}
}

class Student extends Person {
	// 实现抽象的方法
	public void printInfo() {
		System.out.println("Student.printInfo()");
	}
}</span>


5、抽象方法不能被final修饰

<span style="font-size:18px;color:#666666;">public class AbstractTest05 {
	public static void main(String[] args) {
	}
}

abstract class Person {
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	// 此方法各个子类都可以使用
	public void commonMethod1() {
		System.out.println("---------commonMethod1-------");
	}

	// 不能采用final 修饰抽象的方法
	// 这两个关键字存在矛盾
	public final abstract void printInfo();
}

class Employee extends Person {
	// 实现抽象的方法
	public void printInfo() {
		System.out.println("Student.printInfo()");
	}
}

class Student extends Person {
	// 实现抽象的方法
	public void printInfo() {
		System.out.println("Student.printInfo()");
	}
}</span>


四、接口

接口我们可以看作抽象类的一种特殊情况,在接口中只能定义抽象的方法和常量

1) java 中接口采用interface 声明

2) 接口中的方法默认都是public abstract 的,不能更改

3) 接口中的变量默认都是public static final 类型的,不能更改,所以必须显示的

初始化

4) 接口不能被实例化,接口中没有构造函数的概念

5) 接口之间可以继承,但接口之间不能实现

6) 接口中的方法只能通过类来实现,通过implements 关键字

7) 如果一个类实现了接口,那么接口中所有的方法必须实现

8) 一类可以实现多个接口

 

1、接口中的方法默认都是public abstract 的,不能更改

<span style="font-size:18px;color:#666666;">public class InterfaceTest01 {
	public static void main(String[] args) {
	}
}

// 采用interface 定义接口
// 定义功能,没有实现
// 实现委托给类实现
interface StudentManager {
	// 正确,默认public abstract 等同public abstract void addStudent(int id, String
	// name);
	public void addStudent(int id, String name);

	// 正确
	// public abstract void addStudent(int id, String name);
	// 正确,可以加入public 修饰符,此种写法较多
	public void delStudent(int id);

	// 正确,可以加入abstract,这种写法比较少
	public abstract void modifyStudent(int id, String name);

	// 编译错误,因为接口就是让其他人实现
	// 采用private 就和接口原本的定义产生矛盾了
	private String findStudentById(int id);
}</span>


2、接口中的变量是public static final 类型的,不能更改,所以必须显示的初始化

<span style="font-size:18px;color:#666666;">public class InterfaceTest02 {
	public static void main(String[] args) {
		// 不能修改,因为final 的
		// StudentManager.YES = "abc";
		System.out.println(StudentManager.YES);
	}
}

interface StudentManager {
	// 正确,默认加入public static final
	String YES = "yes";
	// 正确, 开发中一般就按照下面的方式进行声明
	public static final String NO = "no";
	// 错误,必须赋值,因为是final 的
	// int ON;
	// 错误,不能采用private 声明
	private static final int OFF = -1;
}</span>


3、接口不能被实例化,接口中没有构造函数的概念

<span style="font-size:18px;color:#666666;">public class InterfaceTest03 {
	public static void main(String[] args) {
		// 接口是抽象类的一种特例,只能定义方法和变量,没有实现
		// 所以不能实例化
		StudentManager studentManager = new StudentManager();
	}
}

interface StudentManager {
	public void addStudent(int id, String name);
}</span>



4、接口之间可以继承,但接口之间不能实现

<span style="font-size:18px;color:#666666;">public class InterfaceTest04 {
	public static void main(String[] args) {
	}
}
interface inter1 {
	public void method1();
	public void method2();
}
	interface inter2 {
	public void method3();
}
//接口可以继承
interface inter3 extends inter1 {
	public void method4();
}
//接口不能实现接口
//接口只能被类实现
interface inter4 implements inter2 {
	public void method3();
}</span>


5、如果一个类实现了接口,那么接口中所有的方法必须实现

<span style="font-size:18px;color:#666666;">public class InterfaceTest05 {
	public static void main(String[] args) {
		// Iter1Impl 实现了Inter1 接口
		// 所以它是Inter1 类型的产品
		// 所以可以赋值
		Inter1 iter1 = new Iter1Impl();
		iter1.method1();
		// Iter1Impl123 实现了Inter1 接口
		// 所以它是Inter1 类型的产品
		// 所以可以赋值
		iter1 = new Iter1Impl123();
		iter1.method1();
		// 可以直接采用Iter1Impl 来声明类型
		// 这种方式存在问题
		// 不利于互换,因为面向具体编程了
		Iter1Impl iter1Impl = new Iter1Impl();
		iter1Impl.method1();
		// 不能直接赋值给iter1Impl
		// 因为Iter1Impl123 不是Iter1Impl 类型
		// iter1Impl = new Iter1Impl123();
		// iter1Impl.method1();
	}
}

// 接口中的方法必须全部实现
class Iter1Impl implements Inter1 {
	public void method1() {
		System.out.println("method1");
	}

	public void method2() {
		System.out.println("method2");
	}

	public void method3() {
		System.out.println("method3");
	}
}

class Iter1Impl123 implements Inter1 {
	public void method1() {
		System.out.println("method1_123");
	}

	public void method2() {
		System.out.println("method2_123");
	}

	public void method3() {
		System.out.println("method3_123");
	}
}

abstract class Iter1Impl456 implements Inter1 {
	public void method1() {
		System.out.println("method1_123");
	}

	public void method2() {
		System.out.println("method2_123");
	}

	// 再次声明成抽象方法
	public abstract void method3();
}

// 定义接口
interface Inter1 {
	public void method1();

	public void method2();

	public void method3();
}</span>


6、一类可以实现多个接口

<span style="font-size:18px;color:#666666;">public class InterfaceTest06 {
	public static void main(String[] args) {
		// 可以采用Inter1 定义
		Inter1 inter1 = new InterImpl();
		inter1.method1();
		// 可以采用Inter1 定义
		Inter2 inter2 = new InterImpl();
		inter2.method2();
		// 可以采用Inter1 定义
		Inter3 inter3 = new InterImpl();
		inter3.method3();
	}
}

// 实现多个接口,采用逗号隔开
// 这样这个类就拥有了多种类型
// 等同于现实中的多继承
// 所以采用java 中的接口可以实现多继承
// 把接口粒度划分细了,主要使功能定义的含义更明确
// 可以采用一个大的接口定义所有功能,替代多个小的接口,
// 但这样定义功能不明确,粒度太粗了
class InterImpl implements Inter1, Inter2, Inter3 {
	public void method1() {
		System.out.println("----method1-------");
	}

	public void method2() {
		System.out.println("----method2-------");
	}

	public void method3() {
		System.out.println("----method3-------");
	}
}

interface Inter1 {
	public void method1();
}

interface Inter2 {
	public void method2();
}

interface Inter3 {
	public void method3();
}
/*
 * interface Inter { public void method1(); public void method2(); public void
 * method3(); }
 */</span>


7、接口和抽象类的区别

接口描述了方法的特征,不给出实现,一方面解决java 的单继承问题,实现了强大的可接插性抽象类提供了部分实现,抽象类是不能实例化的,抽象类的存在主要是可以把公共的代码移植到抽象类中

抽象类使用的是 is a 关系接口使用的 like a 关系。 

③在实际开发过程中,尽量做到面向接口编程,而不要面向具体编程(面向抽象编程,而不要面向具体编程)

优先选择接口(因为继承抽象类后,此类将无法再继承,所以会丧失此类的灵活性)


















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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值