异常处理
-
throws在方法体前声明此方法可能抛出的异常
-
throw在方法体内执行抛出异常对象
-
异常捕获处理
try {} catch{} finally{}
-
catch块和finally块同时有return或throw语句时, finally块会覆盖catch的return和throw
-
catch块内语句执行完才会跳转到finally块
-
自定义异常, 通常是从
RuntimeException
派生业务根异常BaseException
, 然后再派生具体的业务异常public class BaseException extends RuntimeException { public BaseException() { super(); } public BaseException(String message, Throwable cause) { super(message, cause); } public BaseException(String message) { super(message); } public BaseException(Throwable cause) { super(cause); } // 提供多种构造方法 } public class UserNotFoundException extends BaseException { } public class LoginFailedException extends BaseException { }
反射
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
Class类
-
class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存。
-
每加载一种class,JVM就为其创建一个
Class
类型的实例,并关联起来 -
一个
Class
实例包含了该class的所有完整信息 -
通过
Class
实例获取class信息的方法称为反射(Reflection)// 通过类的静态变量class获取 Class cls1 = String.class; // 通过实例变量的getClass方法获取 Class cls2 = "abcd".getClass(); // 利用一个类的完整类名, 通过静态方法Class.forName()获取 Class cls3 = Class.forName("java.lang.String");
-
Class
实例在JVM中是唯一的, 所以可以用==
比较两个Class实例 -
Class
实例比较与instanceOf
的区别:Integer n = new Integer(123); boolean b1 = n instanceof Integer; // true,因为n是Integer类型 boolean b2 = n instanceof Number; // true,因为n是Number类型的子类 boolean b3 = n.getClass() == Integer.class; // true,因为n.getClass()返回Integer.class boolean b4 = n.getClass() == Number.class; // false,因为Integer.class!=Number.class
-
对象实例转型后并不会改变其关联的class信息
-
cls.getName()
, 完整类名 -
cls.getSimpleName()
, 简单类名 -
cls.getPackage().getName()
, 包名 -
cls.isInterface()
, 是否接口 -
cls.isEnum()
, 是否枚举 -
cls.isArray()
, 是否数组 -
cls.isPrimitive()
, 是否基本类型 -
注意: 数组也有
Class
, 而且不同于其基础类型的Class
-
基本类型也有
Class
Class类实例方法
访问字段
Field getField(name)
:根据字段名获取某个public的field(包括父类)Field getDeclaredField(name)
:根据字段名获取当前类的某个field(不包括父类)Field[] getFields()
:获取所有public的field(包括父类)Field[] getDeclaredFields()
:获取当前类的所有field(不包括父类)
Field对象方法
-
getName()
:返回字段名称,例如,“name”; -
getType()
:返回字段类型,也是一个Class
实例,例如,String.class; -
getModifiers()
:返回字段的修饰符,它是一个int,不同的bit表示不同的含义。 -
利用反射获取字段信息:
Field f = String.class.getDeclaredField("value"); f.getName(); // "value" f.getType(); // class [B 表示byte[]类型 int m = f.getModifiers(); Modifier.isFinal(m); // true Modifier.isPublic(m); // false Modifier.isProtected(m); // false Modifier.isPrivate(m); // true Modifier.isStatic(m); // false
-
获取对象的字段值
f.get(Object)
-
private字段会报错, 使用
f.setAccessible(true)
可以开放权限再获取, 但也可能失败(有安全管理) -
设置对象的字段值
f.set(Object,Object)
, 与get类似
调用方法
Method getMethod(name, Class...)
:获取某个public的Method(包括父类)Method getDeclaredMethod(name, Class...)
:获取当前类的某个Method(不包括父类)Method[] getMethods()
:获取所有public的Method(包括父类)Method[] getDeclaredMethods()
:获取当前类的所有Method(不包括父类)
Method对象方法
getName()
:返回方法名称,例如:“getScore”;getReturnType()
:返回方法返回值类型,也是一个Class实例,例如:String.class;getParameterTypes()
:返回方法的参数类型,是一个Class数组,例如:{String.class, int.class};getModifiers()
:返回方法的修饰符,它是一个int,不同的bit表示不同的含义。invoke(Object, ...args)
: 使用参数调用对象的该方法- 静态方法调用
invoke(null, ...args)
- 调用非public方法:
Method.setAccessible(true)
先开放权限
多态
使用反射调用方法时,仍然遵循多态原则:即总是调用实际类型的覆写方法(如果存在)
调用构造方法
getConstructor(Class...)
:获取某个public的ConstructorgetDeclaredConstructor(Class...)
:获取某个ConstructorgetConstructors()
:获取所有public的ConstructorgetDeclaredConstructors()
:获取所有Constructor- 注意:
Constructor
总是当前类定义的构造方法, 和父类无关, 因此不存在多态的问题 - 调用非public的
Constructor
时,必须首先通过setAccessible(true)
设置允许访问, 可能会失败
获取继承关系
-
获取父类
Class
Class i = Integer.class; Class n = i.getSuperclass(); Class o = n.getSuperclass(); o.getSuperclass(); // null
-
获取
interface
Class[] is = Integer.class.getInterfaces();
-
注意:
getInterfaces()
只返回当前类直接实现的接口类型,并不包括其父类实现的接口类型 -
对所有
interface
的Class
调用getSuperclass()
返回的是null
,获取接口的父接口要用getInterfaces()
-
如果一个类没有实现任何
interface
,那么getInterfaces()
返回空数组 -
判断继承关系
Integer.class.isAssignableFrom(Number.class); // false Number.class.isAssignableFrom(Integer.class); // true
动态代理
在运行期动态创建一个interface实例
- 定义一个
InvocationHandler
实例,它负责实现接口的方法调用; - 通过
Proxy.newProxyInstance()
创建interface实例,它需要3个参数:- 使用的
ClassLoader
,通常就是接口类的ClassLoader
; - 需要实现的接口数组,至少需要传入一个接口进去;
- 用来处理接口方法调用的
InvocationHandler
实例。
- 使用的
- 将返回的
Object
强制转型为接口。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method);
if (method.getName().equals("morning")) {
System.out.println("Good morning, " + args[0]);
}
return null;
}
};
Hello hello = (Hello) Proxy.newProxyInstance(
Hello.class.getClassLoader(), // 传入ClassLoader
new Class[] { Hello.class }, // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
hello.morning("Bob");
}
}
interface Hello {
void morning(String name);
}