这篇文章只是为了复习做的记录,还会有其他的文章
一部分来自JavaGuide
大家可以关注😁😁😁😁
异常
Exception和Error有什么区别
Throwable是所有错误和异常的父类
- Exception:程序本身可以处理的异常,可以通过
catch
来进行捕获。Exception
又可以分为Checked Exception(受检异常,必须处理)和Unchecked Exception(非受检异常,可以不处理) - Error:Error属于程序无法处理的错误,不建议通过
catch
捕获。例如Java虚拟机运行错误VirtualMachineError
、虚拟机内存溢出错误OutOfMemoryError
、类定义错误NoClassDefFoundError
等。这些错误发生时,Java虚拟机一般会选择线程终止
Checked Exception和Unchecked Exception有什么区别
Checked Exception即受检异常,Java代码在编译过程中,如果受检异常没有被处理,就没办法通过编译
除了RuntimeException
及其子类以外,其他的Exception
类及其子类都属于受检异常。常见的受检异常有:IO相关的异常、ClassNotFoundException
、SQLException
Unchecked Exception即非受检异常,Java代码在编译过程中,即使不处理也可以正常通过编译
RuntimeException
及其子类都统称为非受检异常,常见的有
NullPointerException
(空指针错误)IllegalArgumentException
(参数错误比如方法入参类型错误)NumberFormatException
(字符串转换为数字格式错误,IllegalArgumentException
的子类)ArrayIndexOutOfBoundsException
(数组越界错误)ClassCastException
(类型转换错误)ArithmeticException
(算术错误)SecurityException
(安全错误比如权限不够)UnsupportedOperationException
(不支持的操作错误比如重复创建同一用户)
Throwable类的常用方法有哪些
// 返回抛出异常的详细信息
public string getMessage();
public string getLocalizedMessage();
// 返回异常发生时的简要描述
public public String toString();
// 打印异常信息到标准输出流上
public void printStackTrace();
public void printStackTrace(PrintStream s);
public void printStackTrace(PrintWriter s);
// 记录栈帧的当前状态
public synchronized Throwable fillInStackTrace();
finally中的代码一定会执行吗
不一定!
- finally之前虚拟机被终止运行的话,finally中的代码就不会被执行
try {
System.out.println("Try to do something");
throw new RuntimeException("RuntimeException");
} catch (Exception e) {
System.out.println("Catch Exception -> " + e.getMessage());
// 终止当前正在运行的Java虚拟机
System.exit(1);
} finally {
System.out.println("Finally");
}
输出:
Try to do something
Catch Exception -> RuntimeException
另外还有两种特殊情况finally块的代码不会被执行:
- 程序所在的线程死亡
- 关闭CPU
throw和throws的区别
位置不同
- throws用在方法上,后面是异常类;throw用在方法内,后面是异常对象
功能不同
- throws用来声明异常,让调用者只知道该功能可能出现的异常,可以给出预先的处理方式;throw抛出具体问题对象,执行到throw,功能就结束了,跳转到调用者,并将具体问题对象抛给调用者。就是说throw语句独立存在时,下面不要定义其他语句,因为执行不到
- throws表示出现异常的一种可能性;throwe则是抛出了异常,执行throw则一定抛出某种异常对象
- 两者都是消极处理异常的方式,只有抛出或者可能抛出异常,但是不会由方法去处理异常,真正处理异常使用上层调用处理
泛型
泛型是JDK 1.5之后的特性,使用泛型,可以增强代码的可读性和稳定性。
编译器会对泛型参数进行检测,并且通过泛型参数可以指定传入的对象类型。
项目中哪里用到了泛型
- 自定义接口通用返回
CommonResult<T>
通过参数T可根据具体的返回类型动态的指定结果的类型 - 定义
Excel
处理类ExcelUtil<T>
用于动态指定Excel导出的数据类型 - 构建集合工具类
注解
注解又称元数据,在代码中提供了一种形式化的方法。是JDK 1.5 引入的,Java定义了一天注解,共7个,3个在java.util
中,4个在java.lang.annotation
中
注解本质是一个继承了Annotation
的特殊接口
元注解有四个,元注解就是用来标志注解的注解。
@Retention
:标志如何存储,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问
RetentionPolicy.SOURCE
:注解只在源文件中,当Java文件编译成class文件的时候,注解被遗弃
RetentionPolicy.CLASS
:注解保留在class文件,但JVM加载class文件时被遗弃,这是默认的生命周期
RetentionPolicy.RUNTIME
:注解不仅被保存到class文件中,JVM加载class文件之后,仍然存在
@Documented
:标记这些注解是否包含在JavaDoc中@Target
:标记这个注解说明了Annotation所修饰的对象范围,Annotation可被用于packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)
public enum ElementType {
TYPE,
FIELD,
METHOD,
PARAMETER,
CONSTRUCTOR,
LOCAL_VARIABLE,
ANNOTATION_TYPE,
PACKAGE,
TYPE_PARAMETER,
TYPE_USE
}
@Inherited
:标记这个注解是继承于哪个注解类的
从JDK 1.7 开始,又添加了三个额外注解
@SafeVarargs
:在声明可变参数的构造方法时,Java编译器会报unchecked警告。使用@SafeVarargs可以忽略这些警告@FunctionInterface
:表明这个方法是一个函数式接口@Repeatable
:标识某注解可以在同一个声明上使用多次
注意:注解是不支持继承的。
反射
在Java中的反射机制是指**在运行状态中,对于任意一个类都能知道这个类所有的属性和方法了;并且对于任意一个对象,都能够调用它的任意一个方法;**这种动态获取信息以及动态调用对象方法的功能成为Java的反射机制
反射的优缺点
反射使代码更加灵活、为各种框架提供开箱即用的功能提供了便利
不过反射让我们在运行时有了分析操作类的能力的同时,也增加了安全问题,比如可以无视泛型参数的安全检查。另外反射的性能稍差
反射的应用场景
- jdbc
- 框架中使用的大量动态代理
- 注解
反射使用步骤
- 获取想要操作的类的Class对象,是反射的核心,通过Class对象我们可以任意调用类的方法
- 调用Class类中的方法,即反射的使用阶段
- 使用反射API来操作这些信息
获取Class对象的3种方法
- 调用某个对象的
getClass()
方法
Person p = new Person();
Class clazz = p.getClass();
- 调用某个类的class属性获取该类对应的Class对象
Class clazz = Person.class;
- 使用Class类中的
forName()
静态方法最安全性能最好
Class clazz = Class.forName("com.lyu.reflection.Person");
当我们获得了想要操作的类的 Class 对象后,可以通过 Class 类中的方法获取并查看该类中的方法和属性。
//获取 Person 类的 Class 对象
Class clazz=Class.forName("com.lyu.reflection.Person");
//获取 Person 类的所有方法信息
Method[] method=clazz.getDeclaredMethods();
for(Method m:method){
System.out.println(m.toString());
}
//获取 Person 类的所有成员属性信息
Field[] field=clazz.getDeclaredFields();
for(Field f:field){
System.out.println(f.toString());
}
//获取 Person 类的所有构造方法信息
Constructor[] constructor=clazz.getDeclaredConstructors();
for(Constructor c:constructor){
System.out.println(c.toString());
}
创建实例对象的两种方法
- Class对象的
newInstance()
- 使用Class对象的
newInstance()
方法来创建该Class对象对应类的实例,但是这种方法要求该Class对象对应的类有默认的空参构造器
- 调用Constructor对象的
newInstance()
- 先使用Class对象获取指定的Constructor对象,再调用Constructor对象的
newInstance()
方法来创建Class对象对应类的实例,通过这种方法可以选定构造方法创建实例
//获取 Person 类的 Class 对象
Class clazz=Class.forName("com.lyu.reflection.Person");
//使用.newInstane 方法创建对象
Person p=(Person) clazz.newInstance();
//获取构造方法并创建对象
Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class);
//创建对象并设置属性
Person p1=(Person) c.newInstance("李四","男",20);