重难点梳理
接口特点:
-
接口用interface修饰
interface 接口名{}
-
类实现接口用implements表示
-
接口不能实例化,可以创建接口实现类
-
接口的子类
-
要么重写所有的接口中的抽象方法
-
要么子类也是一个抽象类
-
类和接口关系:
-
类与类关系
继承关系,只能单继承,可以多层继承
-
类与接口的关系
实现关系,可以单实现,也可以多实现,还可以继承一个类的同时实现多个接口
-
接口与接口关系
继承关系,可以单继承,可以多继承
接口默认方法:
格式:
default 返回值类型 方法名 (参数列表){}
作用:
解决接口升级问题,不用重写所有方法
注意事项:
-
默认方法不是抽象方法,不要求强制重写.但是可以被重写,重写时候去掉default关键字
-
public可以省略 default不可以省略
-
如果实现多接口,接口之间有相同方法声明的方法,那么子类必须重写该默认方法
接口中静态方法:
格式:
static 返回值类型 方法名(参数列表){}
注意:
-
静态方法只能通过接口名调用,不能通过实现类或者对象名调用
-
public可以省略 static省略,不能跟default同时出现
接口中私有的方法:
格式:
-
private 返回值类型 方法名(参数列表){}
-
private static 返回值类型 方法名(参数列表){}
注意:
-
默认方法可以调用私有的静态方法和非静态方法
-
静态方法只能调用是有的静态方法
多态前提:
-
要有(继承/实现)关系
-
要有方法重写
-
要有父类引用指向子类对象
多态访问特点:
-
成员变量:编译看左(父类),运行看左(父类)
-
成员方法:编译看左(父类),运行看右(子类)注:因为子类对方法进行了重写,所以运行时候看重写后的方法
多态的好处与弊端:
好处:
-
提高了程序的扩展性
-
具体表现为定义方法的时候,使用父类型作为参数,该方法就可以接收者父类的任意子类对象
弊端:
-
不能调用子类特有的功能
多态的转型:
-
向上转型:父类引用指向子类对象就是向上转型
-
向下转型:子类型 对象名=(子类型)父类引用
转型风险:
风险:
如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么转换时
候就会异常
解决方案:
方案一:
变量名 instanceof 类型配合if语句
例:if(变量名 instanceof 父类类型){
子类型 对象名=(子类型)父类引用
对象名.子类特有方法名
}
方案二:
直接创建子类对象调用子类方法简单粗暴
抽象类
抽象方法
当我们在父类中编写了一个所有子类都一定会有,但是每个子类具体的方法内容又不一样的方法,这个方法就可以写成抽象方法;
思考: 为什么一定要在父类中写所有子类都有,但是内容又不一样的方法呢?
答: 是因为父类一旦编写了这样的方法,所有的子类都必须强制性重写;
抽象类
包含了抽象方法的类一定是抽象类;
是不是抽象类就一定会包含抽象方法呢?
答: 不一定;
如何编写抽象方法和抽象类
//抽象类
public abstract class 类名{
//抽象方法 子类一定会重写该方法
public abstract 返回值类型 方法名(形参);
}
抽象类的注意事项
final关键字
概述
final表示最终的含义,可以修饰类,方法,变量;
修饰类
public final class 类名{
}
这样的类不能被其他类继承;
修饰方法
public final 返回值类型 方法名(参数列表){
}
这样的方法子类不能重写;
修饰变量
final 基本数据类型 变量名 = 数据值; // 这样的变量,数据值不能改变
final 引用数据类型 变量名 = 数据值; // 这样的变量,地址值不能改变,但是对象中的内容可以改变
代码块
详解接口
概述
定义接口,实际上就是定义了一套规则/(规范),定义了规则之后,就要求子类必须按照接口制定的规则编写代码;
语法格式
public interface 接口名{
接口的成员;
}
接口成员的特点(JDK7以前)
在JDK8中,对接口新增了默认方法
目的是为了在接口中添加一些带有方法体的方法,同时有不让子类报错;
默认方法的语法:
public default 返回值类型 方法名(形参){
方法体;
}
使用:
实现类可以重写也可以不重写,通过实现类的对象调用默认方法;
当实现类实现的多个接口中出现了重名的默认方法时,实现类必须重写;
静态方法的语法:
public static 返回值类型 方法名(形参){
方法体;
}
使用:
只能使用接口名.方法名(实参);的形式调用;
在JDK9中,对接口新增了私有方法
私有方法可以是静态的也可以是非静态的,主要是为jdk8增加的默认方法和静态方法服务的;
接口的注意事项
-
接口不能直接创建对象;(只能创建接口的实现类/子类对象)
-
接口中没有构造方法;
-
接口与类之间,只能是类实现接口;实现的关键字是 implements
-
接口与接口之间,可以多继承,使用的关键字是 extends
多态
多态的概述
一个对象,多种形态;
多态的前提
有继承或有实现
多态的代码形式(重点)
父类类型 变量名 = new 子类类名();
多态中成员访问的特点
成员变量(了解)
编译和运行都看父类类型;
成员方法(重点)
编译看左边(父类),运行看右边;(子类)
多态的好处和弊端
多态的转型
向上转型: 子类对象,转成父类类型, Fu f = new Zi();
向下转型: 父类对象,转成子类类型, Zi z = (Zi)f;
多态的类型转换异常
为了解决类型转换异常,在转换之前,应该先判断被转的对象是否与目标类型一致;
判断的格式:
if(对象名 instanceof 类名){
在这里转
}
代码练习:
1.1黑马信息管理系统集合改进 (应用)
-
使用数组容器的弊端
-
容器长度是固定的,不能根据添加功能自动增长
-
-
-
优化步骤
-
创建新的StudentDao类,OtherStudentDao
-
创建ArrayList集合容器对象
-
OtherStudentDao中的方法声明,需要跟StudentDao保持一致
注意:如果不一致,StudentService中的代码就需要进行修改
-
完善方法(添加、删除、修改、查看)
-
替换StudentService中的Dao对象
-
-
代码实现
OtherStudentDao类
public class OtherStudentDao {
// 集合容器
private static ArrayList<Student> stus = new ArrayList<>();
static {
Student stu1 = new Student("heima001","张三","23","1999-11-11");
Student stu2 = new Student("heima002","李四","24","2000-11-11");
stus.add(stu1);
stus.add(stu2);
}
// 添加学生方法
public boolean addStudent(Student stu) {
stus.add(stu);
return true;
}
// 查看学生方法
public Student[] findAllStudent() {
Student[] students = new Student[stus.size()];
for (int i = 0; i < students.length; i++) {
students[i] = stus.get(i);
}
return students;
}
public void deleteStudentById(String delId) {
// 1. 查找id在容器中所在的索引位置
int index = getIndex(delId);
stus.remove(index);
}
public int getIndex(String id){
int index = -1;
for (int i = 0; i < stus.size(); i++) {
Student stu = stus.get(i);
if(stu != null && stu.getId().equals(id)){
index = i;
break;
}
}
return index;
}
public void updateStudent(String updateId, Student newStu) {
// 1. 查找updateId, 在容器中的索引位置
int index = getIndex(updateId);
stus.set(index, newStu);
}
}StudentService类
public class StudentService {
// 创建StudentDao (库管)
private OtherStudentDao studentDao = new OtherStudentDao();
// 其他方法没有变化,此处省略...
}
1.2黑马信息管理系统抽取Dao (应用)
-
优化步骤
-
将方法向上抽取,抽取出一个父类 ( BaseStudentDao )
-
方法的功能实现在父类中无法给出具体明确,定义为抽象方法
-
让两个类分别继承 BaseStudentDao ,重写内部抽象方法
-
-
代码实现
BaseStudentDao类
public abstract class BaseStudentDao {
// 添加学生方法
public abstract boolean addStudent(Student stu);
// 查看学生方法
public abstract Student[] findAllStudent();
// 删除学生方法
public abstract void deleteStudentById(String delId);
// 根据id找索引方法
public abstract int getIndex(String id);
// 修改学生方法
public abstract void updateStudent(String updateId, Student newStu);
}StudentDao类
public class StudentDao extends BaseStudentDao {
// 其他内容不变,此处省略
}OtherStudentDao类
public class OtherStudentDao extends BaseStudentDao {
// 其他内容不变,此处省略
}
1.3接口的概述(理解)
-
接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。
-
Java中接口存在的两个意义
-
用来定义规范
-
用来做功能的拓展
-
1.4接口的特点(记忆)
-
接口用关键字interface修饰
public interface 接口名 {}
-
类实现接口用implements表示
public class 类名 implements 接口名 {}
-
接口不能实例化
我们可以创建接口的实现类对象使用
-
接口的子类
要么重写接口中的所有抽象方法
要么子类也是抽象类
1.5接口的成员特点(记忆)
-
成员特点
-
成员变量
只能是常量 默认修饰符:public static final
-
构造方法
没有,因为接口主要是扩展功能的,而没有具体存在
-
成员方法
只能是抽象方法
默认修饰符:public abstract
关于接口中的方法,JDK8和JDK9中有一些新特性,后面再讲解
-
-
代码演示
-
接口
public interface Inter {
public static final int NUM = 10;
public abstract void show();
}-
实现类
class InterImpl implements Inter{
public void method(){
// NUM = 20;
System.out.println(NUM);
}
public void show(){
}
}-
测试类
public class TestInterface {
/*
成员变量: 只能是常量 系统会默认加入三个关键字
public static final
构造方法: 没有
成员方法: 只能是抽象方法, 系统会默认加入两个关键字
public abstract
*/
public static void main(String[] args) {
System.out.println(Inter.NUM);
}
} -
1.6类和接口的关系(记忆)
-
类与类的关系
继承关系,只能单继承,但是可以多层继承
-
类与接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
-
接口与接口的关系
继承关系,可以单继承,也可以多继承
1.7黑马信息管理系统使用接口改进 (应用)
-
实现步骤
-
将 BaseStudentDao 改进为一个接口
-
让 StudentDao 和 OtherStudentDao 去实现这个接口
-
-
代码实现
BaseStudentDao接口
public interface BaseStudentDao {
// 添加学生方法
public abstract boolean addStudent(Student stu);
// 查看学生方法
public abstract Student[] findAllStudent();
// 删除学生方法
public abstract void deleteStudentById(String delId);
// 根据id找索引方法
public abstract int getIndex(String id);
// 修改学生方法
public abstract void updateStudent(String updateId, Student newStu);
}StudentDao类
public class StudentDao implements BaseStudentDao {
// 其他内容不变,此处省略
}OtherStudentDao类
public class OtherStudentDao implements BaseStudentDao {
// 其他内容不变,此处省略
}
1.8黑马信息管理系统解耦合改进 (应用)
-
实现步骤
-
创建factory包,创建 StudentDaoFactory(工厂类)
-
提供 static 修改的 getStudentDao 方法,该方法用于创建StudentDao对象并返回
-
-
代码实现
StudentDaoFactory类
public class StudentDaoFactory {
public static OtherStudentDao getStudentDao(){
return new OtherStudentDao();
}
}StudentService类
public class StudentService {
// 创建StudentDao (库管)
// private OtherStudentDao studentDao = new OtherStudentDao();
// 通过学生库管工厂类, 获取库管对象
private OtherStudentDao studentDao = StudentDaoFactory.getStudentDao();
}
2.接口组成更新
2.1接口组成更新概述【理解】
-
常量
public static final
-
抽象方法
public abstract
-
默认方法(Java 8)
-
静态方法(Java 8)
-
私有方法(Java 9)
2.2接口中默认方法【应用】
-
格式
public default 返回值类型 方法名(参数列表) { }
-
作用
解决接口升级的问题
-
范例
public default void show3() {
} -
注意事项
-
默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字
-
public可以省略,default不能省略
-
如果实现了多个接口,多个接口中存在相同的方法声明,子类就必须对该方法进行重写
-
2.3接口中静态方法【应用】
-
格式
public static 返回值类型 方法名(参数列表) { }
-
范例
public static void show() { }
-
注意事项
-
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
-
public可以省略,static不能省略
-
2.4接口中私有方法【应用】
-
私有方法产生原因
Java 9中新增了带方法体的私有方法,这其实在Java 8中就埋下了伏笔:Java 8允许在接口中定义带方法体的默认方法和静态方法。这样可能就会引发一个问题:当两个默认方法或者静态方法中包含一段相同的代码实现时,程序必然考虑将这段实现代码抽取成一个共性方法,而这个共性方法是不需要让别人使用的,因此用私有给隐藏起来,这就是Java 9增加私有方法的必然性
-
定义格式
-
格式1
private 返回值类型 方法名(参数列表) { }
-
范例1
private void show() { }
-
格式2
private static 返回值类型 方法名(参数列表) { }
-
范例2
private static void method() { }
-
-
注意事项
-
默认方法可以调用私有的静态方法和非静态方法
-
静态方法只能调用私有的静态方法
-
3.多态
3.1多态的概述(记忆)
-
什么是多态
同一个对象,在不同时刻表现出来的不同形态
-
多态的前提
-
要有继承或实现关系
-
要有方法的重写
-
要有父类引用指向子类对象
-
-
代码演示
class Animal { public void eat(){ System.out.println("动物吃饭"); } } class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } } public class Test1Polymorphic { /* 多态的前提: 1. 要有(继承 实现)关系 2. 要有方法重写 3. 要有父类引用, 指向子类对象 */ public static void main(String[] args) { // 当前事物, 是一只猫 Cat c = new Cat(); // 当前事物, 是一只动物 Animal a = new Cat(); a.eat(); } }
3.2多态中的成员访问特点(记忆)
-
成员访问特点
-
成员变量
编译看父类,运行看父类
-
成员方法
编译看父类,运行看子类
-
-
代码演示
class Fu { int num = 10; public void method(){ System.out.println("Fu.. method"); } } class Zi extends Fu { int num = 20; public void method(){ System.out.println("Zi.. method"); } } public class Test2Polymorpic { /* 多态的成员访问特点: 成员变量: 编译看左边 (父类), 运行看左边 (父类) 成员方法: 编译看左边 (父类), 运行看右边 (子类) */ public static void main(String[] args) { Fu f = new Zi(); System.out.println(f.num); f.method(); } }
3.3多态的好处和弊端(记忆)
-
好处
提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,使用具体的子类型参与操作
-
弊端
不能使用子类的特有成员
3.4多态中的转型(应用)
-
向上转型
父类引用指向子类对象就是向上转型
-
向下转型
格式:子类型 对象名 = (子类型)父类引用;
-
代码演示
class Fu { public void show(){ System.out.println("Fu..show..."); } } class Zi extends Fu { @Override public void show() { System.out.println("Zi..show..."); } public void method(){ System.out.println("我是子类特有的方法, method"); } } public class Test3Polymorpic { public static void main(String[] args) { // 1. 向上转型 : 父类引用指向子类对象 Fu f = new Zi(); f.show(); // 多态的弊端: 不能调用子类特有的成员 // f.method(); // A: 直接创建子类对象 // B: 向下转型 // 2. 向下转型 : 从父类类型, 转换回子类类型 Zi z = (Zi) f; z.method(); } }
3.5多态中转型存在的风险和解决方案 (应用)
-
风险
如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
-
解决方案
-
关键字
instanceof
-
使用格式
变量名 instanceof 类型
通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果
-
-
代码演示
abstract class Animal { public abstract void eat(); } class Dog extends Animal { public void eat() { System.out.println("狗吃肉"); } public void watchHome(){ System.out.println("看家"); } } class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); } } public class Test4Polymorpic { public static void main(String[] args) { useAnimal(new Dog()); useAnimal(new Cat()); } public static void useAnimal(Animal a){ // Animal a = new Dog(); // Animal a = new Cat(); a.eat(); //a.watchHome(); // Dog dog = (Dog) a; // dog.watchHome(); // ClassCastException 类型转换异常 // 判断a变量记录的类型, 是否是Dog if(a instanceof Dog){ Dog dog = (Dog) a; dog.watchHome(); } } }
3.6黑马信息管理系统多态改进 (应用)
-
实现步骤
-
StudentDaoFactory类中方法的返回值定义成父类类型BaseStudentDao
-
StudentService中接收方法返回值的类型定义成父类类型BaseStudentDao
-
-
代码实现
StudentDaoFactory类
public class StudentDaoFactory { public static BaseStudentDao getStudentDao(){ return new OtherStudentDao(); } }
StudentService类
public class StudentService { // 创建StudentDao (库管) // private OtherStudentDao studentDao = new OtherStudentDao(); // 通过学生库管工厂类, 获取库管对象 private BaseStudentDao studentDao = StudentDaoFactory.getStudentDao(); }
问答题【继承】
1.1 请问子类继承父类用什么关键字?
extends
1.2 请问子类继承父类的好处是什么?
1:可以提升代码的复用性;
2:子类对象可以直接使用父类非私有的属性和方法;
1.3 请问父类的哪些成员不能被子类继承,或者不能被直接访问?
私有成员
1.4 请问子类是否可以同时继承多个父类?
不可以,可以多层继承
问答题【抽象类】
4.1 请问定义抽象类、抽象方法使用的关键字是什么?
abstract
4.2 请问定义抽象类有什么作用?
1:可以作为设计模式使用;(例如:模板模式)
2:可以通过抽象类的抽象方法强制子类重写某些方法
4.3 请问定义抽象方法有什么作用?
父类中方法无法进行具体事务描述时候,强制子类重写方法
4.4 请问一个类继承了抽象类后,必须要做的事情是什么?
重写抽象类的抽象方法,或者子类是抽象类
4.5 请问抽象类是否可以继承其它抽象类?
可以继承
问答题【接口】
2.1 请问子类实现接口使用什么关键字?
impl//implements
2.2 请问子类实现接口后有什么要求?
重写接口中所有的抽象方法,要么子类也是抽象类
2.3 请问子类是否可以同时实现多个接口?
可以,但是此时子类必须重写所有接口的抽象方法,否则该类只能也是抽象类
2.4 请问子类是否可以在继承一个类的同时实现多个接口?可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
可以
2.5 请问接口是否可以继承一个或多个接口?
接口与接口继承关系,可以单继承,也可以多继承
问答题【final】
请写出final可以修饰的元素,并写出修饰后的含义。
final修饰类:
该类不能被继承(不可以有子类,但是可以有父类)
final修饰方法:
该方法不可以被重写
final修饰变量:
表明该变量是一个产量,不能再次被赋值
1.变量是基本类型,不能改变的是值
2.变量是引用数据类型,不能改变的是地址值,但地址值中的内容可以改变
编程题【抽象类】
题目1:
我们计划为一所体育学校设计一套系统,需要记录以下人员的信息:
教练员:
属性:员工编号、姓名、性别、年龄
行为:吃饭(吃工作餐)
运动员:
属性:学员编号、姓名、性别、年龄、所在班级
行为:吃饭(吃营养餐)
参考答案:
package day3.No_1;
public class Demo {
public static void main(String[] args) {
Jiaolian j=new Jiaolian("020300","教1","男",23);
j.show();
j.eat();
Student s=new Student("0300","学1","男",21,"软件1班");
s.show();
s.eat();
}
}
//Fu
abstract class Ren{
private String id;
private String name;
private String xingbie;
private int age;
public Ren() {
}
public Ren(String id, String name, String xingbie, int age) {
this.id = id;
this.name = name;
this.xingbie = xingbie;
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getXingbie() {
return xingbie;
}
public void setXingbie(String xingbie) {
this.xingbie = xingbie;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
}
//Zi
class Jiaolian extends Ren{
public Jiaolian() {
}
public Jiaolian(String id, String name, String xingbie, int age) {