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

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"。

):

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 反射