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

来源:互联网 发布:慈溪市行知职高在哪 编辑:程序博客网 时间:2024/04/28 21:16

------ 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 finalString 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
原创粉丝点击