------ 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 子类的时候,它不会
再调用父类的方法了,而直接调用子类的方法,所以我们就完成了对父类行为的扩展。
三、抽象类
看我们以前示例中的Person、Student 和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 关系。
③在实际开发过程中,尽量做到面向接口编程,而不要面向具体编程(面向抽象编程,而不要面向具体编程);
④优先选择接口(因为继承抽象类后,此类将无法再继承,所以会丧失此类的灵活性)。