好贷网好贷款

黑马程序员——Ⅰjava基础加强之反射(13)

发布时间:2016-12-5 16:41:47 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"黑马程序员——Ⅰjava基础加强之反射(13)",主要涉及到黑马程序员——Ⅰjava基础加强之反射(13)方面的内容,对于黑马程序员——Ⅰjava基础加强之反射(13)感兴趣的同学可以参考一下。

---------------------- android培训、.java培训、期待与您交流! ---------------------- 一、反射的概念和用途总述         反射的内容时学习老师视频时遇到的最头疼的问题:跟着视频走,勉强能看懂,走神3秒钟,就得倒回去看;看完视频,啥也不会。         目前为止,我认为反射绝对是高端大气上档次的部分,因为通过百度、参考其他人的文章等,我发现貌似反射只有java有,是独一份的,然后还这么难理解,再然后,看到评论说,用处很少(主要用于开发框架,Andriod也用到)。貌似鸡肋……         反射究竟是做什么用的呢?经过我好几天好几遍的看视频,稍作总结如下:         反射首先是一种动态的思想,不再是硬编码。就是说在使用过程中,外部传入一个类,通过对这个类进行反射,再去按照反射定义者的意图使用这个类。传说中目标类和客户类的关系发生改变。         做个比喻,饭店新请一个厨师,负责人就问他会做什么菜啊、调味品用什么量啊等等,等负责人了解之后就让厨师去做菜了,但是为了适应当地人口味,负责人还可以在下命令之前告诉厨师,少发花椒多放辣等。厨师的主要做菜功能不变,但是负责人可以要求他做一些功能上的调整。         为了让我的文章显得高端大气,特意搜罗一些比较官方的描述语言来对反射进行描述。 反射的作用 反射的作用总结起来就一个:倒转了目标类和客户类的依赖关系。 以前我们设计程序,客户类要么依赖于目标类,要么依赖于目标类的接口。因为目标类是作为工具提供给客户类使用的,根据 java 基本语法规则,要使用某个类,必须知道该类提供的接口。有了反射之后,我们就可以方便是使用反射来实现框架,解除框架对于我们写的类——目标类,的依赖关系。 反射的概念和实现原理 Reflection 是Java被视为动态(或准动态)语言的一个关键性质。反射就是把 JVM 通过符号引用动态解析 java 类的字节码的能力映射成为各种 Java 类的成分类的机制,通过这个机制,java 把 JVM 动态解析符号引用的功能封装为各种 API 类公开给我们使用,这个机制允许我们可以于运行时加载、探知、使用,编译期间完全未知的classes,程序在运行时通过 Reflection APIs 取得任何一个 class 的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括 fields 和 methods 的所有信息,并可于运行时改变该类的对象的 fields 内容或调用该类或者该类对象的 methods。这种动态获取类的信息以及动态调用对象的方法的功能就是Java 语言的反射(Reflection)机制。 二、Java类反射中所必须的类: Java的类反射所需要的类并不多,它们分别是:Class、Field、Constructor、Method、Object,下面我将对这些类做一个简单的说明。 Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。 Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。 Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。 Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。 Object类:每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。 三、详述各个反射类及代码示例其用法 1、Class类 被称为反射的基石的Class类究竟何德何能获得这一殊荣呢?静听分解: 首先,这家伙长得像极了class,我们一直使用的class啊。难道有血缘关系?私生子?八卦之火熊熊燃烧。不过,做学问要严肃!好吧,严肃点 Class和class的区别 1)class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,,不同的实例对象有不同的属性值。 2)Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是Class。 Class获取对象的方法(借鉴toShareBeauty同学的图) Class功能函数代码示例 package cn.itcast.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Type; /** * @class: ReflectionClassDemo * @package: cn.itcast.reflect * @description: TODO * @author: vivianZhao * @date: 2013-7-20 上午10:55:13 * @version: 1.0 */ public class ReflectionClassDemo { public static void main(String args[]) throws Exception { ReflectionClassDemo ref = new ReflectionClassDemo(); ref.getConstructor(); } public void getConstructor() throws Exception { Class<?> c = Class.forName("java.lang.Long"); Class<?> cs[] = { java.lang.String.class }; System.out.println("\n-------------------------------\n"); Constructor<?> cst1 = c.getConstructor(cs); System.out.println("1、通过参数获取指定Class对象的构造方法:"); System.out.println(cst1.toString()); Constructor cst2 = c.getDeclaredConstructor(cs); System.out.println("2、通过参数获取指定Class对象所表示的类或接口的构造方法:"); System.out.println(cst2.toString()); Constructor cst3 = c.getEnclosingConstructor(); System.out.println("3、获取本地或匿名类Constructor 对象,它表示基础类的立即封闭构造方法。"); if (cst3 != null) System.out.println(cst3.toString()); else System.out.println("-- 没有获取到任何构造方法!"); Constructor[] csts = c.getConstructors(); System.out.println("4、获取指定Class对象的所有构造方法:"); for (int i = 0; i < csts.length; i++) { System.out.println(csts[i].toString()); } System.out.println("\n-------------------------------\n"); Type types1[] = c.getGenericInterfaces(); System.out.println("1、返回直接实现的接口:"); for (int i = 0; i < types1.length; i++) { System.out.println(types1[i].toString()); } Type type1 = c.getGenericSuperclass(); System.out.println("2、返回直接超类:"); System.out.println(type1.toString()); Class[] cis = c.getClasses(); System.out.println("3、返回 Class 中使用的所有的类和所有的接口:"); for (int i = 0; i < cis.length; i++) { System.out.println(cis[i].toString()); } Class cs1[] = c.getInterfaces(); System.out.println("4、实现的接口"); for (int i = 0; i < cs1.length; i++) { System.out.println(cs1[i].toString()); } System.out.println("\n-------------------------------\n"); Field fs1[] = c.getFields(); System.out.println("1、类或接口的所有可访问公共字段:"); for (int i = 0; i < fs1.length; i++) { System.out.println(fs1[i].toString()); } Field f1 = c.getField("MIN_VALUE"); System.out.println("2、类或接口的指定已声明指定公共成员字段:"); System.out.println(f1.toString()); Field fs2[] = c.getDeclaredFields(); System.out.println("3、类或接口所声明的所有字段:"); for (int i = 0; i < fs2.length; i++) { System.out.println(fs2[i].toString()); } Field f2 = c.getDeclaredField("serialVersionUID"); System.out.println("4、类或接口的指定已声明指定字段:"); System.out.println(f2.toString()); System.out.println("\n-------------------------------\n"); Method m1[] = c.getMethods(); System.out.println("1、返回类所有的公共成员方法:"); System.out.println(m1.length); for (int i = 0; i < m1.length; i++) { System.out.println(m1[i].toString()); } Method m3[] = c.getDeclaredMethods(); System.out.println("2、返回类自己定义所有的成员方法:"); System.out.println(m3.length); for (int i = 0; i < m3.length; i++) { System.out.println(m3[i].toString()); } Method m2 = c.getMethod("longValue", new Class[] {}); System.out.println("3、返回指定公共成员方法:"); System.out.println(m2.toString()); } } 注:获取Class对象方法图和功能代码示例是直接copy  toShareBeauty同学的博文。借用孔乙己的一句话“读书人的事,不能称为偷”(汗!) 在写博客过程中,我借鉴了好多同学的成果,有的甚至直接粘贴过来,偷懒的同时不得不承认,他们的理解和代码确实很好很经典,尤其这位toShareBeauty同学,通过他的文章清晰地感觉到我和人家不在一个级别。他的文章给我的感觉是对java用过好几年,在有深入体验和经验后写成的,站在了一定的高度,而我则是很吃力的去啃知识。如果有和我一样的初学者看到此处,我强烈建议去看一下他的文章,没有像黑马的老师那么精深,但是恰好接近初学者,更接地气。 2、构造方法的反射应用_Constructor 类 package cn.itcast.day1; import java.lang.reflect.Constructor; public class ConstructorDemo { public static void main(String[] args) throws Exception{ //得到某个类所有的构造方法 Constructor<?>[] constructors = Class.forName("java.lang.String").getConstructors(); //取得指定类的构造方法 Class classType = Class.forName("java.lang.String"); Constructor constructor = classType.getDeclaredConstructor(StringBuffer.class); /*创建实例对象*/ //通常方式: String str = new String(new StringBuffer("abc")); //反射方式 String str1 = (String)constructor.newInstance(new StringBuffer("abc")); //Class.NewInstance()方法 String str2 = (String)Class.forName("java.lang.String").newInstance(); /*该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。该方法的内部用到了缓存机制来保存默认构造方法的实例对象*/ //获得构造方法并创建实例对象 Constructor constructor1 = String.class.getConstructor(StringBuffer.class); /*getConstructor()中用到是不定长度参数,1.4版本之前,则是通过传入数组来调节参数类型和数组不确定的情况*/ String str3 = (String)constructor1.newInstance(new StringBuffer("aaa")); } } 3、成员变量的反射_Field 类 //成员变量的反射 ReflectPoint pt1 = new ReflectPoint(3, 6); //成员变量时共有的可以正常反射 Field filedY = pt1.getClass().getField("y"); System.out.println(filedY.get(pt1)); //如果成员变量是私有的要强行反射getDeclaredField Field fieldX = pt1.getClass().getDeclaredField("x"); //暴力反射修改字段的访问属性的方法方法 setAccessible(true); 这是继承自 java.lang.reflect.AccessibleObject 的方法 fieldX.setAccessible(true); //获取 System.out.println(fieldX.get(pt1)); 练习:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a" import java.lang.reflect.Field; public class Reflectest { public static void main(String[] args) throws Exception { ReflectPoint pt1=new ReflectPoint(); changeStringValue(pt1); System.out.println(pt1); } private static void changeStringValue(Object obj) throws Exception{ Field[] fields=obj.getClass().getFields();//获取所有的成员变量 //遍历成员变量 for(Field field:fields){   //比较字节码用== if(field.getType()==String.class){ String oldValue=(String)field.get(obj);//获取obj的String类型的成员变量 String newValue=oldValue.replace('b', 'a');//将b换成a field.set(obj, newValue);//将此 Field表示的字段设置为指定的新值 } } } } class ReflectPoint { public String str1="ball"; public String str2="basketball"; public String str3="itcast"; //重写toString方法 public String toString(){ return str1+" "+str2+" "+str3+" "; } } 4、成员方法的反射_Method类 得到类中的某一个方法: 例子: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);  调用方法: 通常方式:System.out.println(str.charAt(1)); 反射方式: charAt.invoke(str, 1);  如果传递给 Method 对象的 invoke() 方法的第一个参数为 null,说明该 Method 对象对应的是一个静态方法。  jdk1.4和jdk1.5的invoke方法的区别: jdk1.5:public Object invoke(Object obj,Object... args) jdk1.4:public Object invoke(Object obj,Object[] args),按 jdk1.4的语法,需要将一个数组作为参数传递给 invoke 方法,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用 charAt 方法的代码也可以用 jdk1.4 改写为 charAt.invoke(“str”, new Object[]{1}) 形式。 package cn.itcast.day1; import java.lang.reflect.Method; public class MethoDemo { public static void main(String[] args) throws Exception { Sring className = args[0]; Method method = Class.forName(className).getMethod("main", String[].class); method.invoke(null, (Object)new String[]{"aaa","bbb","ccc"}); /* * 如果按照一般写法,传递参数应该是这样: * method.invoke(null, new String[]{"aaa","bbb","ccc"}); * 但是由于jvm自动拆包,会将String数组当作三个参数传入,这个main方法中只接受一个String[]不符,编译器会报错,所以有两种解决方案。 * 其一:像上述程序中所写的那样,在前面加上强制类型转换,告诉编译器这是一个整体,不要拆包 * 其二:可以这样写——method.invoke(null, new Object[]{new String[]{"aaa","bbb","ccc"}}); * 定义一个Object类型数组,并将String[]整体作为一个元素放入数组中,编译器拆包后得到的便是一个String[]类型参数。 */ } } class Test{ public static void main(String[] args){ for (String str : args){ System.out.println(str); } } } 5、数组与Object类的关系及其反射类型 /** * 需求:演示数组 和 Object 的关系 * * 思路: * 1.获取数组的 Class 对象,比较是否相等 * 2.打印数组的 Class 对象的名字 * 3.数组 和 Object 类型之间的类型转换 * * 步骤: * * 总结: * 1.java 里面,相同元素类型和相同维度数的数组是同一个类型的数组,对应同一个 Class 对象 * 2.数组类型的签名是" [ + 元素类型名签名 ",如果是多维数组,也是符合前面的规则,结果就成了几维数组会有几 * 个" [ "符号 * 3.数组类型可以向上转型为 Object 类型 * 4.java 语言中没有多维数组,其实都是一维数组,所谓多维数组,是数组中的元素还是数组,只有最后一层是一个非 * 数组类型 */ package cn.itcast.reflect; public class ArrayAndObject { public static void main(String[] args) { // TODO Auto-generated method stub int [] a1 = new int[4]; int [] a2 = new int[5]; int [][] a3 = new int[2][3]; String [] a4 = new String[3]; // 返回 true,说明同类型同维度的数组是同一个 Class 对象 System.out.println(a1.getClass() == a2.getClass()); // 不可比较,说明同类型不同维度的数组不是同一个 Class 对象 //System.out.println(a1.getClass() == a3.getClass()); // 不可比较,说明不同类型同维度的数组不是同一个 Class 对象 //System.out.println(a1.getClass() == a4.getClass()); // 数组类型的名称是 [ + 类型名签名,如果是多维数组,几维数组用几个 [ System.out.println(a1.getClass().getName()); System.out.println(a3.getClass().getName()); System.out.println(a4.getClass().getName()); // 数组类型的父类型都是 Object 类型 System.out.println(a1.getClass().getSuperclass().getName()); System.out.println(a3.getClass().getSuperclass().getName()); // 数组类型的父类都是 Object 类型,所以数组类型可以上转为 Object 类 Object aObject1 = a1; Object aObject2 = a4; // 数组中的元素有两种类型,一种是基本类型,一种是引用类型 //Object[] aObjects3 = a1; // 数组类型的类型匹配需要匹配两个地方,第一个是否是数组,第二个数组中的元素类型的匹配 // Object [] aObject4 定义了一个 ,一维数组,其中数组中的元素是 Object 类型 // a3 是定义了一个一维数组A,数组中的元素是 一维数组B,一维数组B中的元素是 int 类型,一维数组B可以 // 向上转型为 Object 类型,所以可认为 Java 语言中没有多维数组,其实都是一维数组,所谓多维数组,是 // 数组中的元素还是数组,只有最后一层是一个非数组类型 Object[] aObject4 = a3; Object[] aObject5 = a4; } } Arrays.asList()方法处理 int[] 和 String[] 时的差异 int [] a11 = new int[]{1, 2, 3}; String [] a12 = new String[]{"a", "b","c"}; System.out.println(Arrays.asList(a11)); // 这说明数组中的元素向上转型的时候不会进行自动装箱拆箱 // 自动装箱拆箱只会在运算符表达式中进行 //System.out.println(Arrays.asList((Integer [])a11)); System.out.println(Arrays.asList(a12)); 打印结果为: [[[email protected]] [a, b, c] 这是因为 Arrays 类的 asList 方法在 jdk1.5 和 jdk1.4 中不同, jdk1.5 :static <T> List<T> asList(T... a)  jdk1.4:public static List asList(Object[] a)   jdk1.5 为了兼容 jdk1.5 而首先按照 jdk1.4 的类型运行,所以把 int[] 当做一个 Object 对象,把 String[] 当做一个 Object[] 对象。 四、框架简述 因为没有接触过实际的开发,感觉框架有点虚,很空洞。 简单讲一下目前对框架的理解 前面说到java的反射主要用途是框架,这个框架指的就是我先定义好一个程序,但是程序中间用反射来动态调用后期使用本程序人员传入的程序或参数等,然后再执行本程序的主体。 举个例子,比如小32 今天请PLMM去玩,主体程序当然由我来完成,比如引导MM吃饭、逛街、增进感情……但是中午吃饭,事先不知道去哪里吃,所以也不知道厨师会做什么菜,但是到了一家餐厅,我就可以点菜,具体的菜点好以后由厨师去做;吃饱了去看电影,到了影院具体的影片播放由技术人员去完成……这么看来,我就是那个框架,中间的做饭、放电影等是有我调用的厨师、技术人员来完成。 总结:反射部分的知识目前所了解,用途不是很广,也比较难以理解,但是我可以感觉到,反射的作用很大(作用大和用途不广不矛盾),当需要的时候,会非常省时省力,也非常有效率,非常有必要学透彻。   黑马能给我我需要的,所以,黑马,我来了!                                                                                               ——爱编程,爱黑马,我是快乐的小32   ---------------------- android培训、.java培训、期待与您交流! ---------------------- 详细请查看:http://edu.csdn.net

上一篇:qt-embedded-linux移植要点qt
下一篇:解决问题:Can't compile Java with Sublime Text 2, Ubuntu 12.04 64

相关文章

相关评论