零.昨日复习
零.晨考:
- final 修饰引用数据类型变量有什么特征?
- final 修饰引用数据类型变量,存储地址不可变[指向不可变]
- 引用数据类型指向的空间内容可以修改[指向内容可变]
static 修饰静态代码块使用要求
类文件加载阶段,static 修饰静态代码块内容一定执行,并且有且只执行一次。
静态代码块可以使用类内的静态资源
静态代码块不可以使用类内的非静态资源
静态代码块常用于项目启动初始化操作,配置文件读取,日志文件加载,相关配套程序准备。。。
常用运算符
算术运算符:
±*/ % () =
+= -= *= /= %=
关系运算符:< >= <= != ==
逻辑运算符:
&& 同真为真,有假【即】假
|| 有真【即】真,同假为假
! 取反
条件运算符:
condition ? true result : false result;
自增自减运算符:++
abstract 修饰成员方法有什么特征
方法没有方法体
方法有且只能定义在 abstract 修饰的类内或者 interface 接口中
一个非 abstract 修饰类继承 abstract 或者 遵从 interface 接口,必须实现 abstract 修饰的方法。
public protected private 关键字修饰特征
public
公开的~~~
protected
1. 类内使用
2. 同包内使用
3. 子孙类可以使用
private
有且只能类内使用
- 数组容量的范围
0 ~ Integer.MAX_VALUE - 8
一.interface接口【重点】
1.1 interface接口语法特征
关键字:
interface
类【遵从】关键字:
implements
接口的定义格式:
interface 接口名{
成员变量;//缺省属性 public static final 公开的带有名称的常量,仅提供数据操作
成员方法;// 缺省属性 public abstract
默认成员方法;
}
遵从接口的格式
class TypaA implements 接口名 {
// TypeA 类必须实现接口中所有缺省属性为public abstract 的修饰方法
}
基本语法代码演示
package com.qfedu.a_interface;
// 自定义接口
interface A {
int NUM = 10; // 缺省属性 public static final
void test(); // 缺省属性 public abstract
}
class TypeA implements A {
@Override
public void test() {
System.out.println("Type A 类遵从接口 A 实现 test 方法");
}
}
/**
* @author Anonymous 2023/2/27 9:37
*/
public class Demo1 {
public static void main(String[] args) {
new TypeA().test();
}
}
1.2interface语法特殊用法
一个类可以遵从多个接口
interface B {
void testB();
void test();
}
interface C {
void testC();
void test();
}
/**
* 一个类可以同时遵从多个接口,不同的接口使用 , 隔开
*/
class TypeB implements B, C {
@Override
public void testB() {
System.out.println(111);
}
@Override
public void testC() {
System.out.println(222);
}
@Override
public void test() {
System.out.println("遵从多接口,接口中有相同声明的方法,实现类有且只实现一次即可。");
}
}
接口可以继承,且可以多继承其他接口
package com.qf.poly;
public interface USB1_0 {
void usb1_0Connected();
}
interface USB2_0 {
void usb2_0Connected();
}
interface USB3_0 {
void usb3_0Connected();
}
/*
USB3.1同时继承 USB1-0,USB2_0,USB3_0接口
表示USB3.1接口向下兼容
*/
interface USB3_1 extends USB1_0,USB2_0,USB3_0 {
void usb3_1Connected();
}
/*
实现类遵从接口,同时需要实现当前接口对应父类接口中的缺省属性为 public abstract 修饰方法
*/
class LogiUDisk implements USB3_1 {
@Override
public void usb1_0Connected(){
System.out.println("USB 1_0支持");
}
@Override
public void usb2_0Connected() {
System.out.println("Usb 2_0支持");
}
@Override
public void usb3_0Connected() {
System.out.println("usb 3_0支持");
}
@Override
public void usb3_1Connected() {
System.out.println("usb 3_1支持");
}
}
default 关键字特征
default 关键字在接口中有什么作用
修饰方法,对应方法可以有方法体
JDK1.8 以上版本支持。
interface D {
// 缺省属性为 public abstract 修饰方法
void test();
default void defaultMethod() {
System.out.println("JDK 1.8 以上版本支持的 default 接口方法修饰默认方法");
}
}
class TypeC implements D {
@Override
public void test() {
System.out.println("遵从接口要求必须实现的方法");
}
@Override
public void defaultMethod() {
System.out.println("接口中默认方法,实现类可以【重写】");
}
}
二.多态
编译看左,运行看右
白话:
父类的引用数据类型变量,指向子类或者间接子类的对象(向上转型)
接口的引用数据类型变量,指向遵从接口的实现类对象。
2.1多态举例
package com.qf.poly;
// 父类
class Animal {}
// Animal子类
class Panda extends Animal {}
class Monkey extends Animal {}
class Snake extends Animal {}
// Animal 孙类
class JSMonkey extends Animal {}
public class Demo1 {
public static void main(String[] args) {
// 创建父类和子类对象
Animal animal = new Animal();
Animal panda = new Panda();
Animal monkey = new Monkey();
Animal snake = new Snake();
/*
面向对象编程过程中:
要什么给什么,用什么拿什么 【数据类型一致化】
*/
// 当前方法所需数据类型为 Animal 类型
feedAnimal(animal);
// 当前方法参数支持 Animal 类型的子类。
feedAnimal(panda);
feedAnimal(monkey);
feedAnimal(snake);
feedAnimal(new JSMonkey());
System.out.println("--------------------------");
/*
利用多态
*/
//数据类型向上转型
//Panda 类型对象 ==> Animal 类型
Animal a1 = new Panda();
System.out.println(a1.getClass().getName() + "来吃饭啦~~");
}
public static void feedAnimal(Animal animal) {
/*
animal.getClass().getName()
获取当前参数对象,对应的具体的数据类型名称
*/
System.out.println(animal.getClass().getName() + "来吃饭啦~");
}
}
2.2USB接口
后期项目中框架,模块,功能,基本上都是通过接口衔接,降低代码的耦合度,提高代码的复用度和可移植性。
package com.qf.poly;
import java.awt.peer.MouseInfoPeer;
interface USB {
void connect();
}
class Mouse implements USB {
@Override
public void connect() {
System.out.println("鼠标遵从USB接口");
}
}
class LogiMouse extends Mouse {
@Override
public void connect() {
System.out.println("罗技鼠标遵从鼠标");
}
}
class Keyboard implements USB {
@Override
public void connect() {
System.out.println("键盘遵从USB接口");
}
}
class IKBCKeyboard extends Keyboard {
@Override
public void connect() {
System.out.println("IKBC键盘遵从键盘");
}
}
// 电脑类
class PC{
// 电脑声明方法,需要连接USB设备
public void useUSBInterface(USB usb) {
// 通过USB接口调用connect方法,该方法具体实现内容是由USB实现类决定
usb.connect();
}
}
public class Demo2 {
public static void main(String[] args) {
Mouse mouse = new Mouse();
Keyboard keyboard = new Keyboard();
PC pc = new PC();
/*
方法所需参数为接口类型,实际所需的类型是接口的实现类对象。【开发中常用模式】
interface 接口同时也是一个特殊的类。
*/
pc.useUSBInterface(mouse);
pc.useUSBInterface(keyboard);
pc.useUSBInterface(new LogiMouse());
pc.useUSBInterface(new IKBCKeyboard());
}
}
2.3 多态总结
- 拓宽方法参数支持数据类型范围,满足数据类型一致化,支持数据类型多样化
- 拓宽方法返回值类型,可以支持类型统一。
三.匿名内部类【重点】
JDK 1.7 版本及其以下版本常用,JDK 1.8 修改为 lambda 但是有语法限制
package com.qf.poly;
interface A {
void test();
}
/*
【类名没用】
1. 有对象
2. 方法实现
*/
class TypeA implements A {
@Override
public void test() {
System.out.println("TypeA 遵从接口 A 实现方法");
}
}
/**
* @author Anonymous 2023/2/27 11:47
*/
public class Demo3 {
public static void main(String[] args) {
TypeA typeA = new TypeA();
typeA.test();// TypeA 遵从接口 A 实现方法
/*
问题一:
请问这里实例化的是 A 接口对象还是 A 接口实现类对象???
A 接口实现类对象
问题二:
大括号内容是否可以看做是一个接口 A 实现类【本体】???
是的!!!
问题三:
A() 接口 A 的构造方法,该方法做了什么事情???
A 在这里提供数据类型,并且隐含遵从关系,告知编译器当前实例化对象
是遵从接口 A 的实现类对象。
A ==> XXX implements A
() 借用接口 A 的构造方法,实际上实例化对象是接口 A 的实现类对象
但是没有类名。
【匿名内部类】
问题四:
实例化实现类对象赋值给接口 A 的引用数据类型变量
【多态】
接口的引用数据类型变量,指向遵从接口的实现类对象
*/
A a = new A() {
@Override
public void test() {
System.out.println("不报错");
}
};
a.test();
// 匿名内部类的匿名对象,直接调用方法。
new A() {
@Override
public void test() {
System.out.println("常用写法");
}
}.test();
}
}
补充:自己的内容
1基于接口
需求:想使用A接口,并创建多个对象
传统方式:需要几个就写个类,并且遵从该接口,然后创建对象
public class AnonymousInnerClass {
public static void main(String[] args) {
A tiger = new Tiger();// 多态
tiger.cry();
A dog = new Dog();
dog.cry();
}
}
interface A {// 接口
public void cry();
}
class Tiger implements A {
@Override
public void cry() {
System.out.println("老虎叫唤~~");
}
}
class Dog implements A {
@Override
public void cry() {
System.out.println("狗嗷嗷叫~~");
}
}
但是这些类我如果只是使用一次,后面不再使用。就非常占用空间
此时可以使用匿名内部类来简化开发
public class AnonymousInnerClass {// 外部类
public static void main(String[] args) {
/*
接口本不能new,这里的本质是系统在底层给我们分配了一个临时的、名字为外部类 + $ + 序号的类(即匿名内部类):
class AnonymousInnerClass$1 implements A {
@Override
public void cry() {
System.out.println("老虎嗷嗷叫~");
}
}
*/
A Tiger = new A() {
@Override
public void cry() {
System.out.println("老虎嗷嗷叫~");
}
};
Tiger.cry();
System.out.println("Tiger的运行类型是" + Tiger.getClass());// AnonymousInnerClass$1 (即:外部类 + $ + 匿名内部类的序号)
// // 或者也可以直接调用,匿名内部类本身返回的也是对象!
// new A() {
// @Override
// public void cry() {
// System.out.println("老虎嗷嗷叫~");
// }
// }.cry();
}
}
interface A {// 接口
public void cry();
}
2基于类的
总结(个人理解):其实就是在创建对象的过程的那一步加了一个{ },而new的谁,{ }内就重写谁的方法,相当于系统在底层创建了一个临时的类,且这个类继承了父类。而这个类就叫做匿名内部类
public class AnonymousInnerClass {// 外部类
public static void main(String[] args) {
/*
相当于在底层进行了
class AnonymousInnerClass$2 extends Father {
@Override
public void test() {
System.out.println("匿名内部类重写了Father的方法`");
}
}
*/
Father father = new Father("Tom") {
@Override
public void test() {
System.out.println("匿名内部类重写了Father的方法`");
}
};
father.test();
System.out.println(father.getClass());// AnonymousInnerClass$2
// // 或者也可以直接调用,匿名内部类本身返回的也是对象!
// new Father("Tom") {
// @Override
// public void test() {
// System.out.println("匿名内部类重写了Father的方法`");
// }
// }.test();
}
}
class Father {
public Father(String name) {// 构造器
}
public void test() {
}
}
3匿名内部类的细节
1.可以直接访问外部类的所有成员,包含私有的
2.不能添加访问修饰符,因为他的地位就是一个局部变量
3.作用域:仅仅在定义它的方法或代码块中
4.匿名内部类---->访问---->外部类成员【访问方式:直接访问】
5.外部其它类---->不能访问---->匿名内部类(因为匿名内部类地位是一个局部变量)
8.如果外部类和内部类的成员重名时,内部类访问的胡,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
四.泛型
4.1泛型概述
1.泛型满足数据类型支持多样化
2.严格遵守数据类型一致化要求
3.核心目标是增强方法
4.2泛型的格式
<英文单个大写字母无意义占位符>
一般情况下会选择以下占位符
T Type 类型
E Element 元素
K Key 键
V Value 值
R Return 返回值
语法特征:
1.单一方法增强
2.整体方法增强
a.类声明泛型,类内的成员方法使用
b.接口声明泛型,接口内成员方法使用
4.3泛型增强方法
4.3.1单一方法增强
语法格式:
权限修饰符 [static] <自定义泛型占位符> 返回值 方法名(形式参数列表) { 方法体; }
[严格要求:]形式参数列表中必须有一个参数对应自定义泛型,用于明确约束泛型对应的具体数据类型
其他:
返回值类型可以是自定义泛型T
方法内可以使用泛型定义的局部变量
package com.qf.fx;
import java.io.Serializable;
public class Demo1 {
public static void main(String[] args) {
Integer a = getType(100);
String b = getType("党浩");
Demo1 d = new Demo1();
System.out.println(a);// 100
System.out.println(b);// 党浩
System.out.println(d);// com.qf.fx.Demo1@14ae5a5
System.out.println("-----------------------");
/*
* ??? ? = test(1, "字符串");
* test(T, T)
* 按照开发规则,实际参数的数据类型应该是一致的,如果不一致,为了满足
* 代码的正常运行,会选择变成 Object 类型,失去方法增强含义。
*/
Object e = test(1, "党浩");
System.out.println(e);// 1
}
// 声明一个带有自定义泛型的方法
// 泛型占位符为 T ,方法参数数据类型对应自定义泛型类型
// t 自定义泛型参数
// <T> 自定义泛型占位符
// return 自定义泛型类型,具体数据类型需要通过用户传递实际参数来明确
public static <T> T getType(T t) {
return t;
}
public static <T> T test(T t1,T t2) {
return t1;
}
}
package com.qfedu.d_genericity;
import java.util.Arrays;
/**
* @author Anonymous 2023/2/27 14:59
*/
public class MyArrays {
/*
以下三个 public 修饰的公开方法,提供给用户使用,满足用户使用的多样性,数据类型
处理的单一性。
*/
public static void printIntArray(Integer[] arr) {
printArray(arr);
}
public static void printDoubleArray(Double[] arr) {
printArray(arr);
}
public static void printFloatArray(Float[] arr) {
printArray(arr);
}
/*
工具类私有化方法,使用泛型约束方法的参数类型,增强方法功能,用于处理
数组类型数据展示打印功能,提供给以上三个 public 修饰公开方法使用。
可以同时满足用户操作使用工具的多样性,同时满足数据处理一致性,节约代码资源。
*/
private static <T> void printArray(T[] arr) {
Arrays.sort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
4.3.2类声明泛型
定义类的格式,在类声明位置告知编译,当前类内有自定义泛型,主要用于方法增强
class 类名<自定义泛型占位符> {
成员方法可以使用自定义泛型.
}
类名带有自定义泛型,需要通过【实例化】对象过程进行泛型对应具体数据类型确定。
// IDEA 写法
类名<具体数据类型> 类对象 = new 类名<>();
4.3.3接口声明泛型
接口声明泛型
interface 接口名<自定义泛型占位符> { 接口中的成员变量无法使用自定义泛型,因为缺省属性为 public static final ,定义时需要初始化。无法对于泛型类型进行初始化操作。 因此接口声明泛型有且只用于成员方法。 1. 缺省属性为 public abstract 的方法可以使用自定义泛型 2. default 默认方法也可以使用自定义泛型 }
接口声明泛型影响的是实现类操作,实现类遵从带有自定义泛型的接口有两种形式
- 妻管严 【约束模式】
- 媳妇回娘家 【自由模式】
接口实现
interface A<T> {
/**
* 缺省属性为 public abstract 修饰方法,带有自定义泛型
* return 接口约束的自定义泛型,需要实现类明确泛型对应的具体类型
*/
T getType(T t);
/**
* default 约束的默认方法,可以有方法体,这里使用的自定义泛型。
* return 接口约束的自定义泛型,需要实现类明确泛型对应的具体类型
*/
default T testDefault(T t) {
return t;
}
}
妻管严模式
/*
【妻管严模式】
类遵从接口,直接明确泛型对应的具体数据类型
A<String> 告知编译器,当前接口中泛型对应的具体数据类型为 String 类型
要求 TypeB 中实现的方法,所有泛型对应的位置都是 String 类型。
*/
class TypeB implements A<String> {
/*
所有泛型对应的位置都是 String 类型
*/
@Override
public String getType(String s) {
return s;
}
@Override
public String testDefault(String s) {
return s;
}
}
媳妇回娘家,自由模式
/*
媳妇回娘家,自由模式
TypeC 类遵从接口 A 并且 TypeC 类声明和接口一致的泛型占位符。
泛型对应的具体数据类型,是通过实例化对象操作约束。
*/
class TypeC<T> implements A<T> {
@Override
public T getType(T t) {
return t;
}
@Override
public T testDefault(T t) {
return t;
}
}
五.异常
5.1异常的结构
Java 中所有异常和错误的基类:
Throwable
Throwable 有两个子类
--| Exception 异常 可以处理【捕获,抛出】
--| Error 错误 只能不写 BUG
涉及到的方法:
构造方法 Constructor
Throwable();
无参数构造方法,用于初始化异常/错误信息为 null 的构造方法,很少使用。
Throwable(String message);
使用 message 描述当前的异常/错误信息
成员方法 Method
printStackTrace();
在控制台展示错误/异常导致的方法调用流程,和错误信息,红色
String toString();
获取当前异常/错误简要信息描述,异常/错误的类型
String getMessage();
获取当前异常/错误的信息
5.2异常的分类
运行时异常
Java 编译器不会提示当前异常的处理要求,JVM 针对于这些异常是有对应的处理手段,通常是
printStackTrace 方法。
编译时异常
【提示】告知程序员当前代码出现异常的情况非常紧急,极易出现.
代码编写过程中,针对于当前异常进行预处理【捕获,抛出】
后期项目中 【Servlet】
可以完成规范的异常处理器,针对于不同的异常类型,不同的异常情况,不同的异常等级,进行分别处理
INFO 信息
WARNING 警告
DANGER 危险
ERROR 错误
5.3异常处理方式——捕获
package com.qfedu.e_throwable;
import java.lang.reflect.Method;
/**
* 捕获异常
* 1. 如果代码通过 try - catch 捕获异常,JVM 会认为当前代码中没有异常情况,可以正常运行。
* 2. 支持多个 catch 处理不同的异常
* 3. 目前没有其他方式可以处理异常,后期可以记录错误日志。
* 4. try - catch - finally 后期用于管理资源
* @author Anonymous 2023/2/27 20:49
*/
public class Demo1 {
public static void main(String[] args) {
/*
try 大括号中是有可能出现异常代码
*/
try {
/*
用户指定对应类型的完整的【包名.类名】获取对应类型的 Class 对象【反射重点 Reflect】
*/
Class<?> aClass = Class.forName("com.qfedu.a_interface.D1");
Method test = aClass.getMethod("test");
} catch (ClassNotFoundException e) {
/*
catch 之后是捕获的异常类型,同时将当前异常对象临时存储到引用数据变量 e 中
之后是针对于当前异常的处理形式,处理方法,Java 默认是 控制台展示。
*/
e.printStackTrace();
} catch (NoSuchMethodException e) {
// try - catch 允许多个异常情况,可以分门别类处理不同的异常信息。
e.printStackTrace();
}
System.out.println("-------------代码正常运行---------------");
}
}
5.4常处理方式——抛出
使用的关键字:
throws在方法的声明位置告知调用者当前方法有哪些异常抛出
throw在方法中,出现对应的异常情况,异常数据,抛出对应的异常对象,并且带有异常信息。
package com.qfedu.a_throwable;
import java.io.FileNotFoundException;
/**
* @author Anonymous 2023/2/28 9:34
*/
public class Demo1 {
public static void main(String[] args)
throws FileNotFoundException {
/*
调用一个带有异常抛出的方法,需要考虑当前异常的处理方式
方式一: 捕获处理
方式一: 抛出处理
*/
try {
// 捕获处理
searchFile("1.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 抛出处理 当前方法声明位置补充 throws FileNotFoundException
searchFile("2.txt");
}
/**
* 搜索文件方法
*
* @param fileName 用户指定的方法名
* @throws FileNotFoundException 用户提供的文件路径/名称不符合要求
*/
public static void searchFile(String fileName)
throws FileNotFoundException {
/*
判断用户同的文件路径是否有问题
情况一: 用户提供的 fileName 是 null
情况二: 用户提供的 fileName 字符串为 空字符串
一定会导致文件找不到!!!
*/
if (null == fileName || "".equals(fileName)) {
/*
throw 抛出异常的关键字
new FileNotFoundException() 实例化异常对象,同时提供对应的异常信息
IDEA错误提示: Unhandled exception: java.io.FileNotFoundException
【注意】
方法运行到 throw 抛出异常操作,当前代码终止运行。
*/
throw new FileNotFoundException("文件路径不合法");
}
// 每一个错误条件有且只能抛出一个异常对象,如果存在多种异常情况,需要不同的 if 判断执行。
if (fileName.length() > 10) {
throw new IllegalArgumentException("非法参数异常");
}
System.out.println("已找到" + fileName);
}
}
5.5抛出和捕获的对比
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i9wrvUGc-1678062678773)(GP_05.assets/image-20230228141927536.png)]
* @throws FileNotFoundException 用户提供的文件路径/名称不符合要求
/
public static void searchFile(String fileName)
throws FileNotFoundException {
/
判断用户同的文件路径是否有问题
情况一: 用户提供的 fileName 是 null
情况二: 用户提供的 fileName 字符串为 空字符串
一定会导致文件找不到!!!
/
if (null == fileName || “”.equals(fileName)) {
/
throw 抛出异常的关键字
new FileNotFoundException() 实例化异常对象,同时提供对应的异常信息
IDEA错误提示: Unhandled exception: java.io.FileNotFoundException
【注意】
方法运行到 throw 抛出异常操作,当前代码终止运行。
*/
throw new FileNotFoundException("文件路径不合法");
}
// 每一个错误条件有且只能抛出一个异常对象,如果存在多种异常情况,需要不同的 if 判断执行。
if (fileName.length() > 10) {
throw new IllegalArgumentException("非法参数异常");
}
System.out.println("已找到" + fileName);
}
}
## 5.5抛出和捕获的对比
![\[外链图片转存中...(img-i9wrvUGc-1678062678773)\]](https://img-blog.csdnimg.cn/271afe6ba15446bca520330254dc4daf.png)