回顾
接口
public interface 接口 extends 父接口1,父接口2 ... {
public abstract 返回类型 方法名(参数); // 必须通过对象调用
public static final 变量类型 变量名;
// jdk8~jdk9
public default 返回类型 方法名(参数) {
// 必须通过对象调用
// 方法实现
}
public static 返回类型 方法名(参数) {
// 通过接口名调用
// 方法实现
}
}
实现
public class 类 extends 父类1 implements 接口1, 接口2... {
// 实现接口中的抽象方法
}
final
- 类 - 类不能继承
- 方法 - 方法不能重写
- 变量 - 变量只能赋值一次,引用类型,引用地址不可改变了,引用对象内容 final 是不关心的
模板模式
把固定步骤放在父类的方法中,不固定步骤,在父类中表现为抽象方法,然后由子类实现
多态
- 父子类关系(接口和实现类)
- 方法发生重写
- 父类变量 引用(指向)子类的对象
通用性
今日内容
耦合高的问题: 修改 dao 类,影响了 servcie 类,这种就称为耦合高
降低耦合目标就是:不管 dao 怎么该,service 的代码不受影响
做法
- 引入一个工厂类 (factory) 用来创建对象的类,我们这里用 工厂来生产 dao 对象,对于 service 只需要和 factory 打交道,至于 dao 的实际类型 service 并不关心
- 所有 dao 实现类需要一个共同的【接口】
1. 多态
定义、前提、好处
多态:一个父类(或接口)变量根据它所引用的对象的不同,而表现出不同的行为
前提:
- 父子类关系(接口和实现类)
- 方法发生重写
- 父类变量 引用(指向)子类的对象
好处:
扩展性,通用性
只能通过父类来调用方法(只能看到父类中的方法)不能看到子类中特有方法,执行的是子类中重写后的方法
向上转型与向下转型
类图
Animal a = new Dog(); // 向上转型
Dog d = a; // 向下转型,编译出错
Dog d = (Dog) a; // 向下转型, 强制类型转换,就可以使用子类特有方法了
Animal b = new Cat();
Dog e = (Dog) b; // 不行, 必须有【是一个的关系】才能向下转换
instanceof // instance 本意是实例,对象的意思 instanceof 就是判断该对象是否能转换为右侧的类型,它表达的是【是一个】的关系
对象 instanceof 类型 返回 true 表示左边对象可以被转换为右边类型, false 就表示不能转换
练习
按上述类图,设计【一个】getAnimal 方法,接收动物名字,返回一种动物对象,例如参数为 “Dog” 返回 Dog 对象,参数为 “Hasky” 返回 Hasky 对象
提示:
- 参数应该是 String 类型
- 方法内可以用 switch 分支
- 返回值类型是什么,自行思考?
接上题,判断根据上题返回的结果,再设计【一个】领养(adopt)方法
-
只有 Pet 才能领养,返回该动物对象表示领养成功
-
如果类型不是 Pet 返回 null 表示领养失败
提示:
- 接收的参数为 Animal 类型
- 返回值类型应该为 Pet 类型
参考解答
public class TestAnimal {
public static void main(String[] args) {
Animal a1 = getAnimal("Dog"); // 返回的实际对象是 Dog
Animal a2 = getAnimal("Labrador"); // 返回的实际对象是 Labrador
Animal a3 = getAnimal("Wolf"); // 返回的实际对象是 Wolf
System.out.println(adopt(a1)); // 领养成功, 因为 Dog 是 Pet
System.out.println(adopt(a2)); // 领养成功, 因为Labrador是 Pet(继承Dog间接地实现了Pet)
System.out.println(adopt(a3)); // 领养失败,因为 Wolf 没有实现 Pet
}
public static Animal getAnimal(String name) {
switch (name) {
case "Dog":
return new Dog();
case "Cat":
return new Cat();
case "Wolf":
return new Wolf();
case "Labrador":
return new Labrador();
default:
return null; // 没有该类型动物
}
}
public static Pet adopt(Animal animal) {
// 拉布拉多 是一个? 宠物
if (animal instanceof Pet) {
Pet pet = (Pet) animal;
return pet;
} else {
return null; // 领养失败
}
}
}
interface Pet{
}
class Animal{
}
class Dog extends Animal implements Pet{
}
class Cat extends Animal implements Pet{
}
class Wolf extends Animal{
}
class Labrador extends Dog{
}
class Husky extends Dog{
}
class PersianCat extends Cat{
}
练习2
public class Transport {
static interface Vehicle {
}
static class Bus implements Vehicle {
}
public static void main(String[] args) {
Bus bus = new Bus();
boolean n = null instanceof Bus;
boolean v = bus instanceof Vehicle;
boolean b = bus instanceof Bus;
System.out.println(n + " " + v + " " + b);
}
}
A. true true true
B. false true true
C. false false false
D. None of the above
练习3
class Laptop extends Computer {
String type = "laptop";
}
public class Computer {
String type = "computer";
public static void main(String[] args) {
Computer computer = new Laptop();
Laptop laptop = new Laptop();
System.out.print(computer.type + "," + laptop.type);
}
}
A. computer,laptop
B. laptop,computer
C. laptop,laptop
D. None of the above
2. 内部类(了解)
成员内部类
// 内部类作用
// 1. 更精确的表达抽象时的嵌套关系
// 2. 内部类可以访问外部类的私有成员, 如果是平级关系的类则无法做到
// 3. 一般会在 Person 类内来创建并使用 Head 和 Body 这样的内部类
public class Person {
private String name;
private int age;
private static int x;
private Head head = new Head(); // 头部
private Body body = new Body(); // 身体
class Head {
private String mouth;
private String eyes;
private String nose;
private String ears;
public void print() {
System.out.println(name + "的相貌是:" + mouth);
}
}
private class Body {
}
}
静态内部类
应用:防止平时做练习时的类名冲突,例如下面
public class TestStudent1 {
// 此 Student 有 id, name 属性
static class Student{
int id;
String name;
}
public static void main(String[] args) {
Student s = new Student();
s.id = 1;
s.name = "张三";
}
}
和
public class TestStudent2 {
// 此 Student 只有 name 属性
static class Student{
String name;
}
public static void main(String[] args) {
Student s = new Student();
s.name = "李四";
}
}
中的 Student 类是可以独立测试使用,互不干扰
成员内部类与静态内部类的区别
public class TestOuter {
public static void main(String[] args) {
Outer1.Inner1 inner1 = new Outer1.Inner1(); // 静态内部类创建
Outer1.Inner2 inner2 = new Outer1().new Inner2(); // 成员内部类创建
}
}
class Outer1 {
private int x;
private static int y;
static class Inner1 {
public void test() {
System.out.println(x); // 编译出错,静态内部类不能访问外部类的成员变量
System.out.println(y); // 可以访问外部类的静态成员变量
}
}
class Inner2 {
public void test() {
System.out.println(x); // 静态内部类可以访问外部类的成员变量
System.out.println(y); // 可以访问外部类的静态成员变量
}
}
}
局部内部类
public void test(){
// 局部内部类中如果访问【外层方法的局部变量】,此局部变量相当于是 final,只能读,不能改
// 同样适用于 匿名内部类
final int t = 10;
class Inner3 {
public void x() {
System.out.println(t);
t = 20; // 编译出错
}
}
}
匿名内部类
配合抽象类和接口使用
接口 变量名 = new 接口() {
实现抽象方法
}
变量名.抽象方法()
3. lambda(了解)
在某些场景下对匿名内部类做简化
函数,(对应着java中的方法),只关心输入和输出,不关系方法名,方法属于哪个类
- 行为的参数化
@FunctionalInterface // 检查此接口是否是函数式接口(是否只有一个抽象方法)
interface Comparator {
// 抽象方法只有一个
int compare(String o1, String o2);
// 默认方法随意
default int aaa(){
return 1;
}
}
// 对应的 lambda
(o1, o2) -> {
return 正数或负数或零
}
函数式接口 - 只有一个抽象方法的接口
-
Comparator
-
Consumer
-
Function
-
Predicate
-
Supplier