面向对象的三大特征之一
多种形态->多种表现形式
多态的最终体现:
父类的引用指向子类的对象
多态的前提:
继承关系
实现关系
多态的使用:
需要配合方法的重写才有意义
当多态调用时候,会调用子类中的重写方法
多态引用对子类非重写内容不可见
多态调用成员特点:
成员变量:
编译运行看父类|左边|类型
成员方法:
编译看父类,运行找子类
编译看左边,运行找右边
编译看类型,运行找对象
优点:
减少耦合性,增加灵活性,便于后期维护
package com.xxx.learn.tostringdemo;
public class UserInfo {
private String name;
private int age;
private int id;
public UserInfo(){
}
public UserInfo(String name,int age,int id){
this.name = name;
this.age = age;
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public int getId() {
return id;
}
public String toString(){
return "姓名:"+this.name+"\n年龄:"+this.age+"\n学号:"+this.id+"\n";
}
public void print(){
System.out.println("我是User");
}
}
package com.xxx.learn.tostringdemo;
public class StudentInfo extends UserInfo{
private String className;
public StudentInfo(){
}
public StudentInfo(String name,int age,int id,String className){
super(name,age,id);
this.className = className;
}
public String getClassname() {
return className;
}
public String toString(){
return super.toString()+"班级:"+this.className;
}
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj instanceof StudentInfo){
String name = ((StudentInfo) obj).getName();
String className = ((StudentInfo)obj).getClassname();
return (this.getName().equals(name) && this.getClassname().equals(className) && this.getAge() == ((StudentInfo)obj).getAge() && this.getId() == ((StudentInfo)obj).getId());
}
return false;
}
public void print(){
System.out.println("我是Student");
}
}
package com.xxx.learn.tostringdemo;
public class ToStringDemo {
public static void main(String[] args) {
StudentInfo si1 = new StudentInfo("张三",20,10000,"高一三班");
StudentInfo si2 = new StudentInfo("张",20,10000,"高一三班");
UserInfo ui = new UserInfo("张",20,10000);
//多态,将子类对象赋值给父类的引用
UserInfo ui1 = new StudentInfo("张三",20,10000,"高一三班");
System.out.println(si1);
System.out.println(si2);
System.out.println(si1.equals(si2));
//ui1对象属于StudentInfo类,所以可以判断对象的内容是一致的
System.out.println(si1.equals(ui1));
//此时ui调用的为自己的print方法
ui.print();
si1.print();
//多态的状态下可以实现父类的引用调用子类重写的方法
ui1.print();
}
}
/*
输出:
姓名:张三
年龄:20
学号:10000
班级:高一三班
姓名:张
年龄:20
学号:10000
班级:高一三班
false
true
我是User
我是Student
我是Student
*/
基本数据类型 :
自动类型提升 : 小–>大
int i = ‘a’;
强制类型转换 : 大–>小
byte b = (byte)i;
转型:
引用数据类型:
父类->大
子类->小
向上转型: 小->大
Person p = new Student();
向下转型: 大->小
Student s = (Student)p;
通过多态的引用调用子类中新增的内容时候,需要向下转型
注意:
对象向上转型后再使用向下转型,不能直接父类对象强制转型为子类引用,否则转型后通过子类引用调用子类方法或父类方法会报错
向下转型时候,如果类型不注意,就有可能出现ClassCastException类型转换异常
instanceof 运算符–>避免遇到类型转换异常
引用 instanceof 类型 : 判断前面的引用是否是指向后面类型的对象|子类对象->是true | 不是false
抽象方法:被abstract修饰的方法
没有方法体
要求定义在抽象类中
抽象类:被abstract修饰的类
父类:
具体的父类:普通的类,类中所有的方法必须存在实现(方法体)
抽象的父类:抽象类,可以存在具体方法,可以存在抽象方法
抽象类特点
1.抽象类中可以存在具体方法,可以存在抽象方法
可以存在成员变量,构造器…
2.抽象类不能实例化(不饿能创建对象)
3.一个抽象方法必须被重写,重写可以为抽象方法定义方法体
4.抽象类的使用:通过具体子类的对象使用
具体的子类:重写了所有抽象方法+按需新增
抽象的子类:按需重写抽象方法+按需新增
5.一个抽象方法一旦被重写,后续是否需要重写根据实现
6.abstract关键字不能与private,final,static,native一起使用
package com.xxx.learn.abstractdemo;
public class AbstractDemo {
public static void main(String[] args) {
CarZi1 cz1 = new CarZi1("玛莎拉蒂");
cz1.start();
cz1.stop();
//'CarZi2' is abstract; cannot be instantiated
//CarZi2 cz2 = new CarZi2("玛莎拉蒂");
}
}
abstract class CarAbstract{
public String brand;
public CarAbstract(){}
public CarAbstract(String brand){
this.brand = brand;
}
public abstract void start();
public void stop(){
System.out.println(brand+"停下了");
}
}
class CarZi1 extends CarAbstract{
public CarZi1(){}
public CarZi1(String brand) {
super(brand);
}
//具体子类继承抽象父类,需要将抽象父类中的抽象方法全部实现
public void start(){
System.out.println(brand+"启动了");
}
}
abstract class CarZi2 extends CarAbstract{
public CarZi2(){}
//抽象子类继承抽象父类不需要实现父类中的抽象方法
}
特殊的抽象类
是一种引用数据类型
功能的集合(抽象方法的集合)
继承与实现:
类的继承:
子类一旦继承父类,就有权使用父类中的内容,拿过来就可以直接使用
接口的实现:
实现类一旦实现一个接口,需要对接口中的抽象功能进行实现->重写,然后才能使用
侧重点不同
类只能单继承,接口可以多实现
接口便于后期维护,更加灵活
接口实现解耦(高内聚低耦合)
定义开发规范
推荐使用接口,但是接口不能完全替代父类
定义:
class 类
interface 接口
jdk7及以前:
公共的静态的常量 public static final->默认可以任意省略
公共的抽象的方法 public abstract->默认可以任意省略
jdk8及之后:
接口中可以定义被static或被default修饰的具体方法
1.静态方法
只能跟随接口名.使用,不能在实现类对象调用和重写
2.默认方法
跟随实现类对象调用,可以在实现类中进行重写
接口的使用
1.不能实例化
2.接口需要被实现 通过implements关键字进行实现
3.根据实现类对象使用
具体实现类:重写所有的抽象方法+按需新增
抽象实现类:按需重写抽象方法+按需新增
4.类只能单继承,类可以实现多接口,需要重写多个抽象方法
5.类与接口之间只能是类实现接口,可以多实现
6.接口与接口之间,可以多继承
7.一个类需要先继承后实现
package com.xxx.demo.interfacedemo;
public class InterfaceDemo {
public static void main(String[] args) {
Computer computer = new Computer();
Mouse mouse = new Mouse();
computer.run(computer.check());
//实现类调用接口中的default方法
computer.write();
computer.read();
//接口中static修饰的具体方法只能通过接口名.调用
Usb.initialize();
//接口的多态
computer.startUseUSB(mouse); //computer.startUseUSB(Usb usb);
computer.stopUseUSB(mouse);
}
}
interface Memory{
boolean memory();
}
interface Cpu{
boolean cpu();
}
interface Disk{
boolean disk();
//jdk8及以后可以在接口中声明被default修饰的具体方法
default void write(){
System.out.println("正在向硬盘写入数据...");
}
default void read(){
System.out.println("正在读取硬盘数据...");
}
}
interface Power{
boolean power();
}
interface Usb{
//jdk8及以后可以在接口中声明被static修饰的具体方法
static void initialize(){
System.out.println("驱动正在初始化...");
}
void start();
void stop();
}
//接口可以多继承接口
interface MainBoard extends Memory,Cpu,Disk,Power {
boolean check();
}
//具体类实现接口的所有方法
class Computer implements MainBoard{
@Override
public boolean cpu() {
System.out.println("cpu成功安装");
return true;
}
@Override
public boolean memory() {
System.out.println("内存成功安装");
return true;
}
@Override
public boolean disk() {
System.out.println("硬盘成功安装");
return true;
}
@Override
public boolean power() {
System.out.println("电源成功安装");
return true;
}
@Override
public boolean check(){
if(cpu()&&memory()&&disk()&&power())
System.out.println("硬件自检通过!");
return true;
}
public void run(boolean flag){
if(flag) System.out.println("电脑启动成功!");
}
//接口的多态,将实现类对象给接口的引用,接口的引用调用实现类中重写的方法
public void startUseUSB(Usb usb){
usb.start();
}
public void stopUseUSB(Usb usb){
usb.stop();
}
}
class Mouse implements Usb{
@Override
public void start() {
System.out.println("开始使用鼠标");
}
@Override
public void stop() {
System.out.println("停止使用鼠标");
}
}
单例模式:某个类型只能拥有单个实例->单例模式
实现方式:
1.饿汉式:在类第一次加载完成之后,就创建实例,线程是安全的,同步的,一般效率较低
2.懒汉式:在调用的时候,创建实例,线程是不安全的,不同步的,一般效率较高
步骤:
1.私有的构造器
2.私有的静态的该类的引用->指向创建好的那个对象
3.公共的静态的访问方式->返回提供一个当前类型的实例
package com.xxx.learn.singledemo;
public class SingleDemo {
public static void main(String[] args) {
System.out.println(SingleE.test); //此时SingleE类已被加载,对象已经被创建
System.out.println(SingleE.getSh());
SingleE se = SingleE.getSh();
System.out.println(se);
System.out.println(SingleE.getSh());
SingleL sl = SingleL.getSl();
System.out.println(sl);
System.out.println(SingleL.getSl());
}
}
//饿汉式
class SingleE{
static {
System.out.println("SingleE被加载");
}
private static SingleE se = new SingleE();
private SingleE(){}
public static SingleE getSh(){
return se;
}
}
//懒汉式
class SingleL{
private static SingleL sl = null;
private SingleL(){}
public static SingleL getSl() {
if(sl == null) {
return sl = new SingleL();
}
return sl;
}
}
静态代理:
真实角色
代理角色
条件:
真实角色与代理角色要求实现相同的接口
代理角色需要持有真实角色的引用–>通过属性来维护代理行为
减少与真实角色的沟通,让程序便于后期维护
package com.xxx.learn.proxydemo;
public class ProxyDemo {
public static void main(String[] args) {
//项目经理
Manager manager = new Manager();
//Hr
Hr hr = new Hr(manager);
//开始招人
hr.addUser();
}
}
//招人
interface AddUser{
void addUser();
}
//真实角色 项目经理
class Manager implements AddUser{
@Override
public void addUser() {
System.out.println("录用了...");
}
}
//代理角色
class Hr implements AddUser{
//管理者
Manager manager;
public Hr(Manager manager){
this.manager = manager;
}
@Override
public void addUser() {
System.out.println("发布招聘信息...");
System.out.println("预约面试");
//项目经理面试
manager.addUser();
System.out.println("录用成功..谈薪资...");
}
}
抽象产品角色:具体产品角色实现的接口|继承的父类
具体产品角色:抽象产品角色的实现类
工厂角色