接口
了解了Java面对对象的三大特征分别是封装、继承、多态。
关于什么是封装和继承在之前都有分享过了,只剩这个多态,多态是什么呢?
通过接口让我们好好了解什么是多态。
生活中的接口
生活中比较常见的接口:
USB接口,国标插座,Type-C , 3.5MM , ARJ45 , Lighting接口 , HDMI , VGA, SATA, M.2 , DisplayPort,雷电口, PCI-E
这些接口有什么作用?
USB接口 USB-A
- 鼠标连接,键盘连接,声卡连接,麦克风,摄像头,补光灯,U盘,移动硬盘
- 规范,规范一个接口,都是USB设备
- 就像通过USB接口连接的设备本身决定了,要做什么事情。鼠标、键盘、U盘
Java中接口使用
格式:
interface 接口名 {
成员变量
成员方法
}
类【遵从】或者说实现接口
// implements
class 类名 implements 接口 {
}
接口中成员变量和成员方法缺省属性原因:
从生活角度:USB接口规定了尺寸和连接方式,但是该接口做什么内容,是由设备决定的!!!
尺寸是固定 ==> 成员变量 缺省属性是public static final
设备做什么事情,不管,但是规定连接方式 ==> 成员方法,需要设备自己完成
缺省属性 public abstract修饰
接口使用总结
- 成员变量缺省属性 public static final
成员方法缺省属性 public abstract - 一个非abstract类遵从interface接口,需要强制完成接口中所有缺省属性为public abstract的成员方法
- 接口和接口之间,允许使用extends关键字继承,并且允许一个接口,继承多个接口
interface A extends B, C
生活中: 协议直接的向下兼容问题 - 接口中可以使用default关键字修饰方法,default方法拥有方法体,可以认为是非强制实现方法,不要求遵从接口的非abstract强制实现,JDK1.8新特征
多态
接口生活化演示
从生活中映射USB接口:
interface USB
规定USB设备必须完成的方法:
void connect();
鼠标类 implements USB
鼠标是一个USB设备,必须完成connect方法
键盘类 implements USB
键盘是一个USB设备,必须完成connect方法
USB接口在电脑上,我们需要使用USB接口
/*
从生活中映射USB接口
interface USB
规定USB设备必须完成的方法
void connect();
鼠标类 implements USB
鼠标是一个USB设备,必须完成connect方法
键盘类 implements USB
键盘是一个USB设备,必须完成connect方法
*/
/**
* USB接口
* @author Anonymous
*
*/
interface USB {
/**
* 要求所有的USB设备,必须完成的方法,告知USB接口连接之后完成的
* 功能是什么
*/
void connect();
}
/**
* 鼠标类,遵从USB接口,实现connect方法
*
* @author Anonymous
*/
class Mouse implements USB {
@Override
public void connect() {
System.out.println("鼠标连接USB接口,控制光标");
}
}
/**
* Logi类,继承Mouse鼠标类
* 1. 鼠标设备
* 2. Logi间接遵从USB接口,是一个USB设备
* @author Anonymous
*
*/
class Logi extends Mouse {
@Override
public void connect() {
System.out.println("Logi Master 2S");
}
}
/**
* 键盘类,遵从USB接口,实现connect方法
*
* @author Anonymous
*/
class Keyboard implements USB {
@Override
public void connect() {
System.out.println("键盘连接USB接口,输入设备");
}
}
/**
* IKBC继承Keyboard类
* 1. 键盘设备
* 2. 间接遵从USB接口,也是一个USB设备
* @author Anonymous
*
*/
class IKBC extends Keyboard {
@Override
public void connect() {
System.out.println("IKBC C87 静音红轴");
}
}
/**
* PC电脑类,使用USB接口,这里需要通过USB接口连
接一个USB设备
*
* @author Anonymous
*/
class PC {
/**
* 电脑类连接USB接口连接方法,这里需要的是一
个USB设备
*
* @param usb USB接口对应的设备
*/
public void usbConnect(USB usb) {
// usb设备执行connect方法
usb.connect();
}
}
public class Demo1 {
public static void main(String[] args) {
// 电脑中有一个方法是使用USB接口连接USB设备
PC pc = new PC();
// 鼠标和键盘都是USB设备
Mouse mouse = new Mouse();
Keyboard keyboard = new Keyboard();
// 电脑需要通过USB接口连接USB设备,mouse鼠标就是USB设备
pc.usbConnect(mouse);
// keyboard键盘也是USB设备
pc.usbConnect(keyboard);
// 传入一个Logi类对象
pc.usbConnect(new Logi());
// 传入一个IKBC类对象
pc.usbConnect(new IKBC());
}
}
继承生活化演示
动物园: 所有的动物都可以看做是一个Animal类
狗类:Dog
熊猫类:Panda
老虎类:Tiger
方法:
喂食动物的方法
获取动物的方法
/*
动物园:
所有的动物都可以看做是一个Animal类
狗类:Dog
熊猫类:Panda
老虎类:Tiger
方法:
喂食动物的方法
获取动物的方法
*/
/**
* 动物类
* @author Anonymous
*
*/
class Animal {
}
/**
* 狗类,Animal动物的子类
* @author Anonymous
*
*/
class Dog extends Animal {
}
/**
* 熊猫类,Animal动物的子类
* @author Anonymous
*
*/
class Panda extends Animal {
}
/**
* 老虎类,Animal动物的子类
* @author Anonymous
*
*/
class Tiger extends Animal {
}
public class Demo2 {
public static void main(String[] args) {
Animal animal = new Animal();
Dog dog = new Dog();
Tiger tiger = new Tiger();
Panda panda = new Panda();
// 这里传入一个Animal类对象
feed(animal);
// 这里可以传入Dog类对象,因为Dog类对象是Animal类的子类对象
feed(dog);
// 这里传入的对象是Tiger类对象,Tiger类是Animal的子类
feed(tiger);
// 同上
feed(panda);
// 数据类型强转,
Dog dog2 = (Dog) getAnimal();
System.out.println(dog2.getClass());
}
/**
* 该方法的是喂食【动物】的方法
*
* @param animal 需要的参数是Animal类对象
*/
public static void feed(Animal animal) {
// 获取当前对象的完整包名.类名
System.out.println(animal.getClass() + "来吃饭了!!!");
}
/**
* 返回【动物】类对象的方法
*
* @return Animal类对象
*/
public static Animal getAnimal() {
// return new Animal();
return new Dog();
// return new Tiger();
// return new Panda();
}
}
多态总结
多态:父类的引用指向子类的对象,或者说接口的引用指向遵从接口的类对象,这就是多态。
作用:
- 拓宽方法的参数范围
例如:
方法参数为Animal类型可以传入Animal类型本身,或者其子类对象都可以
方法参数为USB接口类型只要是直接或者间接遵从USB接口的类对象可以作为方法的参数传入 - 拓宽方法的返回值范围
- 简化代码开发,提高开发效率,整合数据类型
异常
生活中的异常
医院看病:
医生问你: 你怎么了?
我: 我难受
医生: 你那里难受
我: 我头疼
医生: 你为什么头痛
我: 昨天晚上喝了2斤二锅头 + 10瓶福佳白 + 1箱1664
医生:…
异常或者说错误,都讲究一个前因后果!!!处理错误,讲究对症下药!!!
代码中的异常
Throwable类
Java中所以异常的超类,在Java中所有的异常,错误的基类就是Throwable类。
Throwable
Exception 异常 可以处理,代码还有拯救的可能性
Error 错误 GG思密达
Throwable常用方法:
Constructor:
Throwable();
Throwable构造方法,Throwable类对象中,存储的异常或者错误信息为null
Throwable(String message);
Throwable构造方法,Throwable类对象中,存储的异常或者错误信息为message
Method:
String getMessage(); 获取Throwable对象中存储的异常或者错误信息
String toString(); 返回当前异常或者错误的简要描述
void printStackTrace(); 展示错误的前因后果,【红色字体】
Exception和Error区别
Exception 异常,可以处置
Error 错误,不可以处置,只能避免
异常处理
捕获异常
try - catch 结构
try - catch - finally 结构 后期设计到资源问题再说
格式:
try {
// 有可能出现异常代码
} catch (/* 对应处理的异常对象 */) {
// 处理方式
}
示范:
/*
* 捕获异常问题总结:
* 1. 代码中从异常发生位置开始,之后的代码都不在运行
* 2. 代码中有多个异常,可以使用多个catch块进行捕获操作,分门别类处理
* 3. 当前情况下,只能展示异常情况,后期可以讲异常情况做成log日志文件
* 4. 异常被捕获之后代码可以正常运行。
*/
public class Demo {
public static void main(String[] args) {
test(10, 2, null);
}
public static void test(int num1, int num2, int[] arr) {
int ret = 0;
try {
ret = num1 / num2;
System.out.println("测试代码");
arr[0] = 10;
} catch (ArithmeticException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
System.out.println("ret:" + ret);
}
}
抛出异常
throw:在方法内抛出异常
throws:在【方法声明】位置,告知调用者当前方法有哪些异常抛出
声明的异常需要生成对应的文档注释
/*
* 抛出异常总结:
* 1. 一个代码块内,有且只能抛出一个异常
* 2. 从throw位置开始,之后的代码不在运行
* 3. 代码中存在使用throw抛出异常,在方法的声明位置必须告知调用者这里有什么异常
*
*/
public class Demo2 {
// 调用带有异常抛出的方法,如果选择继续抛出需要在当前方法的声明位置
// 告知其他调用者,这里有什么异常抛出
public static void main(String[] args)
throws NullPointerException,
ArithmeticException {
// 调用一个带有异常抛出的方法
// 捕获处理
try {
test(10, 2, null);
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
} catch (NullPointerException e) {
System.out.println(e.getMessage());
}
// 可以继续抛出异常
test(10, 0, null);
}
/**
* 测试方法
*
* @param num1 int类型
* @param num2 int类型
* @param arr int类型数组
* @throws ArithmeticException 除数不能为0
* @throws NullPointerException 操作数组null地址异常
*/
public static void test(int num1, intnum2, int[] arr)
throws ArithmeticException,
NullPointerException {
// 参数合法性判断
/*if (0 == num2 || null == arr) {
System.out.println("InputParameter is Invalid!");
return;
}*/
// 抛出异常方式来处理当前的参数合法性判断
if (0 == num2) {
// 有可能会导致算术异常
throw new ArithmeticException("算术异常");
}
if (null == arr) {
// 存在数组操作空指针异常
throw new NullPointerException("数组空指针异常");
}
System.out.println(num1 / num2);
arr[0] = 10;
}
}
抛出和捕获的对比
捕获之后,代码可以正常运行,要保证处理之后的异常不会在导致其他问题。
例如:
用户名密码错误,不能采用捕获异常。
用户指定路径问题,也不能采用捕获异常。
抛出的确可以解决很多问题,并且可以让代码健壮性很强。到用户层面说什么都不能抛出异常。所谓不能抛出,是指不能讲错误信息直接甩到用户脸上。
用户密码错误情况:
- 捕获异常
- 通过异常处理 catch将错误抛出
- 给予用户的友好提示
为什么不使用大异常和不知道为什么出错
直接抛出Exception?
不行!!!对症下药!!!
不能所有的异常都使用Exception捕获或者抛出无法得知具体的异常类型,无法做到对症下药,
不知道为什么出错,Eclipse IDEA都会有当前错误的提示。
正常情况下,只要不是带有自定义异常的方法,通常情况下需要处理的异常,代码中都有会有声明告知。如果未处理异常,代码报错。
RuntimeException
运行时异常: JVM在运行的过程中可以非检查异常
例如:
ArrayIndexOutOfBoundException //下标越界
NullPointerException //空指针
StringIndexOutOfBoundException //下标越界
ArithmeticException
这些异常在代码中如果出现,不需要代码中强制进行捕获或者抛出处理。
自定义异常
代码运行的过程中存在一定的生活化
例如:
用户名密码错误
NoGirlFriendException //没有女朋友异常
自定义异常格式:
class 自定义异常类名 extends Exception {
// No Fields Constructor
// String Field Constructor
}
自定义异常类名:必须Exception结尾!!!
/*
* 自定义异常
*/
class NoGirlFriendException extends Exception {
/**
* 无参数构造方法
*/
public NoGirlFriendException() {}
/**
* 带有String类型参数的构造方法
*
* @param message 描述当前的异常信息
*/
public NoGirlFriendException(String message) {
super(message);
}
}
public class Demo5 {
public static void main(String[] args)
throws NoGirlFriendException {
try {
buyOneFreeOne(false);
} catch (NoGirlFriendException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
buyOneFreeOne(false);
}
/**
* 买一送一方法,需要判断是不是单身狗
*
* @param singleDog boolean类型数据,true 是单身,false表示有女朋友
* @throws NoGirlFriendException 没有女朋友异常
*/
public static void buyOneFreeOne(boolean singleDog)
throws NoGirlFriendException {
if (singleDog) {
throw new NoGirlFriendException("两只黄鹂鸣翠柳,你还没有女朋友");
}
System.out.println("买蜜雪冰城甜筒一个送保时捷一辆");
}
}