java笔记32 反射
2015-06-21 11:58
423 查看
1. 反射
JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。
动态获取类中信息,就是java反射。可以理解为对类的解剖。
如果想要对指定名称的字节码文件进行加载并获取其中的内容并调用,这时就使用到了反射技术。
简单地说:
反射把java类中的各种成分(方法、包名、变量等等)映射成相应的java类。
通过Class类的一系列方法,可以获取其中的变量、方法、构造方法、修饰符等信息。
2. 反射的基础àClass类(Class是大写)
Class类:
Java程序中各个java类属于同一类型事物,描述这类事物的java类名就是Class。
获取字节码的方式:
1、使用类名.class à类不一定事先加载
比如使用了Date类,Person类
Class cls1=Date.class;//字节码
Class cls2=Person.class;
2、使用对象的getClass()方法 à不一定会有实例对象
例如:p1.getClass();
3、使用Class.forName(“类名”) à通常使用这一种
Class.forName(“java.lang.String”);
System.out.println(int.class.isPrimitive());//判断是否为基本类型
System.out.println(int.class==Integer.TYPE);//返回是true
//Integer.TYPE代表是被包装类的字节码
System.out.println(int [] .class.isArray());
只要是在源程序中出现的类型,都有各自的Class实例对象。
3. Constructor类
代表某个类中的一个构造方法
1、 得到某个类中所有的构造方法
Constructor [] constructor=Class.forName(“java.lang.String”).getConstructors();
2、 得到某一个构造方法
Constructor constructor=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
反射相对耗内存
4. Filed类
ReflectPoint pt1=new ReflectPoint(3,5);
Field fieldY=pt1.getClass().getField("y");
//fieldY的值不是5,fieldY不是对象身上的变流量,而是类上,要用它去去某个对象上对应的值。
System.out.println(fieldY.get(pt1));
Field fieldX=pt1.getClass().getDeclaredField("x");//私有的变量不能直接获得,要用Declared
fieldX.setAccessible(true);//暴力反射,将参数设为可获得
System.out.println(fieldX.get(pt1));//这个时候可以知道有x,但不能获得,需要使用暴力反射
5. Method类
//获得String类的charAt方法
Method method=String.class.getMethod("charAt", int.class);
System.out.println(method.invoke(str2, 1)); //获得abc中角标为1的元素
//invoke 调用,是Method类中的方法,表示表用前面的方法。
//invoke(null,1) 说明调用的是静态方法
Class.getMethod方法用于得到一个方法,该方法要接受什么参数,显然要一个方法名
但方法名可能重名,要根据参数类型和个数来区别
6. 通过反射调用main方法
//调用一个类中的main方法的一般方式
//TestArguments.main(new String[]{"haha","hehe"});
Class clazz=Class.forName(args[0]);// 把cn.itcast.TestArguments作为第一个参数传入主函数,用这个参数去获得类字节码。
Method mainMethod=clazz.getMethod("main", String[].class);
//mainMethod.invoke(null, new Object[]{new String[]{"haha","hehe"}});
mainMethod.invoke(null, (Object)new String[]{"haha","hehe"});
7. 数组的反射
1、具有相同维数和元素类型的数组具有相同的Class实例对象
2、数组的Class实例对象的getSuperclass()方法返回父类为Object类对应的Class
3、基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用。
4、非基本类型的一维数组,既可以当做Object类使用,也可以当做Object[]类型使用
5、Arrays.asList()方法处理int[]和 String[]时的差异
8. 内存泄露
以HashSet为例,
如果重写了HashCode方法,添加对象后不要再去修改 参与了哈希值计算的变量,否则会导致不能删除该对象。会造成内存泄露。
内存溢出(out of memory ) :通俗的说就是内存不够用了,比如在一个无限循环中不断创建一个大的对象,很快就会引发内存溢出。
内存泄漏(leak of memory) :是指为一个对象分配内存之后,在对象已经不在使用时未及时的释放,导致一直占据内存单元,使实际可用内存减少,就好像内存泄漏了一样。
substring(int beginIndex, int endndex )是String类的一个方法,但是这个方法在JDK6和JDK7中的实现是完全不同的(虽然它们都达到了同样的效果)。
在jdk1.6中,substring引用还是原字符串,只是偏移量不同。
在jdk1.7中,修正了正给问题,获得了一个新的子串。
9. 用反射开发框架的原理
1、框架与框架要解决的核心问题
房子是一个框架,用户要自己安装门窗、空调等。用户需要使用房子这个框架,吧门窗插入。
框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
2、在写框架的时候,类还没有出现(即还没有门窗),但是可以定义好类名(比如说一定有“门”这个部件名,一定有“窗”这个部件名。)
3、通过部件名来获得字节码(类似门或者窗的图纸)。
10. 反射演示
先建立一个普通类
public class ReflectPoint { private int x; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + x; result = prime * result + y; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ReflectPoint other = (ReflectPoint) obj; if (x != other.x) return false; if (y != other.y) return false; return true; } public int y; public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; } public String str1="ball"; public String str2="basketball"; public String str3="itcast"; @Override public String toString() { return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ", str3=" + str3 + "]"; } }
反射各类方法演示
import java.lang.reflect.*;//反射包public class ClassTest{ public static void main(String[] args) throws Exception { //获取构造器 需要传入类型 Constructor<String>cons1=String.class.getConstructor(StringBuffer.class);//获得一个参数是StringBuffer的构造函数 //使用构造方法构造对象 要传入该类型参数 String str2=cons1.newInstance(new StringBuffer("abc"));//定义泛型(cons1是一个String的构造器),不用强转 System.out.println(str2);//输出abc //String str3=String.class.newInstance(); ReflectPoint pt1=new ReflectPoint(3,5); Field fieldY=pt1.getClass().getField("y");//y对应的属性 //fieldY的值不是5,fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值。 System.out.println(fieldY.get(pt1));//结果是5 Field fieldX=pt1.getClass().getDeclaredField("x");//私有的变量不能直接获得,要用Declared fieldX.setAccessible(true);//暴力反射,将参数设为可获得 System.out.println(fieldX.get(pt1));//同样获取x字段对应的值 结果是3 fieldX.set(pt1, 1);//将pt1对应fieldX的参数设置为1 System.out.println(fieldX.get(pt1));//结果是1 changeStringvalue(pt1); System.out.println(pt1); //ReflectPoint [str1=aall, str2=aasketaall, str3=itcast] //获得String类的charAt方法 Method method=String.class.getMethod("charAt", int.class); System.out.println(method.invoke(str2, 1)); //获得abc中角标为1的元素 结果b //invoke 调用,是Method类中的方法,表示表用前面的方法。 //invoke(null,1) 说明调用的是静态方法 //调用一个类中的main方法的一般方式 //TestArguments.main(new String[]{"haha","hehe"}); Class clazz=Class.forName(args[0]);// 把cn.itcast.TestArguments作为第一个参数传入主函数,用这个参数去获得类字节码。 Method mainMethod=clazz.getMethod("main", String[].class); //mainMethod.invoke(null, new Object[]{new String[]{"haha","hehe"}}); mainMethod.invoke(null, (Object)new String[]{"haha","hehe"}); }//打印 haha hehe private static void changeStringvalue(Object obj) throws Exception, IllegalAccessException { Field[] fields=obj.getClass().getFields(); for(Field field:fields) { if(field.getType()==String.class)//这里是判断是不是同一份字节码,用== { String oldValue=(String)field.get(obj); String newValue=oldValue.replace('b', 'a');//替换操作 field.set(obj, newValue);// } } }} class TestArguments{ public static void main(String[] args) { for(String arg:args) { System.out.println(arg); } }}
JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。
动态获取类中信息,就是java反射。可以理解为对类的解剖。
如果想要对指定名称的字节码文件进行加载并获取其中的内容并调用,这时就使用到了反射技术。
简单地说:
反射把java类中的各种成分(方法、包名、变量等等)映射成相应的java类。
通过Class类的一系列方法,可以获取其中的变量、方法、构造方法、修饰符等信息。
2. 反射的基础àClass类(Class是大写)
Class类:
Java程序中各个java类属于同一类型事物,描述这类事物的java类名就是Class。
获取字节码的方式:
1、使用类名.class à类不一定事先加载
比如使用了Date类,Person类
Class cls1=Date.class;//字节码
Class cls2=Person.class;
2、使用对象的getClass()方法 à不一定会有实例对象
例如:p1.getClass();
3、使用Class.forName(“类名”) à通常使用这一种
Class.forName(“java.lang.String”);
System.out.println(int.class.isPrimitive());//判断是否为基本类型
System.out.println(int.class==Integer.TYPE);//返回是true
//Integer.TYPE代表是被包装类的字节码
System.out.println(int [] .class.isArray());
只要是在源程序中出现的类型,都有各自的Class实例对象。
3. Constructor类
代表某个类中的一个构造方法
1、 得到某个类中所有的构造方法
Constructor [] constructor=Class.forName(“java.lang.String”).getConstructors();
2、 得到某一个构造方法
Constructor constructor=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
反射相对耗内存
4. Filed类
ReflectPoint pt1=new ReflectPoint(3,5);
Field fieldY=pt1.getClass().getField("y");
//fieldY的值不是5,fieldY不是对象身上的变流量,而是类上,要用它去去某个对象上对应的值。
System.out.println(fieldY.get(pt1));
Field fieldX=pt1.getClass().getDeclaredField("x");//私有的变量不能直接获得,要用Declared
fieldX.setAccessible(true);//暴力反射,将参数设为可获得
System.out.println(fieldX.get(pt1));//这个时候可以知道有x,但不能获得,需要使用暴力反射
5. Method类
//获得String类的charAt方法
Method method=String.class.getMethod("charAt", int.class);
System.out.println(method.invoke(str2, 1)); //获得abc中角标为1的元素
//invoke 调用,是Method类中的方法,表示表用前面的方法。
//invoke(null,1) 说明调用的是静态方法
Class.getMethod方法用于得到一个方法,该方法要接受什么参数,显然要一个方法名
但方法名可能重名,要根据参数类型和个数来区别
6. 通过反射调用main方法
//调用一个类中的main方法的一般方式
//TestArguments.main(new String[]{"haha","hehe"});
Class clazz=Class.forName(args[0]);// 把cn.itcast.TestArguments作为第一个参数传入主函数,用这个参数去获得类字节码。
Method mainMethod=clazz.getMethod("main", String[].class);
//mainMethod.invoke(null, new Object[]{new String[]{"haha","hehe"}});
mainMethod.invoke(null, (Object)new String[]{"haha","hehe"});
7. 数组的反射
1、具有相同维数和元素类型的数组具有相同的Class实例对象
2、数组的Class实例对象的getSuperclass()方法返回父类为Object类对应的Class
3、基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用。
4、非基本类型的一维数组,既可以当做Object类使用,也可以当做Object[]类型使用
5、Arrays.asList()方法处理int[]和 String[]时的差异
8. 内存泄露
以HashSet为例,
如果重写了HashCode方法,添加对象后不要再去修改 参与了哈希值计算的变量,否则会导致不能删除该对象。会造成内存泄露。
内存溢出(out of memory ) :通俗的说就是内存不够用了,比如在一个无限循环中不断创建一个大的对象,很快就会引发内存溢出。
内存泄漏(leak of memory) :是指为一个对象分配内存之后,在对象已经不在使用时未及时的释放,导致一直占据内存单元,使实际可用内存减少,就好像内存泄漏了一样。
substring(int beginIndex, int endndex )是String类的一个方法,但是这个方法在JDK6和JDK7中的实现是完全不同的(虽然它们都达到了同样的效果)。
在jdk1.6中,substring引用还是原字符串,只是偏移量不同。
在jdk1.7中,修正了正给问题,获得了一个新的子串。
9. 用反射开发框架的原理
1、框架与框架要解决的核心问题
房子是一个框架,用户要自己安装门窗、空调等。用户需要使用房子这个框架,吧门窗插入。
框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
2、在写框架的时候,类还没有出现(即还没有门窗),但是可以定义好类名(比如说一定有“门”这个部件名,一定有“窗”这个部件名。)
3、通过部件名来获得字节码(类似门或者窗的图纸)。
10. 反射演示
先建立一个普通类
public class ReflectPoint { private int x; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + x; result = prime * result + y; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ReflectPoint other = (ReflectPoint) obj; if (x != other.x) return false; if (y != other.y) return false; return true; } public int y; public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; } public String str1="ball"; public String str2="basketball"; public String str3="itcast"; @Override public String toString() { return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ", str3=" + str3 + "]"; } }
反射各类方法演示
import java.lang.reflect.*;//反射包public class ClassTest{ public static void main(String[] args) throws Exception { //获取构造器 需要传入类型 Constructor<String>cons1=String.class.getConstructor(StringBuffer.class);//获得一个参数是StringBuffer的构造函数 //使用构造方法构造对象 要传入该类型参数 String str2=cons1.newInstance(new StringBuffer("abc"));//定义泛型(cons1是一个String的构造器),不用强转 System.out.println(str2);//输出abc //String str3=String.class.newInstance(); ReflectPoint pt1=new ReflectPoint(3,5); Field fieldY=pt1.getClass().getField("y");//y对应的属性 //fieldY的值不是5,fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值。 System.out.println(fieldY.get(pt1));//结果是5 Field fieldX=pt1.getClass().getDeclaredField("x");//私有的变量不能直接获得,要用Declared fieldX.setAccessible(true);//暴力反射,将参数设为可获得 System.out.println(fieldX.get(pt1));//同样获取x字段对应的值 结果是3 fieldX.set(pt1, 1);//将pt1对应fieldX的参数设置为1 System.out.println(fieldX.get(pt1));//结果是1 changeStringvalue(pt1); System.out.println(pt1); //ReflectPoint [str1=aall, str2=aasketaall, str3=itcast] //获得String类的charAt方法 Method method=String.class.getMethod("charAt", int.class); System.out.println(method.invoke(str2, 1)); //获得abc中角标为1的元素 结果b //invoke 调用,是Method类中的方法,表示表用前面的方法。 //invoke(null,1) 说明调用的是静态方法 //调用一个类中的main方法的一般方式 //TestArguments.main(new String[]{"haha","hehe"}); Class clazz=Class.forName(args[0]);// 把cn.itcast.TestArguments作为第一个参数传入主函数,用这个参数去获得类字节码。 Method mainMethod=clazz.getMethod("main", String[].class); //mainMethod.invoke(null, new Object[]{new String[]{"haha","hehe"}}); mainMethod.invoke(null, (Object)new String[]{"haha","hehe"}); }//打印 haha hehe private static void changeStringvalue(Object obj) throws Exception, IllegalAccessException { Field[] fields=obj.getClass().getFields(); for(Field field:fields) { if(field.getType()==String.class)//这里是判断是不是同一份字节码,用== { String oldValue=(String)field.get(obj); String newValue=oldValue.replace('b', 'a');//替换操作 field.set(obj, newValue);// } } }} class TestArguments{ public static void main(String[] args) { for(String arg:args) { System.out.println(arg); } }}
相关文章推荐
- java程序中数据类型转换
- 重新定向输出流,实现java程序日志功能。
- java中的三种排序方法使用:选择排序,冒泡排序,sort方法排序。
- 黑马程序员-Java 字符流的使用简明
- java编程思想复用,多态,以及设计模式-复用篇
- java笔记06 数组
- java笔记07 面向对象
- java笔记08 设计模式与单例设计模式
- java笔记09 继承
- java笔记10 多态 Object类
- java笔记11 模板设计模式
- java笔记12 内部类
- java笔记13 异常
- java笔记14 包
- java笔记15 多线程1
- java笔记15 多线程2(线程通信、Lock)
- java笔记16 String类
- java笔记17 集合框架 List Set 泛型
- java笔记18 Map集合
- java笔记19 Collections和Arrays