JAVA反射汇总和示例
2016-02-04 11:42
543 查看
一.反射的概念:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。 对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。另一种解释,反射就是把Java类中的各种成分映射成相应的java类。
字节码文件(class文件):java文件经过编译器预处理后生成的二进制的文件就是字节码文件。
2.获取字节码文件对应的class类型的对象的三种方法:
(1)源文件阶段(.java):
Class c = class.forName(“包名.类名”);
//作用:读取配置文件
例子(通过读取配置文件创建class类的方法):
1).创建一个配置文件(例如配置文件名为“config.properties”),配置文件中添加需要调用的”全包名.类名”(如:com.reflect.类名)。
2).类名的代码如下:
class Cat implements Animal{
public void eat(){
System.out.println(“吃鱼”);
}
}
3).类名的父类(接口)代码,使用父类(接口)功能的调用类:
interface Animal{
public void eat();
}
class Using{
Public void use(Animal a){ //传入动物对象
A.eat();
}
}
4).使用配置文件获取字节码的代码:
public class ReflectTest{
/**
* 动物吃肉的案例
* 分别有动物(Animal)猫(CAt)狗(Dog) * @throws Exception
*/
public static void main(String[]args)throws Exception{
BufferedReader bufr = new BufferedReader(new FileReader("config.properties")); //创建输入流对象,关联配置文件
Class c = Class.forName(bufr.readLiine());
//读取配置文件一行内容,获取该类的字节码对象
Animal a = (Animal)c.newInstance();
//通过字节码对象创建实例对象,同时利用多态
Using u = new Using();
U.use(a);
}
}
(2)java文件编译成class文件后:
Class c = 类名.class;
//作用:当作静态方法的锁对象
(3)创建实例(对象)后:
Object obj = new Object();
Class c = obj(对象名).getClass();//利用的是Object的getClass方法。
//作用:判断是否是同个字节码文件
二.反射常用的:Constructor、Field、Method
1.Constructor:Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
例子:Constructor [] constructors= Class.forName("java.lang.Integer").getConstructors();
得到某一个构造方法:
例子: Constructor constructor = Class.forName(“java.lang.Integer”).getConstructor(String.class);
//获得方法时要用到类型,(构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值。)
创建实例对象:
通常方式:Integer in= new Integer("5"));
反射方式:
Constructor constructor = Class.forName(“java.lang.Integer”).getConstructor(String.class);
nteger in = constructor.newInstance("5");
//调用获得的方法时要用到上面相同类型的实例对象
2.Field:提供有关类或接口的单个字段的信息,可以代表一个成员变量。
Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值
例子1(将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
):
例子2(修改字段的值):
3.Method:Method类代表某个类中的一个成员方法
Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法,调用invoke(Object, Object...)可以调用该方法,Class.getMethod("eat") invoke(obj) Class.getMethod("eat",int.class) invoke(obj,10)
例子1: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法:
String str = “sdfsfsg”;
通常方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1));
例子2:
例子3(将obj对象中名为propertyName的属性的值设置为value):
三.数组的反射的特征:
1.具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。
2.代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。(Object[] 与String[]没有父子关系,Object与String有父子关系,所以new Object[]{“aaa”,”bb”}不能强制转换成new String[]{“aaa”,”bb”};,Object x = “abc”能强制转换成String x = “abc”。
)
3.基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
四:利用反射避开泛型的限制的实例:
五:动态代理概述
* 代理:本来应该自己做的事情,请了别人来做,被请的人就是代理对象。
* 举例:春节回家买票让人代买
* 动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理
* 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象
* public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
* 最终会调用InvocationHandler的方法
* InvocationHandler Object invoke(Object proxy,Method method,Object[] args)
以下为接口的代理例子:
字节码文件(class文件):java文件经过编译器预处理后生成的二进制的文件就是字节码文件。
2.获取字节码文件对应的class类型的对象的三种方法:
(1)源文件阶段(.java):
Class c = class.forName(“包名.类名”);
//作用:读取配置文件
例子(通过读取配置文件创建class类的方法):
1).创建一个配置文件(例如配置文件名为“config.properties”),配置文件中添加需要调用的”全包名.类名”(如:com.reflect.类名)。
2).类名的代码如下:
class Cat implements Animal{
public void eat(){
System.out.println(“吃鱼”);
}
}
3).类名的父类(接口)代码,使用父类(接口)功能的调用类:
interface Animal{
public void eat();
}
class Using{
Public void use(Animal a){ //传入动物对象
A.eat();
}
}
4).使用配置文件获取字节码的代码:
public class ReflectTest{
/**
* 动物吃肉的案例
* 分别有动物(Animal)猫(CAt)狗(Dog) * @throws Exception
*/
public static void main(String[]args)throws Exception{
BufferedReader bufr = new BufferedReader(new FileReader("config.properties")); //创建输入流对象,关联配置文件
Class c = Class.forName(bufr.readLiine());
//读取配置文件一行内容,获取该类的字节码对象
Animal a = (Animal)c.newInstance();
//通过字节码对象创建实例对象,同时利用多态
Using u = new Using();
U.use(a);
}
}
(2)java文件编译成class文件后:
Class c = 类名.class;
//作用:当作静态方法的锁对象
(3)创建实例(对象)后:
Object obj = new Object();
Class c = obj(对象名).getClass();//利用的是Object的getClass方法。
//作用:判断是否是同个字节码文件
二.反射常用的:Constructor、Field、Method
1.Constructor:Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
例子:Constructor [] constructors= Class.forName("java.lang.Integer").getConstructors();
得到某一个构造方法:
例子: Constructor constructor = Class.forName(“java.lang.Integer”).getConstructor(String.class);
//获得方法时要用到类型,(构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值。)
创建实例对象:
通常方式:Integer in= new Integer("5"));
反射方式:
Constructor constructor = Class.forName(“java.lang.Integer”).getConstructor(String.class);
nteger in = constructor.newInstance("5");
//调用获得的方法时要用到上面相同类型的实例对象
2.Field:提供有关类或接口的单个字段的信息,可以代表一个成员变量。
Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值
例子1(将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
):
class Xxx { String name="abc"; String email="abd"; int x = 5; } func(Object obj) { Field [] fields = obj.getClass().getDeclaredFields(); for(Field field : fields) { if(field.getType()==java.lang.String.class) { field.setAccesible(true); String original = (String)field.get(obj); field.set(obj,original.replaceAll("b","a"); } } }
例子2(修改字段的值):
import java.lang.reflect.Constructor; import java.lang.reflect.Field; public class FieldDemo { /** * Class.getField(String)方法可以获取类中的指定字段(可见的), * 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值, * 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值 * @throws Exception */ public static void main(String[] args) throws Exception { // TODO Auto-generated method stub Class clazz = Class.forName("Person"); //Person类和本类在同个包中 Constructor c = clazz.getConstructor(String.class,int.class); //获取有参构造 Person p = (Person) c.newInstance("张三",23); //通过有参构造创建对象 //Field f = clazz.getField("name"); //获取姓名字段 //f.set(p, "李四"); //修改姓名的值 Field f = clazz.getDeclaredField("name"); //暴力反射获取字段 f.setAccessible(true); //去除私有权限 f.set(p, "李四"); System.out.println(p); } } class Person{ private String name; private int age; public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
3.Method:Method类代表某个类中的一个成员方法
Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法,调用invoke(Object, Object...)可以调用该方法,Class.getMethod("eat") invoke(obj) Class.getMethod("eat",int.class) invoke(obj,10)
例子1: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法:
String str = “sdfsfsg”;
通常方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1));
例子2:
import java.lang.reflect.Constructor; import java.lang.reflect.Method; import com.heima.bean.Person; public class DemoMethod { /** * Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, * Class...)方法可以获取类中的指定方法,调用invoke(Object, * Object...)可以调用该方法,Class.getMethod("eat") invoke(obj) * Class.getMethod("eat",int.class) invoke(obj,10) * @throws Exception */ public static void main(String[] args) throws Exception { Class clazz = Class.forName("com.heima.bean.Person"); Constructor c = clazz.getConstructor(String.class,int.class); //获取有参构造 Person p = (Person) c.newInstance("张三",23); //通过有参构造创建对象 Method m = clazz.getMethod("eat"); //获取eat方法 m.invoke(p); Method m2 = clazz.getMethod("eat", int.class); //获取有参的eat方法 m2.invoke(p, 10); } }
例子3(将obj对象中名为propertyName的属性的值设置为value):
public class Test3 { /** * * A:案例演示 * public void setProperty(Object obj, String propertyName, Object value){}, * 此方法可将obj对象中名为propertyName的属性的值设置为value。 * @throws Exception */ public static void main(String[] args) throws Exception { Student s = new Student("张三", 23); System.out.println(s); Tool t = new Tool(); t.setProperty(s, "name", "李四"); System.out.println(s); } } class Student { private String name; private int age; public Student() { super(); } public Student(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } } import java.lang.reflect.Field; public class Tool { //此方法可将obj对象中名为propertyName的属性的值设置为value。 public void setProperty(Object obj, String propertyName, Object value) throws Exception { Class clazz = obj.getClass(); //获取字节码对象 Field f = clazz.getDeclaredField(propertyName); //暴力反射获取字段 f.setAccessible(true); //去除权限 f.set(obj, value); } }
三.数组的反射的特征:
1.具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。
2.代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。(Object[] 与String[]没有父子关系,Object与String有父子关系,所以new Object[]{“aaa”,”bb”}不能强制转换成new String[]{“aaa”,”bb”};,Object x = “abc”能强制转换成String x = “abc”。
)
3.基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
四:利用反射避开泛型的限制的实例:
import java.lang.reflect.Method; import java.util.ArrayList; public class Test { /** * @param args * ArrayList<Integer>的一个对象,在这个集合中添加一个字符串数据,如何实现呢? * 泛型只在编译期有效,在运行期会被擦除掉 * @throws Exception */ public static void main(String[] args) throws Exception { ArrayList<Integer> list = new ArrayList<>(); list.add(111); list.add(222); Class clazz = Class.forName("java.util.ArrayList"); //获取字节码对象 Method m = clazz.getMethod("add", Object.class); //获取add方法 m.invoke(list, "abc"); System.out.println(list); } }
五:动态代理概述
* 代理:本来应该自己做的事情,请了别人来做,被请的人就是代理对象。
* 举例:春节回家买票让人代买
* 动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理
* 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象
* public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
* 最终会调用InvocationHandler的方法
* InvocationHandler Object invoke(Object proxy,Method method,Object[] args)
以下为接口的代理例子:
public interface User { public void add(); public void delete(); } public class UserImp implements User { @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("日志记录"); } } import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** 接口的动态代理功能的类 */ public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("权限校验"); method.invoke(target, args); //执行被代理target对象的方法 System.out.println("日志记录"); return null; } } import java.lang.reflect.Proxy; public class Test { /** * @param args */ public static void main(String[] args) { UserImp ui = new UserImp(); ui.add(); ui.delete(); System.out.println("-------------------------------"); /* * public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, * InvocationHandler h) */ MyInvocationHandler m = new MyInvocationHandler(ui); User u = (User)Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(), m); u.add(); u.delete(); } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树