——java中的反射
——java中的反射
---------------------- <a href=""target="blank">ASP.Net+Unity开发</a>、<a href=""target="blank">.Net培训</a>、期待与您交流! ----------------------
什么是反射?
一,反射就是把java类中的各个成员,提取成其对应的java类对象。
例如:一个java类中用一个Class类的对象来表示,一个类中的组成部分都有对应的类:
Field —— 成员变量;
Method —— 成员方法;
Constructor —— 构造函数;
Package ——包
二,一个类中的每个成员可以用相对应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些
实例对象,就可以执行相应的操作了。
反射的基石 -- Class类
1,java中的各个java类属于同一类事物,描述这类事物的java类名就是Class。
注:对比:众多人用一个Person类表示,众多的java类就用Class表示
a,一个人 -->Person
b,java类 -->Class
2,Class类代表java类,它的实例对象分别对应什么呢?
1,对应各个类在内存中字节码,例如,String类的字节码,Person类的字节码等。。。
2,一个类被类加载器加载到内存中,占用一片存储空间,这个空间的内容就是类的字节码,不同的类的字节码是不同的,
所以它们在内存中的内容是不同的,这一个个空间分别用一个个的对象来表示,这些对象具有相同的类型即Class类型。
3,如何得到各个字节码对应的实例对象(Class类型)
有3中方式:
1:类名.class;例如:System.class
2:对象名.getClass();例如:new Date().getClass()3:Class.forName(类的全名称(包名+类名)字符串);例如:Class.forName("java.util.Date");
4,九个预定义Class实例对象:
1,boolean.class = Boolean.TYPE,
2,char.class = Character.TYPE,
3,byte.class = Byte.TYPE,
4,short.class = Short.TYPE,
5,int.class = Integer.TYPE,
6,long.class = Long.TYPE,
7,float.class = Float.TYPE,
8,double.class = Double.TYPE,
9,void.class = Void.TYPE
5,数组类型的Class对象实例对象
1,Class.isArray()
2,总之,只要好似在源程序中出现的类型,都有各自的Class实例对象,例如,int[]
构造函数的反射应用
一,Constructor类代表某个类中的一个构造方法
二,得到某个类所有的构造方法:
示例:Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
三,得到某一个构造方法://获取时要用到参数类型
示例:Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
四,创建示例对象:
示例:
1,普通方式:String str = new String(new StringBuffer("abc"));
2,反射方式:
Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
String str = (String)constructor.newInstance(new StringBuffer("abc"));
五,Class.newInstance()方法:
1,示例:String obj = (String)Class.forName("java.lang.String").newInstance();
2,该方法内部先得到默认的构造方法,然后用该构造方法来创建实例对象。
3,该方法内部的具体事项代码,用到了缓存机制来保存默认构造方法的示例对象。
构造函数反射的示例代码:
package com.itheima.reflect;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;/*** 反射操作构造函数* @author wuyong**/
public class ConstrutorDemo {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubtry {Constructor constructor1 = String.class. getConstructor(StringBuffer .class);String str2 = (String) constructor1.newInstance (/*"abc"*/new StringBuffer("abc"));System.out .println(str2.charAt (2));} catch (Exception e) {e.printStackTrace();}}}
成员变量的反射
Field类表示某个类中的一个成员变量。
语法:
类名 对象名 = new 类();
Field field = 对象名.getClass().getField(属性名字符串);
此时field对象并不代表具体的值,只代表该类下的成员变量的一个对象,
要获取到指定对象里的成员变量的值,语法如下:
field.get(对象名);指明要取的成员变量的值属于哪个对象里的。
注:一,getField()和getDeclareField()方法的区别:
getField()方法只能获取到访问级别为可见的属性,不能获取到不可见的属性,若调用该方法
获取不可见的属性,会报出:notFoundFieldException的异常。
getDeclareField()方法可以获取该类中声明的所有属性,包括private所修饰的。
二,使用Field 对象下的get(对象名)来获取该对象下的属性时,如果属性的访问修饰符为不可见时,
则会报出IllegaAccessException()异常。若要获得不可见的属性的话,可以用以下的方式来强行
获得,Field对象名.setAccessible(true);设置访问级别为可见。(称为暴力反射)
例子:将一个类中的所有String类型中的"b"全部换成"a";
注:字节码比较时,要用"=="来比较,因为是同一份字节码。
成员变量反射的实例代码:
package com.itheima.reflect;import java.lang.reflect.Field;/*** 成员变量的反射* @author wuyong**/
public class FieldDemo {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubtry {ReflectPoint point = new ReflectPoint(3,5 );Field fieldY = point .getClass().getField("y" );//fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值System.out .println("成员变量Y的值:" + fieldY.get (point));Field fieldX = point .getClass().getDeclaredField("x" );//由于X是不可见的,所以就要调setAccessible,并设为true的方式。用暴力反射的方式来获得。fieldX.setAccessible (true);System.out .println("成员变量X的值:" + fieldX.get (point)); //2)将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。Field name = point.getClass().getField("name");System.out.println("替换之前:" + name.get(point));changeStringValue(point);System.out .println("替换之后:" + name.get(point));} catch (Exception e) {e.printStackTrace();}}/*** 定义一个将所有字符串的类成员变量中的”a“ 变成 ”b“的方法* @param obj* @throws Exception*/private static void changeStringValue(Object obj ) {try {Field[] fields = obj. getClass().getFields ();for(Field field : fields ){//if(field.getType().equals(String.class)){if(field .getType() == String .class){String oldValue = ( String)field .get( obj);String newValue = oldValue.replace("b" , "a" );field .set( obj, newValue );}}} catch (Exception e) {e.printStackTrace();} }}
/*** 被反射操作的类* @author wuyong**/
class ReflectPoint {private int x;public int y;public String name = "a1b2c3d4c3b2a1";public ReflectPoint(int x,int y){this.x = x;this.y = y;}public static void main(String[] args){for (int i = 0; i < args.length; i++) {System.out.println(args[i]);}}
}
成员方法的反射
Method代表某一个类中的一个成员方法
语法:
Class cls = TestUtil1.class;
TestUtil1 tu1 = (TestUtil1)cls.newInstance();
Method method = cls.getDeclaredMethod("show", null);//指定获取方法名为“show”,并且没有参数的方法
method.invoke(tu1, null);//在对象tu1中执行无参的方法
Method method2 = cls.getDeclaredMethod("show2", null);
method2.invoke(null, null);//当对象参数为null时,表示这是一个静态方法
调用方法的方式:
一,使用对象名.方法名。调用;
二,使用反射来获得对应的方法对象,来调用invoke(Object obj,Object...args)执行方法;
其中obj是指那一个对象上的方法,args是表示该方法的参数列表
注:专家模式:哪个类拥有该方法需要的私有数据,那这个方法就属于哪个类。
用反射调用某个类的main方法
语法:
String className = args[0];//获取第一个参数,首先要设置RunConfigurations中的Arguments为要执行的类的完整类名。
Class cls2 = Class.forName(className);//通过活动到的完整类名,获得该类的字节码
Method main = cls2.getMethod("main", new String[]{}.getClass());//通过字节码,获得该类的main方法
/*
* 因为为了兼容JDK1.4以下的版本,在传入参数的时候,会对参数进行装包;执行时,会对参数进行拆包,如果
* 单纯的传入一个数组的话,则在拆包的时候将每一个元素都拆成一个参数,此时会报出:IllegalArgumentException异常
* 解决方式有以下2种。
*/
//使用一个Object数组,再把传入的数组参数当成Object数组的一个元素在传入。
//main.invoke(null, new Object[]{new String[]{"abc","东方","123"}});
//将传入的参数强转成Object对象,
main.invoke(null, (Object)new String[]{"abc","东方","123"});
成员方法反射的示例代码:
package com.itheima.reflect;import java.lang.reflect.Method;/*** 类成员方法的反射* @author wuyong**/
public class MethodDemo {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubtry{//执行普通方法String str1 = "asdewfs21";//str1.charAt(1)Method methodCharAt = String .class. getMethod("charAt" , int .class);System.out .println("字符串的第二个字符是:" + methodCharAt.invoke (str1, 1 ));System.out .println("字符串的第二个字符是:" + methodCharAt.invoke (str1, new Object[]{2 }));//执行Person的main方法,及静态方法的演示
// Person.main(new String[]{"111","222","333cc"});//静态方法由于不用对象就可以调用,所以对象那个参数是null。 //用反射的方式调用ReflectPoint的main方法,//注:运行前要设置当前主函数的参数步骤:Run Configureations ---> Arguments --->要调用的类的全名称如:com.itheima.reflect.ReflectPointString startingClassName = args [0];Method mainMethod = Class .forName(startingClassName).getMethod ("main", String[].class);//mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});mainMethod.invoke (null, (Object )new String []{"111","222" ,"333"}); //数组,jdk会将数组拆成多个参数,从而出现参数不对异常。}catch (Exception e) {e.printStackTrace();}}}
/*** 被反射操作的类* @author wuyong**/
class ReflectPoint {private int x;public int y;public String name = "a1b2c3d4c3b2a1";public ReflectPoint(int x,int y){this.x = x;this.y = y;}public static void main(String[] args){for (int i = 0; i < args.length; i++) {System.out.println(args[i] + "aa");}}
}
数组的反射,及数组与Object
数组的反射
1,具有相同位数(例如:一维对一维)和元素类型的数组属于同一个类型,即具有相同的Class实例对象
2,代表数字的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class
3,基本类型的一维数组可以被当做Object类型使用,不能当作Object[]类型使用;
非基本类型的一维数组,既可以当作Object类型使用,又可以当作Object[]类型使用。
4,Arrays.asList()方法处理int[]和String[]的差异
当处理的是一维的基本数据类型的数组时,其保存的是一维数组的完整名称,即内存中的地址如:[I @a6d7f3。但二维的基本数据类型数组是可以遍历的。
当处理的是引用类型的数组,则会将每一个元素都保存到集合中。
5,Array工具类用于完成对数组的反射操作。
6,通过反射获取元素的步骤:
1,获取数组的字节码:对象.getClass()
2,判断是否是数组:字节码对象.isArray()
3,获取数组的长度:getlength(Object obj)
4,遍历数组元素
5,通过元素.getClass().getName()方法获取元素对应的类型
数组反射的示例代码:
package com.itheima.reflect;import java.lang.reflect.Array;
import java.util.Arrays;/*** 数组的反射,及数组与Object对象* @author wuyong**/
public class ArrayDemo {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubint [] a1 = new int []{1, 2,3 };int [] a2 = new int [4];int[][] a3 = new int [2][ 3];String [] a4 = new String[]{"a" ,"b","c"};System.out .println("a1 = a2" + (a1.getClass () == a2.getClass ())); //true , 相同的类型和相同的维数有相同字节码对象//JDK1.5之后,编译错误,因为出现了泛型是。类型不同,没有可比性
// System.out .println(a1.getClass () == a4.getClass ());//false//JDK1.5之后,编译错误维数不同,没有可比性
// System.out .println(a1.getClass () == a3.getClass ());//falseSystem.out .println("a1的名称" + a1.getClass ().getName());//[ISystem.out .println("a1的父类名称" + a1.getClass ().getSuperclass().getName());//java.lang.ObjectSystem.out .println("a4的父类名称" + a4.getClass ().getSuperclass().getName());//java.lang.ObjectObject aObj1 = a1 ;Object aObj2 = a4 ;//Object[] aObj3 = a1;//不行,因为基本数据类型不是ObjectObject[] aObj4 = a3; //二维数组,将一维数组作为一个对象,Object[] aObj5 = a4; //string本身就是一个对象System.out .println("a1的toString()形式:" + a1);System.out .println("a1的toString()形式:" + a4);//基本类型的一维数组传入asList方法后,会将数组当成一个对象元素存入集合中。System.out .println("a1的保存集合后的形式:" + Arrays.asList (a1)); //[I@12344 asList(T...t) 作为对象传递进去了。//引用类型就可以遍历System.out .println(Arrays.asList (a4)); //[a,b,c] asList(Object[] obj) 兼容jdk1.4,作为数组传递进去// 数组的反射//传递数组调用printObject(a4 );//传递对象调用printObject("xyz" );}/*** 数组的反射,如果是数组则遍历,如果是当对象就输出* @param obj*/private static void printObject(Object obj ) {Class clazz = obj. getClass();if(clazz .isArray()){ //如果是数组,拆开数组,打印里面的元素int len = Array.getLength (obj);for(int i=0;i
---------------------- <a href=""target="blank">ASP.Net+Unity开发</a>、<a href=""target="blank">.Net培训</a>、期待与您交流! ----------------------
- 浪潮存储与虚拟服务器连接失败,浪潮
- Eclipse,JKD,JRE
- 前端和Java后端分别需要学哪些技术?
- CStdioFile的Writestring无法写入中文的问题
- Web过滤器:Filter
- 均衡负载集群(LBC)
- 小波变换的理解(适合新手短期内分析信号的高频特性f)
- 狄利克雷分布通俗讲解
- Python四行代码实现的猜数字小游戏,基于thinker,带GUI界面
- sql语句执行顺序及简单优化
- PTA题目 计算分段函数[3]
- 搭建Janus的HTTPS环境
- Java中带返回值的线程池Future
- Java并发Future
- 视频编解码——编码流程介绍
- 字符编码简介:ASCII,Unicode,UTF
- JS JavaScript