多态
多态的概念
多态指的是一类事物的多种形态,想使用多态编写代码的方式必须满足继承/实现关系。
多态的体现
宏观体现
父类数据类型 变量名 = new 子类数据类型();
让一个保存父类对象地址的变量也可以保存子类对象的地址值,这就是多态!
宏观体现一般不会在代码中直接编写!学习宏观体现的目的就是让大家明确这种写法就是多态! 微观体现就是变相的宏观体现!
微观体现
将父类类型作为方法参数,在调用方法的时候实际可以传递子类对象(满足多态)。
将接口类型作为方法参数,在调用方法的时候实际可以传递实现类对象(满足多态)
//父类Animal
//子类Dog
Dog dog = new Dog();
showEat(dog);//相当于 Animal animal = new Dog();
public static void showEat(Animal animal){
}
补充
除了父类类型作为方法参数满足多态,还有父类类型作为返回值类型也可以返回子类对象。
父类引用可以调用子类继承或者重写的方法!而方法的逻辑执行的是子类的!
父类引用是否可以调用某一个方法的前提编左看右:编译阶段看左边(父类/接口有没有这个方法),运行阶段运行的是子类的逻辑!
instanceof
instanceof(格式: a instanceof b)作用是:判断a的实例化对象类型是不是b,并且返回boolean值。
public static void main(String[] args) {
Dog dog = new Dog();
Pig pig = new Pig();
showEat(dog);
showEat(pig);
}
public static void showEat(Animal animal) {
animal.eat();
//instanceof(格式: a instanceof b)作用是判断a的实例化对象类型是不是b,并且返回boolean值
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.lookDoor();
}
}
多态的好处与弊端
好处
提高代码的拓展性,复用性(可以任意传递子类对象)。
弊端
提高拓展性表示父类引用可以调用所有子类都继承/重写了的方法,但是提高拓展性的同时也就表示不能基于父类引用调用子类的特有方法!
多态向下转型
多态的情况下默认不允许调用子类特有方法,但是如果真的想要调用子类特有方法,就需要进行强制类型转换。
子类数据类型 变量名 = (子类数据类型) 父类变量;
Dog dog = (Dog) a;
当强转为子类之后,就可以基于子类对象调用特有方法!
但是如果当前父类变量保存的不是目标子类的对象地址值,则会出现ClassCaseException异常。
解决方案:
在强转之前进行判断,如果保存的的确是目标子类的地址值再转换,否则不转换。
变量 instanceof 类名 最终会返回一个boolean值。
if (a instanceof Dog) { //如果a变量保存的地址值是Dog类的对象,则返回true,否则返回false!
Dog dog = (Dog) a;
dog.lookDoor();
}
final关键字
- final关键字是最终的意思,可以修饰(类、方法、变量)。
- 修饰类:该类被称为最终类,特点是不能被继承了。
- 修饰方法:该方法被称为最终方法,特点是不能被重写了。
- 修饰变量:该变量只能被赋值一次。
final修饰变量的注意
- final修饰基本类型的变量,变量存储的数据不能被修改。
- fina修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的。
abstract抽象
抽象:说不清道不明。
例:定义一个父类,Animal(抽取所有动物都具备共性内容) 吃
public class Animal {
public void eat(){}
}
1.eat方法的逻辑是什么? 不清楚,因为每个子类吃的东西,方式都不一样!
2.基于类创建对象,对象是类的具体体现。 Animal作为父类存在有意义,但是创建对象没意义!说不清道不明。
抽象类定义的格式
public abstract class 类名 {}
抽象方法的定义格式
权限修饰符 abstract 返回值类型 方法名(形式参数);
抽象类的使用方法
public abstract class Animal {
//经过之前代码的编写(动物应该具备吃的功能,父类要进行抽取,但是具体逻辑父类不明确,声明为抽象方法)
//抽象方法必须在抽象类中
public abstract void eat();
}
抽象类由于说不清道不明不可以实例化,抽象类只可以作为父类存在。
当子类继承了抽象类,那么必须重写抽象类的所有抽象方法,除非子类也是抽象的!
public class Dog extends Animal {
//当一个子类继承抽象类之后,必须对抽象类中的所有抽象方法进行重写(父类只是声明共性功能,具体的逻辑需要子类完成)
@Override
public void eat() {
System.out.println("狗吃肉骨头!");
}
}
抽象类的注意事项
(1)抽象类中可以没有抽象方法,而抽象方法必须在抽象类中!
抽象类没有抽象方法的意义就是单纯作为抽取共性内容的父类存在。
(2)抽象类和具体类没有那么大的区别,具体类应该写什么,抽象类里就可以写什么(包括构造器)
(3)抽象类不能创建对象,仅仅作为父类存在!
(4)子类继承抽象类必须重写抽象类中的所有抽象方法,基于快捷键Ctrl + O即可选择要重写的方法。
如果当你认为某一个类仅作为父类存在,不具备创建对象的意义,那么就可以将这个类改为抽象类!
接口
生活中的接口用于声明规范。只要遵守了规范就具备指定的功能!
Java中的接口本质上也是规范,接口是接口,某个类遵守了接口的规范,某个类就具备指定的功能!
抽象类更多是对事物的抽象,更多是作为父类而存在(共性成员变量…)
接口是对行为的抽象,不在乎到底表示哪种事物,更多是作为规范而存在(共性行为)
接口的定义格式-(旧与新)
public interface 接口名 {
//常量(必须给初始化值)
public static final 数据类型 变量名 = 初始化值;
//抽象方法
public abstract 返回值类型 方法名(形式参数);
}
Java8之前接口中可以定义常量与抽象方法(抽象方法也是使用最多的方法)
public interface Flyable {
//接口中可以定义成员变量(默认会被public static final修饰) 接口是规范,规范的东西不可以随便改! 接口中一般不会声明成员变量
int AGE = 10;
//接口中可以定义成员方法(默认是抽象方法)(默认会加public abstract)
public abstract void fly();
}
在Java8之后接口中也添加了一些新的组成部分(了解)
public interface A {
/*
默认方法:
格式 : public default 返回值类型 方法名(参数列表){方法体;} 这里不可以加abstract
特点 : 当实现类实现了接口,不强制实现默认方法(类似于继承),实现类可以调用,实现类也可以主动重写该方法!
作用 : 避免冲突 A接口有B C D实现类,A接口新增一抽象方法,B和C需要,D不需要(强制实现),如果是默认方法,则D不需要强制实现
*/
public default void defaultMethod() {
System.out.println("这是A接口中的默认方法defaultMethod执行了~");
}
/*
静态方法:
格式 : public static 返回值类型 方法名(参数列表){方法体;} 这里不可以加abstract
特点 : 和类的静态方法一样,静态方法归接口管理,实现类不需要实现也不可以实现,只可以被接口名调用
作用 : Java8中更希望接口具有更强大的工具
Ps : Java中的一些核心接口 List / Set / Map,针对于静态方法推出了一些快速构建方式.
*/
public static void staticMethod() {
System.out.println("这是A接口中的静态方法staticMethod执行了~");
}
/*
私有方法:
格式 : private 返回值类型 方法名(参数列表){方法体;} 这里不可以加abstract
特点 : 和类的私有方法一样,只可以在当前接口中被其他的方法调用,实现类不需要实现也不可以实现也不可以调用
作用 : 抽取当前接口中其他方法的共性内容
*/
private void methodC() {
System.out.println("A");
System.out.println("B");
}
public default void methodA() {
methodC(); //调用私有方法
System.out.println("C");
System.out.println("D");
}
public default void methodB() {
methodC(); //调用私有方法
System.out.println("Z");
System.out.println("Z");
}
}
接口的使用方式
接口是规范,想要和接口产生关系。实现关系 实现类实现接口!
接口不在乎实现类是什么事物(不体现事物的特性),实现类有没有遵守接口的规范!
public class 类名 implements 接口A,接口B,接口C ... {
//针对于实现的所有接口的抽象方法进行重写
}
一个类可以实现多个接口。一个类遵守多种规范!
接口的注意事项
类和类的关系是继承关系,只允许单继承。
类和接口的关系是实现关系,可以多实现。
接口和接口的关系是继承关系,可以多继承。
一个类可以继承1个父类实现N个接口。
public class 类名 extends 父类 implements 接口 {}
面试:模版方法设计模式
模版方法设计模式解决了什么问题?= = >解决方案中存在重复代码的问题。