反射
类的加载:
当程序要使用某个类时,如果该类还未被加载到内存中,
则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
1、加载:
就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象。
2、连接:
验证 : 是否有正确的内部结构,并和其他类协调一致
准备 : 负责为类的静态成员分配内存,并设置默认初始化值
解析: 把类中的符号引用转换为直接引用
3、初始化:
通过构造方法
加载时机:
1、创建类的实例
2、访问类的静态变量,或者为静态变量赋值
3、调用类的静态方法
4、使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5、初始化某个类的子类
6、直接使用java.exe命令来运行某个主类
类加载器:
负责将.class文件加载到内在中,并为之生成对应的Class对象
分类:
Bootstrap ClassLoader 根类加载器
Extension ClassLoader 扩展类加载器
Sysetm ClassLoader 系统类加载器
作用:
Bootstrap ClassLoader( 根类加载器)
也被称为引导类加载器,负责Java核心类的加载
比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader (扩展类加载器)
负责JRE的扩展目录中jar包的加载。
在JDK中JRE的lib目录下ext目录
Sysetm ClassLoader (系统类加载器)
负责在JVM启动时加载来自java命令的class文件,
以及classpath环境变量所指定的jar包和类路径
反射:
就是在运行状态中的一种动态调用方法或者属性的一种机制
(即获取字节码文件对象,然后剖析该类中存在哪些构造方法,哪些成员变量,哪些成员方法)
获取class文件对象的三种方式:
1、Object类的getClass()方法
2、静态属性class
3、Class类中静态方法forName()
例:
一、
public class test1 {
public static void main(String[] args) {
Student student = new Student(); s
//方式1 通过该方法,获取该类对应的字节码文件对象
Class aClass = student.getClass();
Class aClass2 = student.getClass();
System.out.println(aClass == aClass2); //true
Student student1 = new Student();
Class aClass3 = student1.getClass();
System.out.println(aClass2 == aClass3);//true
System.out.println(student == student1);//false
}
}
class Student {
}
二、
public class test2 {
public static void main(String[] args) {
//方式2 通过一个静态属性 class
Class studentClass = Student.class;
Class studentClass2 = Student.class;
Class studentClass3 = Student.class;
System.out.println(studentClass==studentClass2);
System.out.println(studentClass2 == studentClass3);
}
}
三、
public class test3 {
public static void main(String[] args) throws ClassNotFoundException {
//通过Class类中静态方法forName()
Class aClass = Class.forName("com.lian.cn.Student");
Class aClass2 = Class.forName("com.lian.cnStudent");
System.out.println(aClass==aClass2);
}
}
反射常见方法
获取构造方法:
1、获取所有构造方法
public Constructor<?>[] getConstructors() 获取所有的构造方法不包含私有的
public Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法 包括私有的
2、获取单个构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes) 获取单个的构造方法 不包含私有的
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取单个的构造方
法包含私有的
获取成员变量:
1、获取所有成员变量
public Field[] getFields() 获取所有的成员变量包含从父类继承过来的
public Field[] getDeclaredFields() 获取所有的成员变量 包含私有的 也包含从父类继承过来的成员变量
2、获取单个成员变量
public Field getField(String name)
public Field getDeclaredField(String name)
获取成员方法:
1、获取所有成员方法
public Method[] getMethods() //获取所有的公共的成员方法不包含私有的 包含从父类继承过来的过来的公共方法
public Method[] getDeclaredMethods()//获取自己的所有成员方法 包含私有的
2、获取单个成员方法
//参数1: 方法名称 参数2:方法行参的class 对象
public Method getMethod(String name,Class<?>... parameterTypes) //获取单个的方法 不包含私有的
public Method getDeclaredMethod(String name,Class<?>... parameterTypes) 获取单个方法包括私有的
属性设置:
public void setProperty(Object obj, String propertyName, Object value){},
此方法可将obj对象中名为propertyName的属性的值设置为value。
动态代理:
代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。
动态代理其实就是通过反射来生成一个代理
动态代理实现:
在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,
通过使用这个类和接口就可以生成动态代理对象。
//Proxy类中的方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
-loader: 类加载器
-interfaces: 接口对应的一个Class数组
-InvocationHandler: 这个其实就是要代理对象所做的事情的一个类的封装
public Object invoke(Object proxy, Method method, Object[] args)
- Object proxy: 代理对象
- Method method:就是UserDaoImpl这个类中的方法对应的实例对象
- Object[] args:就是每一个方法上需要传递的参数
例:
public class MyTest {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
UserDao proxy = GetProxyUtils.getProxy(userDao);
proxy.add();
System.out.println("----------------");
proxy.delete();
System.out.println("----------------");
proxy.query();
System.out.println("----------------");
proxy.update();
}
}
public class GetProxyUtils {
public static UserDao getProxy(UserDao dao) {
UserDao obj = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), new InvocationHandler() {
// proxy代理对象、method被代理类中方法的对象、args 方法中的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//权限校验
System.out.println("权限的校验");
Object invoke = method.invoke(dao);
System.out.println("记录日志");
return invoke;
}
});
return obj;//返回代理对象
}
}
public interface UserDao {
public abstract void add();
public abstract void delete();
public abstract void update();
public abstract void query();
}
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("增加了一条数据");
}
@Override
public void delete() {
System.out.println("删除了一条数据");
}
@Override
public void update() {
System.out.println("修改了一条数据");
}
@Override
public void query() {
System.out.println("查询一条数据");
}
}
public class UserDaoSon extends UserDaoImpl{
@Override
public void add() {
System.out.println("校验用户权限的代码");
System.out.println("增加了一条数据");
System.out.println("记录日志");
}
@Override
public void delete() {
System.out.println("校验用户权限的代码");
System.out.println("删除了一条数据");
System.out.println("记录日志");
}
@Override
public void update() {
System.out.println("校验用户权限的代码");
System.out.println("修改了一条数据");
System.out.println("记录日志");
}
@Override
public void query() {
System.out.println("校验用户权限的代码");
System.out.println("查询一条数据");
System.out.println("记录日志");
}
}
枚举
枚举:
定义枚举类要用关键字enum
所有枚举类都是Enum的子类
枚举类的第一行上必须是枚举项
格式:
- public enum 枚举名 {
- 枚举项1 , 枚举项2 , 枚举项3 .....
- }
常见方法:
int ordinal() 返回枚举项的序号
int compareTo(E o) 比较两个枚举项的 返回的是两个枚举项序号的 差值
String name() 获取枚举项的名称
String toString() 获取枚举项的名称
values() 获取所有的枚举项
<T> T valueOf(Class<T> type,String name)
用来获取指定的枚举项
参数1:枚举类对应的字节码对象 参数2 枚举项的名称
例:
public class MyTest {
public static void main(String[] args) {
Direction front = Direction.FRONT;
Direction after = Direction.AFTER;
Direction left = Direction.LEFT;
Direction right = Direction.RIGHT;
System.out.println(front.toString());
System.out.println(after);
System.out.println(left);
System.out.println(right);
}
}
public enum Direction {
FRONT("前"), AFTER("后"), LEFT("后"),RIGHT("右");
//下面如果有代码,; 分号不要省略,每个枚举项,用逗号隔开
private Direction(String name){}
}