JavaSE进阶-day03
一、接口
1.黑马信息管理系统-集合改进【】(视频01) (10‘’)
- 使用数组容器的弊端
1.容器长度是固定的,不能根据添加功能自动增长
2.没有提供用于赠删改查的方法
-
优化步骤
1.创建新的StudentDao类,OtherStudentDao
2.创建ArrayList集合容器对象
3.OtherStudentDao中的方法声明,需要跟StudentDao保持一致
注意:如果不一致,StudentService中的代码就需要进行修改。
4.完善方法(添加、删除、修改、查看)
5.替换StudentService中的Dao对象
-
集合转换成数组的方法
Student[] students = new Student[stus.size()]; stus.toArray(students);
-
代码流程图
-
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()]; stus.toArray(students); 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); } }
2.黑马信息管理系统-抽取公共Dao【】(视频02) (6‘’)
-
抽取公共Dao
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); }
-
实现继承
public class StudentDao extends BaseStudentDao {}
//快捷键 alt + insert : 快速进行方法重写 public class OtherStudentDao extends BaseStudentDao {}
3.接口介绍【】(视频03) (5‘’)
-
什么是接口
接口就是一种公共的规范标准,只要符合规范标准,都可以使用
当一个类中的所有方法都是抽象方法的时候,我们就可以将其定义为接口
-
接口存在的意义
规则的定义
程序的扩展
4.接口的定义和特点【重点】(视频04) (9‘’)
-
如何定义接口
//public interface 接口名{} public interface Inter { public abstract void study(); }
-
如何实现接口
//public class 类名 implements 接口名{} public class InterImpl implements Inter { @Override public void study() { System.out.println("我是实现类中的study方法"); } }
-
当一个类中的所有方法都是抽象方法的时候,我们就可以将其定义为接口, 为什么?
1、接口(干爹)不占用继承(亲爹)的位置
2、使用接口需要写的代码量少
-
接口的特点
-
接口不能被实例化
-
接口的实现类 : 如果实例类不是抽象类,就必须重写接口中所有的抽象方法
-
接口和实现类关系,可以单实现,也可以多实现
//接口 public interface Inter { public abstract void study(); } //接口 public interface InterA { public abstract void print1(); public abstract void print2(); public abstract void study(); }
//实现类 - 必须实现接口中所有的抽象方法 class InterImpl implements Inter{ public void study(){} } //可以单实现,也可以多实现 public class InterImpl implements Inter , InterA { @Override public void study() { System.out.println("我是实现类中的study方法"); } @Override public void print1() { } @Override public void print2() { } }
-
自由练习-5分钟 - (接口的定义)
5.接口中的成员特点【重点】(视频05) (8‘’)
-
成员变量
只能是常量,默认修饰符为:public static final
public interface Inter { public static final int NUM = 10; }
public class TestInterface { /* 成员变量: 只能是常量 系统会默认加入三个关键字 public static final */ public static void main(String[] args) { System.out.println(Inter.NUM); } } class InterImpl implements Inter{ public void method(){ // NUM = 20; System.out.println(NUM); } }
-
构造方法
接口中没有构造方法
public interface Inter { public static final int NUM = 10; // 接口中 - 构造方法: 不存在 // public Inter(){} public abstract void show(); }
class InterImpl extends Object implements Inter{ //接口实现类中, super() 调用的是父类的构造方法(比如: Object) public InterImpl(){ super(); } }
-
成员方法
只能是抽象方法,默认修饰符为:public abstract
注意:jdk8版本以前public interface Inter { /* 成员方法: 只能是抽象方法, 系统会默认加入两个关键字 public abstract JDK8以后可以有静态方法 JDK9以后可以有默认方法 */ public abstract void show(); }
6.JDK8版本中接口成员的特点-默认方法【了解】(视频06) (8‘’)
-
默认方法的作用
解决接口升级的问题
-
默认方法的格式
//格式:public default 返回值类型 方法名(参数列表) {} //注意: 默认方法只能使用 public进行修饰 public default void show3() { }
-
默认方法的注意事项
- 默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字
- 如果实现了多个接口,多个接口中存在相同的方法声明,实现类就必须对该方法进行重写
- public可以省略,default不能省略
7.JDK8版本中接口成员的特点-静态方法 【了解】(视频07) (5‘’)
-
静态方法 - 语法格式
//格式:public static 返回值类型 方法名(参数列表) { } public static void show() { }
-
接口中静态方法的注意事项
- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
- public可以省略,static不能省略
public interface InterA { public static void show() { } } class InterAImpl implements InterA { } class Test { public static void main(String[] args) { InterA.show(); //可以 InterAImpl.show(); //不可以 InterAImpl interA = new InterAImpl(); interA.show(); //不可以 } }
8.JDK9版本中接口成员的特点-私有方法 【了解】(视频08) (8‘’)
-
私有方法 - 使用格式
//格式1:private 返回值类型 方法名(参数列表) { } private void show() { } //格式2:private static 返回值类型 方法名(参数列表) { } private static void method() { }
-
接口中私有方法的注意事项
- 私有方法是jdk9才存在的, jdk9以前接口中方法的访问权限只能是公共的
- 静态方法只能调用静态的私有方法,不能调用普通的私有方法
9.类和接口的关系【】(视频09) (8‘’)
-
类和接口的关系
-
类和类之间的关系
继承关系 : 可以单继承,不能多继承,但是可以多层继承
组合关系: A类中存在B类的成员变量
-
类和接口之间的关系
实现关系,可以单实现,也可以多实现
还可以继承一个类的同时,再实现多个接口class InterImpl extends Object implements Inter{ //接口实现类中, super() 调用的是父类的构造方法(比如: Object) public InterImpl(){ super(); } }
-
接口和接口之间的关系
继承关系,可以单继承、也可以多继承
public interface InterC extends InterA , InterB { }
-
为什么类只能单继承 而类却可以实现多接口? 为什么接口可以多继承接口?
-
```java
//为什么类却可以实现多接口?
public interface Inter {
public abstract void study();
}
interface InterA {
public abstract void study();
}
class InterImpl implements Inter, InterA {
@Override
public void study() {
}
}
```
```java
//为什么接口可以多继承接口?
public interface InterA {
public abstract void study();
}
interface InterB {
public abstract void study();
}
interface InterC extends InterA, InterB {
public abstract void study();
}
class D implements InterC {
@Override
public void study() {
}
}
```
结论: 类多继承会造成逻辑冲突, 类实现多接口不会逻辑冲突,接口继承多接口也不会逻辑冲突
10.黑马信息管理系统-接口改进【】(视频10) (2‘’)
-
BaseStudentDao类改为接口
public interface BaseStudentDao { // 添加学生方法 boolean addStudent(Student stu); // 查看学生方法 Student[] findAllStudent(); // 删除学生方法 void deleteStudentById(String delId); // 根据id找索引方法 int getIndex(String id); // 修改学生方法 void updateStudent(String updateId, Student newStu); }
-
实现接口
public class StudentDao implements BaseStudentDao {}
public class OtherStudentDao implements BaseStudentDao {}
二、多态
1.黑马信息管理系统-多态引入【】(视频11) (6‘’)
-
存在问题- service与dao耦合性大
public class StudentService { private StudentDao studentDao = new StudentDao(); }
public class StudentService { private OtherStudentDao studentDao = new OtherStudentDao(); }
-
解决方案,创建工厂
public class StudentDaoFactory { public static OtherStudentDao getStudentDao(){ return new OtherStudentDao(); } }
public class StudentService { // 通过学生库管工厂类, 获取库管对象 private OtherStudentDao studentDao = StudentDaoFactory.getStudentDao(); }
2.多态的前提条件【重点】(视频12) (6‘’)
-
什么是多态?
同一个对象,在不同时刻表现出来的不同形态 ( h2O 水 冰 气)
public class Test1Polymorphic { //同一个对象 new Cat(); 可以使用不同类型的变量引用 public static void main(String[] args) { // 当前事物, 是一只猫 Cat c = new Cat(); // 当前事物, 是一只动物 Animal a = new Cat(); a.eat(); } } class Animal { public void eat(){ System.out.println("动物吃饭"); } } class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } }
-
多态的前提条件有哪些?
要有继承/实现关系
要有方法重写
要有父类引用指向子类对象//前提条件之 - 实现关系 public interface Animal { }
//前提条件之 - 实现关系 public class Cat implements Animal { @Override public void eat() { } public static void main(String[] args) { Animal a = new Cat(); } }
自由练习-6分钟 - (什么是多态)
3.多态中成员访问的特点 【重点】(视频13) (7‘’)
-
成员变量
编译看左边(父类)、运行看左边(父类)
public class Test2Polymorpic { /* 多态的成员访问特点: 成员变量: 编译看左边 (父类), 运行看左边 (父类) 编译看左边 (父类): 当父类不存在num变量时,代码编译就会报错 运行看左边 (父类): 运行结果,10 */ public static void main(String[] args) { Fu f = new Zi(); System.out.println(f.num); } } class Fu { int num = 10; } class Zi extends Fu { int num = 20; }
-
成员方法
编译看左边(父类)、运行看右边(子类)
前提:进行了方法重写
静态方法本质上是没有进行重写的,编译运行都是左边
final修饰的方法不能进行重写,编译运行都是左边public class Test2Polymorpic { /* 多态的成员访问特点: 成员方法: 编译看左边 (父类), 运行看右边 (子类) 编译看左边 (父类): 父类中不存在method方法,编译就会报错 运行看右边 (子类): 子类重写了父类方法,运行结果: 执行子类method方法 */ public static void main(String[] args) { Fu f = new Zi(); f.method(); } } class Fu { public void method(){ System.out.println("Fu.. method"); } } class Zi extends Fu { public void method(){ System.out.println("Zi.. method"); } }
4.多态的好处和弊端 【】(视频14) (9‘’)
-
多态的好处
提高了代码的扩展性
定义方法时,如果将父类型作为参数,在使用方法时,可以传递任意子类对象 (重点)代码图:
代码实现:
public class Test3Polymorpic { public static void main(String[] args) { useAnimal(new Dog()); useAnimal(new Cat()); } public static void useAnimal(Animal a){ a.eat(); } } abstract class Animal { public abstract void eat(); } class Dog extends Animal { public void eat() { System.out.println("狗吃肉"); } } class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); } }
-
多态的弊端
不能使用子类特有的成员
自由练习-10分钟
5.多态中的转型 【重点】(视频15) (6‘’)
-
多态中的向上转型
父类引用指向子类对象其实就是向上转型。例如:
Animal a = new Dog();public class Test1Polymorphic { //同一个对象 new Cat(); 可以使用不同类型的变量 作为返回值 public static void main(String[] args) { Cat c = new Cat(); Animal a = new Cat(); //向上转型 a.eat(); } } class Animal { public void eat(){ System.out.println("动物吃饭"); } } class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } }
-
多态中的向下转型
将父类型的引用转换成具体的子类对象。转换格式:
子类 对象名 = (子类)父类引用;public class Test3Polymorpic { public static void main(String[] args) { useAnimal(new Dog()); useAnimal(new Cat()); } public static void useAnimal(Animal a){ Dog dog = (Dog) a; //向下转型 dog.watchHome(); } } 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("猫吃鱼"); } }
6.多态中转型存在的风险和解决方案 【重点】(视频16) (6‘’)
-
多态中转型存在的风险
代码运行的过程中可能会出现 ClassCastException 类型转换异常
-
多态中转型风险的解决方案
如何避免强转可能会出现的问题
关键字 instanceof
使用格式:
变量名 instanceof 类型
通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果public class Test3Polymorpic { public static void main(String[] args) { useAnimal(new Dog()); useAnimal(new Cat()); } public static void useAnimal(Animal a){ //存在风险 ClassCastException 类型转换异常 //Dog dog = (Dog) a; //dog.watchHome(); //解决方案 判断a变量记录的类型, 是否是Dog if(a instanceof Dog){ Dog dog = (Dog) a; dog.watchHome(); } } } 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("猫吃鱼"); } }
自由练习-5分钟
7.黑马信息管理系统-多态改进 【】(视频17) (6‘’)
-
工厂类,以多态的形式返回对象
public class StudentDaoFactory { public static BaseStudentDao getStudentDao(){ return new OtherStudentDao(); } }
-
StudentService类
public class StudentService { // 通过学生库管工厂类, 获取库管对象 private BaseStudentDao studentDao = StudentDaoFactory.getStudentDao(); }
-
代码图