Java基础--反射
2017-10-09 17:01
417 查看
一、反射:一个Java类中,包含成员变量、成员方法等信息。反射就是把类中的这些信息映射成一个个的类。
反射的基本使用:
获取类的字节码对象有三种方法:
类名.class
对象名.getClass()
Class.forName(类的全名)
Class对象提供了如下常用方法:
public Constructor getConstructor(Class<?>...parameterTypes)
public Method getMethod(String name, Class<?>...parameterTypes)
public Field getField(String name)
public Constructor getDeclaredConstructor(Class<?>...parameterTypes)
public Method getDeclaredMethod(String name, Class<?>...parameterTypes)
public Field getDeclaredField(String name)
举例:
Student类
反射测试类:
注:
参数中带有数组的,如方法“m6”,要将数组转换成一个对象。这是因为,jdk1.5及以上版本要兼容1.4。在1.4中,数组中的每个元素都对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,会出现参数数量错误。解决方法:
invoke(null, new Object[]{new String[]{"xxx", "xx"}});
或者
invoke(null, (Object)new String[]{"xxx", "xx"});
这样编译器会做特殊处理,编译时不会把参数当做数组看待。
二、内省:
WIKI上的解释:内省是指计算机程序在运行时(Run time)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查。
相对于内省,反射更进一步,是指计算机程序在运行时(Run time)可以访问、检查和修改它本身状态或行为的一种能力。
内省和反射的区别:
反射是在运行状态把Java类中的各种成分映射成相应的Java类,可以动态的获取所有的属性以及动态调用任意一个方法,强调的是运行状态。
内省机制是通过反射来实现的,BeanInfo用来暴露一个bean的属性、方法和事件,以后我们就可以操纵该JavaBean的属性了。
![](https://img-blog.csdn.net/20160422101525368)
在Java内省中,用到的基本就是上述几个类。通过BeanInfo这个类就可以获取到类中的方法和属性。
举例:
Person类
输出:
三、BeanUtils工具包是Apache开发的一套快速操作JavaBean get/set方法的API,需要commons-beanutils.jar, commons-logging.jar
注:BeanUtils可以进行类型的自动转换,但仅限基本类型
举例:
在原有Person类中加入private Date birthday;,以及get/set方法
BeanUtils可以将Map属性自动放到Bean中
注:原则是,Map的key必须要与Bean的属性一致
举例:
反射的基本使用:
获取类的字节码对象有三种方法:
类名.class
对象名.getClass()
Class.forName(类的全名)
Class对象提供了如下常用方法:
public Constructor getConstructor(Class<?>...parameterTypes)
public Method getMethod(String name, Class<?>...parameterTypes)
public Field getField(String name)
public Constructor getDeclaredConstructor(Class<?>...parameterTypes)
public Method getDeclaredMethod(String name, Class<?>...parameterTypes)
public Field getDeclaredField(String name)
举例:
Student类
public class Student { public String str = "hello"; private int age = 18; public static Date time; public Student() { } public Student(String name){ System.out.println("姓名:" + name); } public Student(String name, int age){ System.out.println(name + " " + age); } private Student(int age){ System.out.println("年龄:" + age); } public void m1(){ System.out.println("m1"); } public void m2(String name){ System.out.println("m2 " + name); } public String m3(String name, int age){ System.out.println("m3 " + name + " " + age); return "m3:OK"; } private void m4(int age){ System.out.println("m4 " + age); } public static void m5(){ System.out.println("m5"); } private static void m6(String[] str){ System.out.println(str.length); } }
反射测试类:
public class Reflect { public static void main(String[] args) throws Exception { Class cl = Class.forName("com.ztq.test.Student"); //获取Student类的字节码对象 4000 Student s = (Student) cl.newInstance(); //利用字节码对象cl,建立Student类的实例,调用的是默认构造方法 Constructor c1 = cl.getConstructor(String.class); //获取相应的构造方法(只能是public修饰的) c1.newInstance("Chris"); //创建新实例 Constructor c2 = cl.getDeclaredConstructor(int.class); //获取相应的构造方法(所有的,包括private修饰的) c2.setAccessible(true); c2.newInstance(22); Constructor[] c3 = cl.getDeclaredConstructors(); //获取所有构造方法(包括private) Method m1 = cl.getMethod("m1", null); //获取名为m1,参数为null的方法 m1.invoke(s, null); //调用该方法,其中s为该类的一个实例,null为该方法的参数 Method m2 = cl.getMethod("m2", String.class); m2.invoke(s, "Chris"); Method m3 = cl.getMethod("m3", String.class, int.class); String str = (String) m3.invoke(s, "Chris", 18); Method m4 = cl.getDeclaredMethod("m4", int.class); m4.setAccessible(true); m4.invoke(s, 20); Method m5 = cl.getMethod("m5", null); m5.invoke(s, null); // m5.invoke(null, null); 对于静态方法,对象可以为s,也可以为null Method m6 = cl.getDeclaredMethod("m6", String[].class); m6.setAccessible(true); m6.invoke(null, (Object)new String[]{"a", "b", "c"}); Field f1 = cl.getField("str"); f1.set(s, "hehe"); //更改类中的str字段 Field f2 = cl.getDeclaredField("age"); f2.setAccessible(true); f2.set(s, 30); Field f3 = cl.getField("time"); f3.set(null, new Date()); } }
注:
参数中带有数组的,如方法“m6”,要将数组转换成一个对象。这是因为,jdk1.5及以上版本要兼容1.4。在1.4中,数组中的每个元素都对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,会出现参数数量错误。解决方法:
invoke(null, new Object[]{new String[]{"xxx", "xx"}});
或者
invoke(null, (Object)new String[]{"xxx", "xx"});
这样编译器会做特殊处理,编译时不会把参数当做数组看待。
二、内省:
WIKI上的解释:内省是指计算机程序在运行时(Run time)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查。
相对于内省,反射更进一步,是指计算机程序在运行时(Run time)可以访问、检查和修改它本身状态或行为的一种能力。
内省和反射的区别:
反射是在运行状态把Java类中的各种成分映射成相应的Java类,可以动态的获取所有的属性以及动态调用任意一个方法,强调的是运行状态。
内省机制是通过反射来实现的,BeanInfo用来暴露一个bean的属性、方法和事件,以后我们就可以操纵该JavaBean的属性了。
在Java内省中,用到的基本就是上述几个类。通过BeanInfo这个类就可以获取到类中的方法和属性。
举例:
Person类
public class Person { private String name = "Tom"; private int 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; } public void eat(){ System.out.println("eat food!"); } }
public class Reflect { public static void main(String[] args) throws Exception { Person p = new Person(); //获取Person类中的属性,被封装到了BeanInfo中,若想获得(不包括Object类中的)属性,则参数为(Person.class, Object, class) BeanInfo bi = Introspector.getBeanInfo(Person.class); PropertyDescriptor[] pds = bi.getPropertyDescriptors(); //获得类中所有属性描述器 System.out.println("属性描述器个数:" + pds.length); //3个,因为Object类中的getClass()方法,也算作1个属性 for(PropertyDescriptor pd : pds){ System.out.println(pd.getName()); } PropertyDescriptor pd = new PropertyDescriptor("name", Person.class); Method m = pd.getReadMethod(); //获取getName()方法,即读方法 String value = (String)m.invoke(p, null); System.out.println(value); Method m1 = pd.getWriteMethod(); m1.invoke(p, "Jerry"); System.out.println(p.getName()); } }
输出:
属性描述器个数:3 age class name Tom Jerry setName
三、BeanUtils工具包是Apache开发的一套快速操作JavaBean get/set方法的API,需要commons-beanutils.jar, commons-logging.jar
注:BeanUtils可以进行类型的自动转换,但仅限基本类型
举例:
在原有Person类中加入private Date birthday;,以及get/set方法
public class Reflect { public static void main(String[] args) throws Exception { Person p = new Person(); String name = BeanUtils.getProperty(p, "name"); //调用getName()方法 System.out.println(name); BeanUtils.setProperty(p, "name", "Jerry"); System.out.println(p.getName()); //非基本类型的属性设置,给BeanUtils注册类型转换器 ConvertUtils.register(new Converter() { //type目标类型 //value当前传入的值 @Override public Object convert(Class type, Object value) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); if (value instanceof String) { String v = (String) value; Date d = null; try { d = df.parse(v); } catch (ParseException e) { e.printStackTrace(); } return d; } else { Date d = (Date)value; return df.format(d); } } }, Date.class); BeanUtils.setProperty(p, "birthday", "2017-10-10"); System.out.println(p.getBirthday()); /* 也可以采取这种方式 ConvertUtils.register(new DateLocaleConverter(), Date.class); //DateLocaleConverter是对上面代码的封装 BeanUtils.setProperty(p, "birthday", "1999-09-09"); System.out.println(p.getBirthday()); */ } }
BeanUtils可以将Map属性自动放到Bean中
注:原则是,Map的key必须要与Bean的属性一致
举例:
public class Reflect { public static void main(String[] args) throws Exception { HashMap map = new HashMap(); map.put("name", "zhang"); Person p = new Person(); BeanUtils.populate(p, map); System.out.println(p.getName()); } }
相关文章推荐
- java反射基础
- 黑马程序员——java基础—反射
- Java自学之路-Java基础教程-48:Java的反射机制Reflection
- java 反射基础(1)
- Java基础-反射学习和JDK新特性
- JAVA 反射基础
- java基础——反射
- -java简单反射(框架基础)体验
- JAVA基础 (二)反射 深入解析反射机制
- JAVA基础--JAVA中的反射机制详解
- JAVA基础 (三)反射 深入解析反射机制
- Java基础知识——反射机制
- [零基础学JAVA]Java SE应用部分-36.反射机制与工厂设计模式 推荐
- java基础知识(二)--反射机制
- 【Java基础学习】 详解Java的反射机制
- java基础加强(二)(枚举与反射)
- Java基础系列:(3)反射机制的简单总结
- JAVA基础--JAVA中的反射机制详解
- 梦入IBM之java基础第十四天反射
- 【java基础】04.反射