java反射
动态代理
特点:无侵入式的给代码增加额外的功能
为什么需要动态代理?调用者->代理->接口->对象
代理是什么样的?代理的方法就是对象被代理的方法
如何保证代理?接口对象和代理需要实现同一个接口,接口中的方法就是对象被代理的所有方法
QQSpeed-demo
接口
public interface Car {
// 代理和对象都要实现run方法,对象所有需要被代理的方法都要在接口中定义
public void run(String roadName);
}
对象类
public class Porsche implements Car {
private String carName;
public Porsche() {}
public Porsche(String carName) { this.carName = carName; }
// Porsche只保留run方法
@Override
public void run(String roadName) {
System.out.println(this.carName + " is running on the " + roadName);
}
public String getCarName() { return carName; }
public void setCarName(String carName) { this.carName = carName; }
public String toString() { return "porsche{carName = " + carName + "}"; }
}
代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
// 创建代理
public static Car creatProxy(Porsche porsche){
Car car = (Car) Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(), // 类加载器
new Class[]{Car.class}, // 接口
new InvocationHandler() { // 代理要做的事情
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("run".equals(method.getName())){
// 加入赛前的准备机制
System.out.println("Reno joins the game room");
System.out.println("Ferrari joins the game room");
System.out.println("Maserati joins the game room");
System.out.println("All vehicles are ready");
System.out.println("Countdown three two one");
System.out.println("QQSpeed start");
// 调用Porsche保留的run方法
method.invoke(porsche,args);
// 加入赛后庆祝机制
System.out.println(porsche.getCarName() + " win the first!!!");
}
return null;
}
}
);
return car;
}
}
测试类
public class testRun {
public static void main(String[] args) {
// 创建对象 porsche-911
Porsche porsche = new Porsche("porsche-911");
// 创建porsche-911的代理
Car proxy = ProxyUtil.creatProxy(porsche);
// 通过代理执行porsche-911的方法,以及代理的一些职能
proxy.run("Mountain Haruna");
}
}
运行结果
Reno joins the game room
Ferrari joins the game room
Maserati joins the game room
All vehicles are ready
Countdown three two one
QQSpeed start
porsche-911 is running on the Mountain Haruna
porsche-911 win the first!!!
反射
什么是反射?反射允许对封装的字段、方法和构造函数的信息进行编程访问
idea的代码提示就是反射实现的
第一步、获取到类
从.class
字节码文件而不是.java
文件
获取class对象的三种方式
// 1.源代码阶段 代码并未加载到内存当中,依旧是硬盘中的操作
Class.forName("全类名");
// 2.加载阶段 将.class文件加载到内存中
类名.class
// 3.运行阶段
对象.getClass()
demo
被获取类
package stepOne;
// 雷诺
public class Reno {
// 直线最高时速
private String straightTopSpeed;
// 0 - 180km/h加速用时
private String AccelerationTime0f180;
// 车身重量 1680 千克
private String BodyWeight;
// 高速转弯半径
private String HighSpeedTurningRadius;
public Reno() {
}
public Reno(String straightTopSpeed, String AccelerationTime0f180, String BodyWeight, String HighSpeedTurningRadius) {
this.straightTopSpeed = straightTopSpeed;
this.AccelerationTime0f180 = AccelerationTime0f180;
this.BodyWeight = BodyWeight;
this.HighSpeedTurningRadius = HighSpeedTurningRadius;
}
public String getStraightTopSpeed() { return straightTopSpeed; }
public void setStraightTopSpeed(String straightTopSpeed) { this.straightTopSpeed = straightTopSpeed; }
public String getAccelerationTime0f180() { return AccelerationTime0f180; }
public void setAccelerationTime0f180(String AccelerationTime0f180) { this.AccelerationTime0f180 = AccelerationTime0f180; }
public String getBodyWeight() { return BodyWeight; }
public void setBodyWeight(String BodyWeight) { this.BodyWeight = BodyWeight; }
public String getHighSpeedTurningRadius() { return HighSpeedTurningRadius; }
public void setHighSpeedTurningRadius(String HighSpeedTurningRadius) { this.HighSpeedTurningRadius = HighSpeedTurningRadius; }
public String toString() {
return "Reno{straightTopSpeed = " + straightTopSpeed + ", AccelerationTime0f180 = " + AccelerationTime0f180 + ", BodyWeight = " + BodyWeight + ", HighSpeedTurningRadius = " + HighSpeedTurningRadius + "}";
}
}
测试类
package stepOne;
public class getClass {
public static void main(String[] args) throws ClassNotFoundException {
// 1.源代码阶段 代码并未加载到内存当中,依旧是硬盘中的操作 Class.forName("全类名") 最为常用
Class clazz1 = Class.forName("stepOne.Reno");
// 2.加载阶段 将.class文件加载到内存中 类名.class 一般当参数进行传递
Class clazz2 = Reno.class;
// 3.运行阶段 对象.getClass() 只有拥有这个类的对象时才可以使用
Reno reno = new Reno();
Class clazz3 = reno.getClass();
System.out.println(clazz1==clazz2&&clazz2==clazz3);
}
}
第二步、使用类的信息
从.class
文件获取类的字段、方法、构造函数
初始化类User
package stepTwo;
import java.io.IOException;
public class User {
private String name;
private int age;
public String gender;
public String sleep(){
return "im sleeping";
}
private void eat(String food) throws IOException, NullPointerException, ClassCastException {
System.out.println("eat" + food);
}
public User() {
}
public User(String name){
this.name = name;
}
protected User(int age){
this.age = age;
}
private User(String name, int age){
this.name = name;
this.age = age;
}
public User(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
* @return gender
*/
public String getGender() {
return gender;
}
/**
* 设置
* @param gender
*/
public void setGender(String gender) {
this.gender = gender;
}
public String toString() {
return "User{name = " + name + ", age = " + age + ", gender = " + gender + "}";
}
}
获取构造函数
Constructor
类用来描述构造函数,Constructor
类的对象就是构造函数的对象
package stepTwo;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
public class getConstructor {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class clazz = Class.forName("stepTwo.User");
// 获取构造函数的四种方式
// 1.返回单个公共构造方法对象
Constructor con = clazz.getConstructor(String.class);
System.out.println(con);
// 2.返回所有公共构造方法对象的数组
Constructor[] cons = clazz.getConstructors();
for(Constructor c : cons) {
System.out.println(c);
}
// 3.返回单个构造方法对象
Constructor dcon = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(dcon);
// 4.返回所有构造方法对象的数组
Constructor[] dcons = clazz.getDeclaredConstructors();
for(Constructor dc : dcons){
System.out.println(dc);
}
// 获取构造函数详细信息,以方法3为例
// 1.获取参数个数
int mod = dcon.getModifiers();
System.out.println(mod);
// 2.获取参数
Parameter[] parameters = dcon.getParameters();
for(Parameter p : parameters){
System.out.println(p);
}
// 3.创建对象
// 暴力反射:临时取消权限校验
dcon.setAccessible(true);
User user = (User) dcon.newInstance("zhangsan", 25);
System.out.println(user);
}
}
获取成员变量
Field
类用来描述成员变量,Field
类的对象就是成员变量的对象
package stepTwo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
public class getField {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class clazz = Class.forName("stepTwo.User");
// 获取成员变量的四种方式
// 1.返回单个公共成员变量对象
Field gender = clazz.getField("gender");
System.out.println(gender);
// 2.返回所有公共成员变量对象的数组
Field[] fields = clazz.getFields();
for(Field f : fields) {
System.out.println(f);
}
// 3.返回单个成员变量对象
Field age = clazz.getDeclaredField("age");
System.out.println(age);
// 4.返回所有成员变量对象的数组
Field[] dfields = clazz.getDeclaredFields();
for(Field df : dfields){
System.out.println(df);
}
// 获取成员变量详细信息,以方法3为例
// 1.获取权限修饰符
int modi = age.getModifiers();
System.out.println(modi);
// 2.获取成员变量名
String n = age.getName();
System.out.println(n);
// 3.获取成员变量数据类型
Class type = age.getType();
System.out.println(type);
// 4.获取成员变量记录的值
User user = new User("zhangsan", 25, "♂");
age.setAccessible(true);
int value = (int) age.get(user);
System.out.println(value);
// 5.修改对象的成员变量值
age.set(user, 22);
System.out.println(user);
}
}
获取成员方法
Method
类用来描述成员方法,Method
类的对象就是成员方法的对象
package stepTwo;
import java.lang.reflect.*;
public class getMethod {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = Class.forName("stepTwo.User");
// 获取成员变量的四种方式
// 1.返回单个公共成员方法对象
Method sleep = clazz.getMethod("sleep", null);
System.out.println(sleep);
// 2.返回所有公共成员方法对象的数组(包含父类中所有的公共方法)
Method[] methods = clazz.getMethods();
for(Method m : methods) {
System.out.println(m);
}
// 3.返回单个成员方法对象
Method eat = clazz.getDeclaredMethod("eat", String.class);
System.out.println(eat);
// 4.返回所有成员方法对象的数组(不包含父类中的方法,但包含本类中的所有方法,包括私有方法)
Method[] dmethods = clazz.getDeclaredMethods();
for(Method dm : dmethods){
System.out.println(dm);
}
// 获取成员方法详细信息,以方法3为例
// 1.获取权限修饰符
int modi = eat.getModifiers();
System.out.println(modi);
// 2.获取成员方法名
String n = eat.getName();
System.out.println(n);
// 3.获取成员方法形参
Parameter[] parameters = eat.getParameters();
for(Parameter parameter : parameters){
System.out.println(parameter);
}
// 4.获取成员方法抛出的异常
Class[] exceptionTypes = eat.getExceptionTypes();
for(Class exceptionType : exceptionTypes){
System.out.println(exceptionType);
}
// 5.运行方法
User u = new User();
eat.setAccessible(true);
eat.invoke(u, " potato floss");
// 6.获取方法运行结果
String result = (String) sleep.invoke(u);
System.out.println(result);
}
}