黑马程序员——高新技术3——反射和JavaBean

来源:互联网 发布:知乎 大胸妹子 编辑:程序博客网 时间:2024/06/06 01:40
------- android培训java培训、期待与您交流! ----------

反射概述

反射就是把Java语言中的类,类成员,数组和枚举映射成相应的Java类,从而完成一些正常情况下完成不了的功能。

反射很耗性能,反射的作用相当于在运行时修改Java源代码。很多测试和反编译工具就是反射实现。

反射机制主要用到了下面的类和方法:


上面带下划线的表示静态成员

反射类及对象

声明类时候用的是关键词class,而反射用到的是Class类,首字母是大写的。
Java类是对具体事务的抽象,Class类是所有Java类的抽象。
得到普通Java类的字节码(Class对象)的方法有三种:
1.类名.class
2.对象名.getClass()
3.Class.forName("类名")
实际用法见下面代码:
package cn.itcase.day1;/** * 反射代码例子——Class类 * @author zwl */public class ReflectionDemo {public static void main(String[] args){//第一种获取Class类对象(字节码)的方法:类名.classClass cls1=Person.class;//第二种获取Class类对象(字节码)的方法:对象名.getClass()Person person=new Person();Class cls2=person.getClass();//第三种获取Class类对象(字节码)的方法:Class.forName("完整限定类名");Class cls3=null;try {//注意这里必须进行异常处理否则无法编译,forName()方法参数必须加包名,否则报异常cls3=Class.forName("cn.itcase.day1.Person");} catch (ClassNotFoundException e) {System.err.println("Person类未找到");}//测试是否获取的是内存上同一个字节码System.out.println(cls1==cls2);//trueSystem.out.println(cls2==cls3);//true}}class Person{}
得到基本数据类型boolean,byte,char,short,int,long,float,double和void的字节码(Class对象)的方法是:
关键字.class
代码如下:
public class ReflectionDemo {public static void main(String[] args){//基本数据类型的字节码Class cls1=int.class;Class cls2=Integer.class;//基本数据类型的字节码和它的封装类的字节码不同哦System.out.println(cls1==cls2);//false}}

反射构造函数

注意使用Constructor类需要导入java.lang.reflect包
主要使用Constructor类和Class类对象的getConstructor方法,代码例子如下:
public static void main(String[] args)throws Exception{//获取String类的构造方法String(StringBuffer buffer)的Constructor对象Constructor constructor= String.class.getConstructor(StringBuffer.class);//用Constructor的对象创建一个String类的实例,参数是一个StringBuffer对象String str1=(String)constructor.newInstance(new StringBuffer("反射构造方法"));System.out.println(str1);}
其中第2行的getConstructor方法的参数的作用是指定要获取String类的哪个构造方法,该参数是要获取的构造方法的参数类型的字节码。例如要获取构造方法public String(StringBuffer s)的Constructor对象,则getConstructor方法要传入参数StringBuffer.class,而如果要获取public String(byte[] bytes,int offset,int length)的Constructor对象,则getConstructor方法的参数要传入byte[].class,int.class,int.class三个参数。

反射字段

使用Field类前要导入java.lang.reflect包
主要用于在运行时获取指定对象的成员变量的值,例子代码如下:
首先定义Point类,用于作为Field类的操作对象:
public class Point {public int x;private int y;public Point(int x, int y) {this.x = x;this.y = y;}}
然后在主函数中反射成员变量:
public class ReflectionDemo {public static void main(String[] args)throws Exception{Point point=new Point(3, 5);//反射公有成员变量xField xField=Point.class.getField("x");System.out.println(xField.get(point));//反射私有成员变量yField yField=Point.class.getDeclaredField("y");yField.setAccessible(true);System.out.println(yField.get(point));}}
其中getField方法用于获取公有成员变量,getDeclaredField方法用于私有成员变量,setAccessible用于获取对私有成员的访问权限,Field对象的get方法用于获取指定对象实例的指定成员变量的值。

反射字段练习

写一个方法,利用反射,修改一个类对象里所有的String类型成员变量的值,把其中的b改为a
import java.lang.reflect.Field;public class ReflectionDemo {public static void main(String[] args)throws Exception{Person person=new Person();ChangeValue(person);System.out.println(person);}public static void ChangeValue(Object object) throws Exception{Field[] fields=Person.class.getFields();for (Field field : fields) {if (field.getType()==String.class) {String oldValue=(String)field.get(object);String newValue=oldValue.replace('b', 'a');field.set(object,newValue);}}}}
Person类的代码如下:
public class Person {public String name1="ball";public String name2="basketball";public String name3="point";public String toString(){return name1+"\n"+name2+"\n"+name3;}}

反射方法

method类用于反射类型中的方法,例子代码如下:
首先定义一个MethodReflection类作为反射要处理的类的例子,这里的类可以被任何类替代
class MethodReflection{public void show(){System.out.println("调用了show()");}public String show(int a){System.out.println("调用了show(int a)");return "返回值:"+(a+1);}private int[] show(int[] inputs){System.out.println("调用了show(int[] inputs)");for (int i = 0; i < inputs.length; i++) {inputs[i]+=1;}return inputs;}public static void show(String[] args){for (String string : args) {System.out.println(string);}}}
用反射调用MethodReflection类中的各个方法
import java.lang.reflect.Method;public class ReflectionDemo {public static void main(String[] args)throws Exception{RefectionMethod();}public static void RefectionMethod()throws Exception{//调用public void show()Method showMethod1=MethodReflection.class.getMethod("show");MethodReflection mr1=new MethodReflection();showMethod1.invoke(mr1);//调用public String show(int a),并打印方法的返回值Method showMethod2=MethodReflection.class.getMethod("show",int.class);MethodReflection mr2=new MethodReflection();Object primitiveReturnValue= showMethod2.invoke(mr2, 3);String needReturnValue=(String)primitiveReturnValue;System.out.println(needReturnValue);//调用private int[] show(int[] inputs)Method showMethod3=MethodReflection.class.getDeclaredMethod("show",int[].class);showMethod3.setAccessible(true);MethodReflection mr3=new MethodReflection();int[] arg3=new int[]{1,2,3,4};Object primitiveReturnValue3= showMethod3.invoke(mr3, arg3);int[] needReturnValue3=(int[])primitiveReturnValue3;for (int i : needReturnValue3) {System.out.println(i);}//public static void show(String[] args)Method showMethod4=MethodReflection.class.getMethod("show",String[].class);String[] strings=new String[]{"字符串1","字符串2","字符串3"};showMethod4.invoke(null, (Object)strings);//因为String[]类型会被当成多个参数,所以此处需要“打包”下}}

数组的反射

数组的反射,主要用java.lang.reflect.Array,类区别于java.sql.Array类。所有的数组都继承自Object类,相同维度和元素数据类型的数组使用同一个类。下面举例介绍数组反射的几个方法:
public static void arrayReflection(){int[] a=new int[]{1,2,3};for (int i = 0; i <Array.getLength(a); i++) {System.out.println(Array.get(a, i));}}

JavaBean

JavaBean就是符合如下规则的Java类:

1.必须有无参构造函数

2.必须有get方法(无参)和set方法(有参)

例子代码如下:

public class Person {private int x;public int getAge(){return x;}public void setAge(int age){this.x=age;}}

内省

内省英文为Introspector,主要用于操作javabean。

内省访问JavaBean有两种方式:

1.通过PropertyDescriptor类来操作JavaBean对象

2.通过Introspector类获取JavaBean对象的BeanInfo,然后通过BeanInfo来获取所有属性的PropertyDescriptor(属性描述器)数组,然后通过遍历这个数组来获取某个属性的名称、类型、getter和setter方法,进而可以通过反射来调用这些方法。

下面是内省所涉及的所有的类及方法的UML类图:


下面的例子用PropertyDescriptor类读写Javabean类对象的属性值(以上面的Person类为例):

import java.beans.PropertyDescriptor;import java.lang.reflect.Method;public class IntrospectionDemo {public static void main(String[] args)throws Exception {Person person=new Person();person.setAge(22);//内省get方法String propertyName="age";PropertyDescriptor pd=new PropertyDescriptor(propertyName, person.getClass());Method method=pd.getReadMethod();Object ret=method.invoke(person);System.out.println(ret);//内省set方法Object value=22;PropertyDescriptor pd2=new PropertyDescriptor(propertyName, person.getClass());Method method2=pd2.getWriteMethod();method2.invoke(person, value);//打印ageSystem.out.println(person.getAge());}}

上面的代码第9、10、11行可以用MyEclipse抽取成单独的方法,MyEclipse自动抽取方法功能的原则是,上面声明和初始化,此处调用的为输入参数;此处声明和赋值,下面调用的为返回值。也就是说选择抽取方法的代码块中,至多有一个变量被下面的代码调用,否则无法抽取。 

将上一段代码中的两个内省操作(9、10、11行)(15、16、17行)抽取成单独的方法:

import java.beans.IntrospectionException;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class IntrospectionDemo {public static void main(String[] args)throws Exception {Person person=new Person();person.setAge(22);//内省get方法String propertyName="age";Object ret = getProperty(person, propertyName);System.out.println(ret);//内省set方法Object value=22;setProperty(person, propertyName, value);//打印ageSystem.out.println(person.getAge());}private static void setProperty(Person person, String propertyName,Object value) throws IntrospectionException,IllegalAccessException, InvocationTargetException {PropertyDescriptor pd2=new PropertyDescriptor(propertyName, person.getClass());Method method2=pd2.getWriteMethod();method2.invoke(person, value);}private static Object getProperty(Object obj, String propertyName)throws IntrospectionException, IllegalAccessException,InvocationTargetException {PropertyDescriptor pd=new PropertyDescriptor(propertyName, obj.getClass());Method method=pd.getReadMethod();Object ret=method.invoke(obj);return ret;}}

复杂内省

下面的代码演示用Introspector类对象的方法来获取JavaBean的属性信息,和上一节的代码功能一致:

import java.beans.BeanInfo;import java.beans.IntrospectionException;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;public class IntrospectionDemo {public static void main(String[] args)throws Exception {Person person=new Person();person.setAge(22);String propertyName="age";Object ret = getProperty(person, propertyName);System.out.println(ret);Object value=26;setProperty(person, propertyName, value);//打印ageSystem.out.println(person.getAge());}//内省set方法private static void setProperty(Object obj, String propertyName,Object value) throws IntrospectionException,IllegalAccessException, InvocationTargetException {//PropertyDescriptor pd2=new PropertyDescriptor(propertyName, person.getClass());//Method method2=pd2.getWriteMethod();//method2.invoke(person, value);BeanInfo beanInfo=Introspector.getBeanInfo(obj.getClass());PropertyDescriptor[] pds=beanInfo.getPropertyDescriptors();for (PropertyDescriptor pDescriptor : pds) {if (pDescriptor.getName().equals(propertyName)) {pDescriptor.getWriteMethod().invoke(obj, value);}}}//内省get方法private static Object getProperty(Object obj, String propertyName)throws IntrospectionException, IllegalAccessException,InvocationTargetException {//PropertyDescriptor pd=new PropertyDescriptor(propertyName, obj.getClass());//Method method=pd.getReadMethod();//Object ret=method.invoke(obj);BeanInfo beanInfo=Introspector.getBeanInfo(obj.getClass());Object ret=null;PropertyDescriptor[] propertyDescriptors=beanInfo.getPropertyDescriptors();for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {if (propertyDescriptor.getName().equals(propertyName)) {ret=propertyDescriptor.getReadMethod().invoke(obj);}}return ret;}}

BeanUtils工具包

BeanUtils是Apache(一个软件基金会,中文名阿帕奇)提供的一个用于简化操作Javabean的代码的类库。

下载地址:点这里

导入方法:见这里

导入BeanUtils类库后还需导入阿帕奇的logging包。

使用方法见如下代码:

import org.apache.commons.beanutils.BeanUtils;public class IntrospectionDemo {public static void main(String[] args)throws Exception {Person person=new Person();person.setAge(22);String propertyName="age";//Object ret = getProperty(person, propertyName);Object ret=BeanUtils.getProperty(person, propertyName);System.out.println(ret);Object value=26;//setProperty(person, propertyName, value);BeanUtils.setProperty(person, propertyName, value);//打印ageSystem.out.println(person.getAge());}}





0 0
原创粉丝点击