黑马程序员——Java学习之反射技术
2015-03-10 19:57
357 查看
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
反射技术也算得上是Java基础知识里较高新的一项技术了(但反射不是java5的新特性),犹记得老师课上说过,当反射遇到Private时,会让我们深深地领悟到啥叫一“招”回到解放前。
如果将Java语言中的各种技术比喻成江湖上纷繁的门派,反射技术的存在总是给人一种隐秘而强悍的幽灵般的感觉,它让限制不再,让规矩死亡,颇有几分C中的goto给人的第一印象。今天讨论反射,首先从下面一个题开刀吧!
ArrayList list = new ArrayList(); 如何在这个泛型为Integer的ArrayList中存放一个String类型的对象。
我们来分析分析给泛型为Integer的ArrayList中添加一个String类型对象,为什么会添加不进去?是因为ArrayList只接受Integer类型,那么,我们就让它不只是接受Integer。如何让它不是只接受Integer呢?既然是接收,靠的是ArrayList中的add方法了。
所以我们需要通过反射将方法接受类型改变,
若要反射,首先要对象字节码,想获取方法,还需要一个ArrayList对象。
其实所谓的泛型,也就是在方法上对于接受的类型进行了一个限定。而反射方法和字段以及构造,字节码就是必须的。运行方法,对象也是必要的。只是构造本来就是new对象的,而获取字段和方法需要有字节码对象,运行,就要有对象参与。
但是涉及反射,一定需求注意的是反射的对象所被修饰的修饰符是什么?
如果是public修饰的,直接可以getMethod();
如果是默认的,就需要通过getDeclaredMethod();
如果是private的话,就要通过暴力反射了,就是要通getDeclaredMethod(),并设置me.setAccessible(true)来进行设置权限
上题的操作如下:
联系泛型可以解释:泛型的出现阻止了形形色色的元素混入,可是,有了反射,就好比让接受重新回到解放前。反射的确是让程序重新变得不安全,因此,对于特别修饰的private,我们需求慎重来考虑一下,毕竟private自然有private的道理。
反射的概念
反射就是把java类中的各种成分映射成相应的java类。一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。
反射的基础:Class–>用来描述java中的类
如何得到各个字节码对应的实例对象
->类名.class 或者 类名.TYPE
->对象.getClass()
->Class.forName(“类名”)
总之,只要在源程序中出现的类型,都有各自的Class实例对象
反射的作用
反射机制最重要的内容——检查类的结构。
在java.lang.reflect包中有三个类Field、Method、Constructor分别用于描述类的域、方法和构造器。
这三个类共有方法:
getModifiers //返回一个整形数值,用不同的位开关描述public和static这样的修饰符使用状况
getName //用来返回项目的名称
构造方法的反射应用
constructor代表一个构造方法,constructor对象上的方法有:得到方法名字,得到所属类,产生实例对象。
无参:Constructor[] constructors =
Class.forName(“java.lang.String”).getConstructors();
有参:Constructor constructor =
Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
成员变量的反射:
Field类代表某个类中的一个成员变量 ,通过Field调用成员变量
如果想直接通过getField方法获取私有对象,会出现如下错误:java.lang.NoSuchFieldException : x
Field fieldX = rp.getClass().getDeclaredField(“x”);
fieldX.setAccessible(true);
这种方法称之为暴力反射,使用setAccessible(true)使private类型的成员变量也可以被获取。
成员方法的反射:
Method类用于描述类中的成员方法。
得到类中的某一个方法:Method charAt = Class.forName(“java.lang.String”)
.getMethod(“charAt”, int.class);
调用方法:
通常方法:System.out.println(str.charAt(1));
反射方法:System.out.println(charAt.invoke(str, 1));
注意:如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是静态方法!
框架的概念及用反射技术开发框架的原理:
框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
框架程序怎样调用以后写的类呢?很多时候程序无法知道被调用的类名,所以,在程序中无法直接new某个类的实例对象,而要用 反射 方式来做。
用类加载器的方式管理资源和配置文件:
方式一:采用类加载器进行加载,使用相对路径的方式
InputStream is = ReflectTest.class.getClassLoader().getResourceAsStream
(“com/mytest/config.properties”);
方式二:利用Class方式进行加载,使用相对路径的方式
nputStream is = ReflectTest.class.getResourceAsStream(“config.properties”);
方式三:利用Class方式进行加载,使用绝对路径的方式
InputStream is = ReflectTest.class .getResourceAsStream(“com/mttest/config.
properties”);
Array工具类 用于完成数组的反射操作:
ArrayList和HashSet的比较及Hashcode分析:
分析:
由以上两示例可以看到:
当集合为ArrayList时,其实质是一个数组,因此放入4个元素后,集合size为4。
当集合为HashSet时,需要通过比较hashcode值以及equals方法是否返回true决定是否放入。
如果hashcode值相等并且equals方法返回true,那么就不会放入。因此,集合size为3。
如果想让size为2,也就是pt1与pt3作为同一个元素存入HashSet集合,那就需要覆盖ReflectPoint类的hashCode方法以及equals方法。
总结:
反射在本质上就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等,明显反射技术的基石就是其class。所以在以后的编程工作中一定要清晰头脑,做到从字节码中反射出自己的思维。
反射技术也算得上是Java基础知识里较高新的一项技术了(但反射不是java5的新特性),犹记得老师课上说过,当反射遇到Private时,会让我们深深地领悟到啥叫一“招”回到解放前。
如果将Java语言中的各种技术比喻成江湖上纷繁的门派,反射技术的存在总是给人一种隐秘而强悍的幽灵般的感觉,它让限制不再,让规矩死亡,颇有几分C中的goto给人的第一印象。今天讨论反射,首先从下面一个题开刀吧!
ArrayList list = new ArrayList(); 如何在这个泛型为Integer的ArrayList中存放一个String类型的对象。
我们来分析分析给泛型为Integer的ArrayList中添加一个String类型对象,为什么会添加不进去?是因为ArrayList只接受Integer类型,那么,我们就让它不只是接受Integer。如何让它不是只接受Integer呢?既然是接收,靠的是ArrayList中的add方法了。
所以我们需要通过反射将方法接受类型改变,
若要反射,首先要对象字节码,想获取方法,还需要一个ArrayList对象。
其实所谓的泛型,也就是在方法上对于接受的类型进行了一个限定。而反射方法和字段以及构造,字节码就是必须的。运行方法,对象也是必要的。只是构造本来就是new对象的,而获取字段和方法需要有字节码对象,运行,就要有对象参与。
但是涉及反射,一定需求注意的是反射的对象所被修饰的修饰符是什么?
如果是public修饰的,直接可以getMethod();
如果是默认的,就需要通过getDeclaredMethod();
如果是private的话,就要通过暴力反射了,就是要通getDeclaredMethod(),并设置me.setAccessible(true)来进行设置权限
上题的操作如下:
public class Test { public static void main(String[] args) throws Exception { ArrayList<Integer> al = new ArrayList<Integer>(); Class clazz = ArrayList.class; //获取字节码对象. Method me = clazz.getMethod("add", Object.class); //反射方法. me.invoke(al,"我是字符串"); //运行方法. System.out.println(al); } }
联系泛型可以解释:泛型的出现阻止了形形色色的元素混入,可是,有了反射,就好比让接受重新回到解放前。反射的确是让程序重新变得不安全,因此,对于特别修饰的private,我们需求慎重来考虑一下,毕竟private自然有private的道理。
反射的概念
反射就是把java类中的各种成分映射成相应的java类。一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。
反射的基础:Class–>用来描述java中的类
如何得到各个字节码对应的实例对象
->类名.class 或者 类名.TYPE
->对象.getClass()
->Class.forName(“类名”)
总之,只要在源程序中出现的类型,都有各自的Class实例对象
String str1 = "abc"; //三种获取字节码的方法 Class cls1 = str1.getClass(); Class cls2 = String.class; Class cls3 = Class.forName("java.lang.String"); System.out.println(cls1 == cls2); //true System.out.println(cls2 == cls3); //true
反射的作用
反射机制最重要的内容——检查类的结构。
在java.lang.reflect包中有三个类Field、Method、Constructor分别用于描述类的域、方法和构造器。
这三个类共有方法:
getModifiers //返回一个整形数值,用不同的位开关描述public和static这样的修饰符使用状况
getName //用来返回项目的名称
构造方法的反射应用
constructor代表一个构造方法,constructor对象上的方法有:得到方法名字,得到所属类,产生实例对象。
无参:Constructor[] constructors =
Class.forName(“java.lang.String”).getConstructors();
有参:Constructor constructor =
Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
成员变量的反射:
Field类代表某个类中的一个成员变量 ,通过Field调用成员变量
public class ReflectPoint { private int x; public int y ; public ReflectPoint(int x, int y) { super( ); this.x = x; this.y = y; } } import java.lang.reflect.Constructor; import java.lang.reflect.Field; public class ReflectTest { public static void main(String[] args) throws Exception { ReflectPoint rp = new ReflectPoint(3, 5); Field fieldY = rp.getClass().getField( "y"); System. out.println(fieldY.get(rp)); } }
如果想直接通过getField方法获取私有对象,会出现如下错误:java.lang.NoSuchFieldException : x
Field fieldX = rp.getClass().getDeclaredField(“x”);
fieldX.setAccessible(true);
这种方法称之为暴力反射,使用setAccessible(true)使private类型的成员变量也可以被获取。
成员方法的反射:
Method类用于描述类中的成员方法。
得到类中的某一个方法:Method charAt = Class.forName(“java.lang.String”)
.getMethod(“charAt”, int.class);
调用方法:
通常方法:System.out.println(str.charAt(1));
反射方法:System.out.println(charAt.invoke(str, 1));
注意:如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是静态方法!
框架的概念及用反射技术开发框架的原理:
框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
框架程序怎样调用以后写的类呢?很多时候程序无法知道被调用的类名,所以,在程序中无法直接new某个类的实例对象,而要用 反射 方式来做。
public class ReflectTest { public static void main(String[] args) throws Exception { InputStream is = new FileInputStream("config.properties" ); Properties props = new Properties(); props.load(is); is.close(); String className = (String)props.get( "className"); Collection collections = (Collection)Class.forName(className).newInstance(); ReflectPoint pt1 = new ReflectPoint(3, 3); ReflectPoint pt2 = new ReflectPoint(5, 5); ReflectPoint pt3 = new ReflectPoint(3, 3); collections.add(pt1); collections.add(pt2); collections.add(pt3); collections.add(pt1); System. out.println(collections.size()); } } className = java.util.ArrayList //4 className = java.util.HashSet //3
用类加载器的方式管理资源和配置文件:
方式一:采用类加载器进行加载,使用相对路径的方式
InputStream is = ReflectTest.class.getClassLoader().getResourceAsStream
(“com/mytest/config.properties”);
方式二:利用Class方式进行加载,使用相对路径的方式
nputStream is = ReflectTest.class.getResourceAsStream(“config.properties”);
方式三:利用Class方式进行加载,使用绝对路径的方式
InputStream is = ReflectTest.class .getResourceAsStream(“com/mttest/config.
properties”);
Array工具类 用于完成数组的反射操作:
public class ReflectTest { public static void main(String[] args) throws Exception { String[] a1 = new String[]{"a" ,"b" ,"c" }; String a2 = "xyz"; printObject(a1); printObject(a2); } public static void printObject(Object obj){ Class clazz = obj.getClass(); if(clazz.isArray()){ int len = Array.getLength(obj); for(int i = 0; i < len; i++){ System. out.println(Array.get(obj, i)); } } else{ System. out.println(obj); } } }
ArrayList和HashSet的比较及Hashcode分析:
ArrayList Collection collections = new ArrayList( ); ReflectPoint pt1 = new ReflectPoint(3, 3); ReflectPoint pt2 = new ReflectPoint(5, 5); ReflectPoint pt3 = new ReflectPoint(3, 3); collections.add(pt1); collections.add(pt2); collections.add(pt3); collections.add(pt1); System. out.println(collections.size()); Collection collections = new ArrayList(); ReflectPoint pt1 = new ReflectPoint(3, 3); ReflectPoint pt2 = new ReflectPoint(5, 5); ReflectPoint pt3 = new ReflectPoint(3, 3); collections.add(pt1); collections.add(pt2); collections.add(pt3); collections.add(pt1); System. out.println(collections.size()); //4 HashSet: Collection collections = new HashSet(); ReflectPoint pt1 = new ReflectPoint(3, 3); ReflectPoint pt2 = new ReflectPoint(5, 5); ReflectPoint pt3 = new ReflectPoint(3, 3); collections.add(pt1); collections.add(pt2); collections.add(pt3); collections.add(pt1); System. out.println(collections.size()); //3
分析:
由以上两示例可以看到:
当集合为ArrayList时,其实质是一个数组,因此放入4个元素后,集合size为4。
当集合为HashSet时,需要通过比较hashcode值以及equals方法是否返回true决定是否放入。
如果hashcode值相等并且equals方法返回true,那么就不会放入。因此,集合size为3。
如果想让size为2,也就是pt1与pt3作为同一个元素存入HashSet集合,那就需要覆盖ReflectPoint类的hashCode方法以及equals方法。
总结:
反射在本质上就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等,明显反射技术的基石就是其class。所以在以后的编程工作中一定要清晰头脑,做到从字节码中反射出自己的思维。
相关文章推荐
- 黑马程序员_Java反射技术学习总结
- 黑马程序员-Java基础学习-反射技术
- 黑马程序员—Java学习笔记之必须掌握的反射技术
- 黑马程序员学习笔记之八(Java 反射机制)
- 黑马程序员-----java基础二十一(java之反射技术应用(代理))
- 黑马程序员--Java学习分享--希望大家的Java技术更近一步
- 黑马程序员_Java高薪技术之构造方法的反射应用
- 黑马程序员--Java基础加强学习笔记之Class类、反射(Reflect)
- 黑马程序员--java学习之反射总结
- 黑马程序员------java学习笔记之反射
- 黑马程序员java学习日记十 反射
- 黑马程序员java学习<基础加强>—反射
- 【黑马程序员】 学习笔记 - Java新技术 - 反射
- 黑马程序员________Java中IO技术字节流字符流的应用及File类学习笔记
- 黑马程序员——java 反射学习笔记
- 黑马程序员_java学习日记_Java高新技术_反射(一)
- 黑马程序员-----java基础二十(java之反射技术)
- 黑马程序员_Java反射技术(一)
- 黑马程序员_java反射学习
- 黑马程序员------反射的深入学习(No.2)(反射与框架、内省及JavaBaen)