JAVA反射汇总和示例



一.反射的概念: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();
 }

}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值