您的位置:首页 > 编程语言 > Java开发

Java_反射(Class文件对象 / 反射 / 动态代理)

2017-08-23 20:17 603 查看

Java_反射(Class文件对象 / 反射 / 动态代理)

本文由 Luzhuo 编写,转发请保留该信息.

原文:
http://blog.csdn.net/Rozol/article/details/77511333


反射: 在运行状态时, 能够获取任意一个类的所有属性和方法; 能够调用任意一个对象的所有属性和方法.

反射性能较低, 一般情况下不考虑用反射.

Proxy 动态代理: 用来修改已经具有的对象的方法, 控制方法是否执行, 或在方法执行之前和执行之后做一些额外的操作

Bean类

public class Bean {
/**
* 公有属性
*/
public int number = 10;
/**
* 私有属性
*/
private String name = Bean.class.getSimpleName();
/**
* 静态属性
*/
public static int max = Integer.MAX_VALUE;
/**
* 常量属性
*/
protected static final int min = Integer.MIN_VALUE;

/**
* 无参构造
*/
public Bean(){}

/**
* 有参构造
* @param numbder
*/
public Bean(int number){
this.number = number;
}

/**
* 私有构造
* @param number
* @param name
*/
private Bean(int number, String name){
this.number = number;
this.name = name;
}

protected Bean(int number, String name, int max){
this.number = number;
this.name = name;
Bean.max = max;
}

/**
* 公有方法
* @param number
*/
public void setNumber(int number){
this.number = number;
}

public int getNumber(){
return this.number;
}

/**
* 私有方法
*/
private void setName(String name){
this.name = name;
}

private String getName(){
return this.name;
}

/**
* 静态方法
* @param max
*/
public static void setMax(int max){
Bean.max = max;
}

public static int getMax(){
return Bean.max;
}

/**
* protected方法
* @param min
* @return
*/
protected int getMin(){
return Bean.min;
}

@Override
public String toString() {
return "Bean [number=" + number + ", name=" + name + ", max=" + Bean.max + ", min =" + Bean.min + "]";
}
}


@Deprecated
public class SubBean extends Bean implements Serializable{

/**
* 调用父类方法, 并抛出一个异常
* @return
* @throws Exception
*/
public int getSuperNumber(int number) throws Exception{
return super.getNumber();
}
}


Class文件对象

在使用反射之前, 首先要获取Class类的文件对象, 然后才能通过反射去获取类的方法, 之后才能调用该方法.

/**
* 获取Class文件对象的几种方式
* @author Luzhuo
*/
public class GetClass {
public static void main(String[] args) throws ClassNotFoundException {

// 方式1: 通过对象获得
GetClass getClass = new GetClass();
Class<? extends GetClass> class1 = getClass.getClass();

// 方式2: 通过数据类型的一个静态calss属性
Class<GetClass> class2 = GetClass.class;

// 方式3: 通过全类名获得
Class<?> class3 = Class.forName("反射.reflect.GetClass");

// 方式4: 通过 类加载器 加载
Class<?> class4 = GetClass.class.getClassLoader().loadClass("反射.reflect.GetClass");

System.out.println(class1 == class2 && class2 == class3 && class3 == class4); // true
}
}


反射

反射: 在运行状态时, 能够获取任意一个类的所有属性和方法; 能够调用任意一个对象的所有属性和方法.

/**
* 反射: 在运行状态时, 能够获取任意一个类的所有属性和方法;
*                      能够调用任意一个对象的所有属性和方法.
*
* 反射性能较低, 一般情况下不考虑用反射.
* @author Luzhuo
*/
public class reflect {
public static void main(String[] args) throws Exception {
// 创建对象(构造方法)
constructor();

// 属性
field();

// 方法
method();

// 案例: 通过反射调用已存在对象的方法
callOldInstance();
}

/**
* 对象的创建(构造方法)
* 访问 private / protected 修饰的构造方法时, 需要取消语法检查
*/
private static void constructor() throws Exception {

// 方式1: Class文件对象
Class<?> clazz = Bean.class;
Bean instance1 = (Bean) clazz.newInstance();

// 方式2: Class文件对象的构造方法
Constructor<?>[] cons = clazz.getConstructors(); // 所有公共构造方法
Constructor<?>[] allcons = clazz.getDeclaredConstructors(); // 所有构造方法(public / private / protected)
Constructor<?> con = clazz.getConstructor(int.class);  // 获取指定公有构造方法
Constructor<?> decCon = clazz.getDeclaredConstructor(int.class, String.class); // 获取指定私有构造方法

decCon.setAccessible(true); // 取消Java语言访问检查(获取 private / protected 构造时使用)

Bean instance2 = (Bean) cons[0].newInstance(200);
Bean instance3 = (Bean) cons[1].newInstance();

System.out.println(instance1 == instance2 || instance2 == instance3); // false

// 访问 private / protected 修饰的构造方法时, 需要取消语法检查
}

/**
* 属性
* 访问 private / protected / static final 修饰的属性时, 需要取消语法检查
* 修改 private / protected 修饰的属性时, 需要取消语法检查, 不能修改 static final 修饰的属性
* 能获取本类所有字段, 但不能获取父类除public外的所有字段
*/
private static void field() throws Exception {
Class<?> clazz = Bean.class;

// 获取成员变量
Field[] fields = clazz.getFields(); // 所有公共字段(public)(含父类)
Field[] allfields = clazz.getDeclaredFields(); // 本类所有字段(public / private / protected)

Object obj = clazz.getConstructor().newInstance(); // 创建对象

// 使用成员变量
// 公有属性
Field number = clazz.getField("number"); // 获取指定公有字段(public)
System.out.println("number: " + number.getInt(obj)); // 获取字段的值

number.set(obj, 1000); // 设置字段的值
System.out.println(obj.toString());

// 私有属性
Field name = clazz.getDeclaredField("name"); // 获取指定字段(...)
name.setAccessible(true);
System.out.println("name: " + name.get(obj));

name.set(obj, "set name");
System.out.println(obj.toString());

// 静态属性
Field max = clazz.getField("max");
System.out.println("max: " + max.getInt(obj));

max.set(obj, 123);
System.out.println(obj.toString());

// 常量属性(protected)
Field min = clazz.getDeclaredField("min");
min.setAccessible(true);
System.out.println("min: " + min.getInt(obj));

// min.set(obj, 321); // static final 修饰的属性不允许修改
System.out.println(obj.toString());

// 访问 private / protected / static final 修饰的属性时, 需要取消语法检查
// 修改 private / protected 修饰的属性时, 需要取消语法检查, 不能修改 static final 修饰的属性
// 能获取本类所有字段, 但不能获取父类除public外的所有字段
}

/**
* 方法
* 能获取该类的所有方法, 但是不能获取父类除public外的所有方法
* 访问 private / protected 修饰的方法时, 需要取消语法检查
*/
private static void method() throws Exception{
Class<?> clazz = Bean.class;
Method[] allmethods = clazz.getMethods(); // 获取所有公共方法(public / public final / public static)(含父类)
Method[] methods = clazz.getDeclaredMethods(); // 获取本类所有方法(public / private / public static / private / protected ...)

Object obj = clazz.getConstructor().newInstance(); // 创建对象

// 方法
// 公有
Method setNumber = clazz.getMethod("setNumber", int.class); // 获取指定公共方法(public)
setNumber.invoke(obj, 1000); // 调用方法

Method getNumber = clazz.getMethod("getNumber");
int number = (int) getNumber.invoke(obj);
System.out.println("getNumber: " + number);

// 私有
Method setName = clazz.getDeclaredMethod("setName", String.class); // 获取指定方法(...)
setName.setAccessible(true);
setName.invoke(obj, "abc");

Method getName = clazz.getDeclaredMethod("getName");
getName.setAccessible(true);
String name = (String) getName.invoke(obj);
System.out.println("getName: " + name);

// 静态
Method setMax = clazz.getMethod("setMax", int.class);
setMax.invoke(obj, 123); // 调用方法

Method getMax = clazz.getMethod("getMax");
int max = (int) getMax.invoke(obj);
System.out.println("getMax: " + max);

// protected
Method getMin = clazz.getDeclaredMethod("getMin");
getMin.setAccessible(true);
int min = (int) getMin.invoke(obj);
System.out.println("getMin: " + min);

// 能获取该类的所有方法, 但是不能获取父类除public外的所有方法
// 访问 private / protected 修饰的方法时, 需要取消语法检查
}

/**
* 通过反射调用已存在对象的方法
*/
private static void callOldInstance() throws Exception {
Bean bean = new Bean();
Class<? extends Bean> clazz = bean.getClass();

// 通过反射调用私有方法
Method getName = clazz.getDeclaredMethod("getName");
getName.setAccessible(true);
String name = (String) getName.invoke(bean);
System.out.println("getName: " + name);

bean.number = 100000000;
// 通过反射调用已存在对象的公有方法
Method getNumber = clazz.getMethod("getNumber");
int number = (int) getNumber.invoke(bean);
System.out.println("getNumber: " + number);
}
}


反射补充

反射相关的一些补充

/**
* 反射的一些补充
* @author Luzhuo
*/
public class Other {
public static void main(String[] args) throws Exception {
Class<?> clazz = SubBean.class;

// 包名
String packageName = clazz.getPackage().getName();
System.out.println("包名: " + packageName); // 包名: 反射.Class

// 完整类名
String className = clazz.getName();
System.out.println("完整类名: " + className); // 完整类名: 反射.Class.Clazz

// 类名
String classSimpleName = clazz.getSimpleName();
System.out.println("类名: " + classSimpleName); // 类名: Clazz

// 获取接口
Class<?>[] interfaces = clazz.getInterfaces();
System.out.println("Interfaces: " + Arrays.toString(interfaces));

// 获取父类
Class<?> superClass = clazz.getSuperclass();
System.out.println("SuperClass: " + superClass);

// 获取异常
Method getSuperNumber = clazz.getMethod("getSuperNumber", int.class);
Class<?>[] exceptions = getSuperNumber.getExceptionTypes();
System.out.println("Exceptions: " + Arrays.toString(exceptions));

// 获取权限修饰符
int mod = getSuperNumber.getModifiers();
System.out.println("Mod: " + Modifier.toString(mod));

// 获取返回值类型
Class<?> returnType = getSuperNumber.getReturnType();
System.out.println("Return Type: " + returnType);

// 获取参数列表
Class<?>[] parameterTypes = getSuperNumber.getParameterTypes();
System.out.println("ParameterTypes: " + Arrays.toString(parameterTypes));

// 方法名
System.out.println("GetSupperNumber Name: " + getSuperNumber.getName());

// 获取属性类型
Field number = clazz.getField("number");
Class<?> type = number.getType();
System.out.println("Field Type: " + type);

// 获取类的注解
// 其他获取注解的方法, 详见 注解 http://blog.csdn.net/rozol/article/details/77758192 文章
Annotation[] classAnnotations = clazz.getAnnotations();
System.out.println("ClassAnnotations: " + Arrays.toString(classAnnotations));
}
}


动态代理

Proxy 动态代理: 用来修改已经具有的对象的方法, 控制方法是否执行, 或在方法执行之前和执行之后做一些额外的操作

jdk动态代理是由Java内部的反射机制来实现的

jdk动态代理需要基于同一的 接口

/**
* Proxy 动态代理
* 用来修改已经具有的对象的方法, 控制方法是否执行, 或在方法执行之前和执行之后做一些额外的操作
* jdk动态代理是由Java内部的反射机制来实现的
* jdk动态代理需要基于同一的 接口
* @author Luzhuo
*/
public class ProxyTest {
public static void main(String[] args) {
User userProxy = initAccess(new ProxyTest.UserImpl());

System.out.println(userProxy.getName());
System.out.println(userProxy.getAge());
}

public static User initAccess(final User user){
User userProxy = (User)Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), new InvocationHandler() {

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

if ("getName".equals(method.getName())){
System.out.println("getName() 调用之前");
Object result = method.invoke(user, args);
System.out.println("getName() 调用之后");
return result;
}

return method.invoke(user, args);
}
});
return userProxy;
}

public static interface User {
public String getName();
public int getAge();
}

public static class UserImpl implements User {
@Override
public String getName() {
System.out.println("UserServiceImpl - getName");
return "name";
}

@Override
public int getAge() {
System.out.println("UserServiceImpl - getAge");
return 12;
}
}
}


输出结果:

getName() 调用之前
UserServiceImpl - getName
getName() 调用之后
name
UserServiceImpl - getAge
12
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 反射
相关文章推荐