关于Java基础的文章,我觉得写得还可以,以前发在了我其它的博客了,肯定是原创,现在再分享给大家出来。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
一、概述
在总结java基础的博客里有简单的写到反射,这里再来深入的理解。http://blog.csdn.net/jin870132690/article/details/41958937
1,定义
首先的问题是什么是反射?百度百科给出的定义是这样的:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
用我自己的话简而言之就是,程序运行时能操纵类的各种成分。
2,反射的基石--class类
java是完全面向对象的语言,在java中万物皆对象,比如男人和女人都可以属于Person类,那么众多的java类是不是也可以用一个类表示呢?
在java中就用一个名为Class的类来表示。
二,获取Class类的三种方式
a,类名.class
b,对象.getClass()
c,Class.forName("类名")
<div style="text-align: left;"> public static void main(String[] args) throws ClassNotFoundException {</div> Date d = new Date(); System.out.println(Date.class);\\a,类名.class <div style="text-align: left;"> System.out.println(Class.forName("java.util.Date"));\\c,Class.forName("类名")</div> System.out.println(d.getClass());\\b,对象.getClass() <div style="text-align: left;"> }</div>
三,获取构造方法
Constructor类代表某类中的一个构造方法。
a,得到某一个构造方法
Class clazz = Class.forName("java.lang.String");
Constructor con = clazz.getConstructor(byte[].class);//得到某一个构造函数
b,得到全部的构造方法
Constructor[] cons = clazz.getConstructors();//得到全部构造函数
四,创建实例对象
使用Constructor.newInstance()方法
1,步骤
a,获取class类
b,获取Gonstructor构造方法
c,调用newInstance()方法.
<div style="text-align: left;">//a,获取class类</div><div style="text-align: left;"> Class clazz = Class.forName("jinfulin.b.bean"); </div> //b,获取Gonstructor构造方法 <div style="text-align: left;"> Constructor cons = clazz.getConstructor(String.class,int.class); </div> //c,调用newInstance()方法. <div style="text-align: left;"> Object obj = cons.newInstance("sf",21); </div>
2,对于无参数构造函数可以简写,但是从底层调用上来看本质是一样的.
<div style="text-align: left;"> Class clazz = Class.forName("jinfulin.p.bean.Person"); </div><div style="text-align: left;"> Object obj = clazz.newInstance();//创建一个新的无参的实例 </div>
五、成员变量的反射
1,方法
Field getField(String s);//只能获取公有和父类中公有
Field getDeclaredField(String s);//获取该类中所有的成员变量,包括私有
setAccessible(true);//对私有字段的访问取消权限检查。暴力访问。
2,举例
<div style="text-align: left;"> //获取字段(属性)</div><div style="text-align: left;"> PointDemo pd = new PointDemo(3,2);</div><div style="text-align: left;"> Field field1 = pd.getClass().getField("x");</div> Object o1 = field1.get(pd); <div style="text-align: left;"> System.out.println(o1);</div>// field1.set(o1, 12); <div style="text-align: left;"> Field field2 = cls2.getDeclaredField("y");</div> Object o2 = cls2.newInstance(); <div style="text-align: left;">// Constructor con2 = cls2.getConstructor(int.class,int.class);</div> field2.setAccessible(true);//暴力反射 field2.set(o2, 12); <div style="text-align: left;"> System.out.println(field2.get(o2));</div>
3,高级应用举例
-- 运用反射,将PointDemo类中的字符串中的所有字符替b换为a.
<div style="text-align: left;">/**</div><div style="text-align: left;"> * 运用反射,将PointDemo类中的字符串中的某一个字符替换掉.</div> * @throws Exception */ <div style="text-align: left;"> private static void changeStringValue() throws Exception {</div> Class cls = Class.forName("cn.jinfulin.day1.Reflect.PointDemo"); <div style="text-align: left;"> for(Field field : fields){</div> Object obj = cls.newInstance(); Field[] fields = cls.getFields(); <div style="text-align: left;"> String newString = oldString.replace('b', 'a');</div> if(field.getType() == String.class){ String oldString = (String) field.get(obj); <div style="text-align: left;"> }</div> field.set(obj, newString); } } <div style="text-align: left;"> System.out.println(obj);</div>
六、成员方法的反射
1,方法
Method[] getMethods();//只获取公有的和父类中的方法。
Method[] getDeclaredMethods();//获取本类中包含私有。
Method getMethod("方法名",参数.class);
Object invoke(Object obj ,参数);//调用方法
如果方法是静态,invoke方法中的对象参数可以为null。
比如
<div style="text-align: left;"><span style="white-space:pre"> </span>public static void main(String[] args) throws Exception {</div><span style="white-space:pre"> </span> <div style="text-align: left;"><span style="white-space:pre"> </span>Object obj = clazz.newInstance();</div><span style="white-space:pre"> </span>Class clazz = Class.forName("java.util.Date"); <div style="text-align: left;"><span style="white-space:pre"> </span> Object returnVaule=me.invoke(obj, null);</div><span style="white-space:pre"> </span> Method me=clazz.getMethod("toString", null); <span style="white-space:pre"> </span> System.out.println(returnVaule); <div style="text-align: left;"><span style="white-space:pre"> </span>} </div>
2,举例:利用反射的方法调用charAt()方法
1)通常方式:str.charAt(1)
2)反射方式:
<div style="text-align: left;"> Method charAtMethod =Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);</div><div style="text-align: left;"> charAtMethod.invoke(str,1);//调用方法</div>
3,用反射执行某个方法中的main方法
java中main方法的参数是一个数组,比如String [] args
但是由于java要兼容1.4版本,直接调用会将数组打散成单独的参数。
解决办法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"});
<div style="text-align: left;"> public static void main(String[] args) throws Exception {</div> Class clazz = Class.forName("Ceshi.Demo.CeshiDemo"); <div style="text-align: left;"> Method mainMethod=clazz.getMethod("main", String[].class); </div> Object obj = clazz.newInstance(); <div style="text-align: left;"> System.out.println(returnVaule); </div> Object returnVaule=mainMethod.invoke(obj, (Object)new String[]{}); <div style="text-align: left;"> }</div>
七、数组中的反射
基本数据类型的一维数组可以当做Object类型使用,不能当做Object[]类型使用,
非基本数据类型的一维数组,既可以当做Object类型使用, 又可以当做Object[]使用。
Array工具类用于完成对数组的反射操作。
Array.getLength(Object obj);//获取数组的长度
Array.get(Object obj,int x);//获取数组中的元素
<div style="text-align: left;"> /**</div><div style="text-align: left;"> * 数组的反射</div> */ <div style="text-align: left;"> private static void printObject(Object obj) {</div> Class clazz = obj.getClass(); <div style="text-align: left;"> int len = Array.getLength(obj);</div> if(clazz.isArray()){//如果是数组,就分行打印 <div style="text-align: left;"> System.out.println(Array.get(obj, i));</div> for (int i = 0; i <len; i++) { } }else{//如果不是就直接打印 <div style="text-align: left;"> }</div> System.out.println(obj); <div style="text-align: left;"> }</div>
八、反射的作用:实现框架
1,概述
框架就像房子,而我们写的类就相当于给房子做装修。
我们在写框架的时候,调用的类还未出现,那么,框架无法知道要被调用的类名,所以在程序中无法直接new其某个类的实例对象,而要用反射来做。
2,工具类与框架区别
工具类被用户类调用,
而框架是调用用户提供的类。
3,四种加载配置文件方法
a,普通方式
FileInputStream in = new FileInputStream("config.properties");
b,类加载器,全写
InputStream in = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/jinfulin/day1/Reflect/config.properties");
c,目录在类文件中,简写(在Java所在文件夹中会自动在类文件夹中创建相同一份)
InputStream in = ReflectTest2.class.getResourceAsStream("config.properties");
d,目录在其它包中,加/回到根目录下在找
InputStream in = ReflectTest2.class.getResourceAsStream("/cn/jinfulin/day1/config/config.properties");
4,举例
<div style="font-family: Arial; font-size: 14px; line-height: 26px; text-align: left;">package cn.jinfulin.day1.Reflect;</div><span style="font-family:Arial;"><span style="font-size: 14px; line-height: 26px;"> import java.io.InputStream; </span></span><div style="font-family: Arial; font-size: 14px; line-height: 26px; text-align: left;">import java.util.Properties;</div><span style="font-family:Arial;"><span style="font-size: 14px; line-height: 26px;">import java.util.Collection; public class ReflectTest2 { </span></span><div style="font-family: Arial; font-size: 14px; line-height: 26px; text-align: left;"> public static void main(String[] args) throws Exception {</div><span style="font-family:Arial;"><span style="font-size: 14px; line-height: 26px;"> //仿照框架,用反射 //1,读取配置文件中的内容 //1.1源:键值对配置文件 </span></span><div style="font-family: Arial; font-size: 14px; line-height: 26px; text-align: left;">// FileInputStream in = new FileInputStream("config.properties");</div><span style="font-family:Arial;"><span style="font-size: 14px; line-height: 26px;">// //1.2三种得到输入流的方法 //a,普通方式 // //b,类加载器,全写 </span></span><div style="font-family: Arial; font-size: 14px; line-height: 26px; text-align: left;">// InputStream in = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/jinfulin/day1/Reflect/config.properties");</div><span style="font-family:Arial;"><span style="font-size: 14px; line-height: 26px;"> //c,目录在类文件中,简写(在Java所在文件夹中会自动在类文件夹中创建相同一份) // InputStream in = ReflectTest2.class.getResourceAsStream("config.properties"); //d,目录在其它包中,加/回到根目录下在找 </span></span><div style="font-family: Arial; font-size: 14px; line-height: 26px; text-align: left;"> in.close();</div><span style="font-family:Arial;"><span style="font-size: 14px; line-height: 26px;"> InputStream in = ReflectTest2.class.getResourceAsStream("/cn/jinfulin/day1/config/config.properties"); Properties pros = new Properties(); pros.load(in); String className = pros.getProperty("className"); System.out.println(className); </span></span><div style="font-family: Arial; font-size: 14px; line-height: 26px; text-align: left;"> PointDemo pd2 = new PointDemo(5, 5);</div><span style="font-family:Arial;"><span style="font-size: 14px; line-height: 26px;"> //2,读取类文件的字节码 Class cls1 = Class.forName(className); Collection collections = (Collection)cls1.newInstance(); // Collection collections = new HashSet(); //3,集合中添加元素 PointDemo pd1 = new PointDemo(3, 3); PointDemo pd3 = new PointDemo(3, 3); </span></span><div style="font-family: Arial; font-size: 14px; line-height: 26px; text-align: left;">}</div><span style="font-family:Arial;"><span style="font-size: 14px; line-height: 26px;"> collections.add(pd1); collections.add(pd2); collections.add(pd3); collections.add(pd1); pd1.x = 12; collections.remove(pd1); System.out.println(collections.size()); } </span></span><div style="text-align: left;"><span style="font-family:Arial;"><span style="font-size: 14px; line-height: 26px;"> </span></span></div>
九、最后
以前写过一篇关于反射的文章,为什么又单独的写一遍?因为我觉得反射比较重要,以后学到了框架更是少不了的用,本篇显然比上一篇写反射的文章要深入多了,但是还不够,因为这些东西都是老师讲给我听,我照葫芦画瓢做出来的,像这些复杂的知识,真正掌握要还需要实践中见识更多的变化与应用场景才行。