Java开发——反射机制
来源:互联网 发布:月薪8000能招到java 编辑:程序博客网 时间:2024/06/04 23:32
前言:
在面向对象的世界里,万事万物皆对象。但是在java语言中,静态的成员、普通数据类型除外,静态成员属于类,而不是对象,而普通数据类型有对应的包装类来弥补它。类是不是对象呢?类是(哪个类的对象呢?)谁的对象呢?类是对象,类是java.lang.Class类的实例对象
一、反射的概念:
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!
只看概念会几乎毫无感觉,通俗的讲可以这样理解:
反射的过程认为是将.class文件(也就是字节码文件)反编译为.java文件(Java源文件)。然后利用反射机制来得到类的属性、方法、构造方法。
二、Class类是什么:
一下通过代码来演示:
Test test = new Test(); //官网说,以下三种方式c1 ,c2 ,c3表示了Test类的类类型(class type) //任何一个类都是Class的一个实例对象,这个实例对象就是类类型 // 这个实例对象有三种表示方式: //第一种表示方式:这是实际在告诉我们,任何一个类都有一个隐含的静态成员变量class; Class c1 = Test.class; //第二种表示方式:已经类的实例,通过类的实例来获取Class的实例对象 Class c2 = test.getClass(); //第三种表示方式: try { Class c3 = Class.forName("Test"); } catch (ClassNotFoundException e) { e.printStackTrace(); } //结果是true,表明不管使用哪一种方式,一个类只能是Class类的一个实例对象 System.out.println(c1==c2);//true System.out.println(c1==c2);//true //我们可以通过类类型,创建该类的实例对象 //即我们可以通过c1,c2,c3,来创建Test类的实例对象 try { Test test1 = (Test)c1.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }
三、java 动态加载类
上面提到的第三种方法,Class.forName(“类的全称”),不仅表示了类的类类型,还代表了动态加载类。
我们一定要区分编译、运行编译时刻加载类是静态加载类、运行时刻加载类是动态加载类。
下面演示一个Java动态加载类的简单实例:
我们创建一个接口Subject,表示考试科目,并创建两个科目Mathmatic和Physics来实现Subject接口。
package com.tong.reflect;public interface Subject { void printGrade();//打印该科目成绩}
package com.tong.reflect;public class Mathmatic implements Subject { @Override public void printGrade() { System.out.println("打印数学成绩"); }}
package com.tong.reflect;public class physics implements Subject { @Override public void printGrade() { System.out.println("打印物理成绩"); }}
然后就可以利用Java反射机制来动态加载类,并创建类的实例。在后续过程中如果还需要增加科目,只要实现Subject接口,并编译为字节码文件。一下为测试代码:
public static void main(String[] args) { try { //动态加载类 Class c1 = Class.forName(args[0]); //动态创建类的实例 Subject subject = (Subject) c1.newInstance(); subject.printGrade();//打印成绩 } catch (ClassNotFoundException e) { e.printStackTrace(); }catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }
四、通过Java反射获取类的成员变量、方法、构造函数
定义类ClassUtils用来获取类的方法:
public class ClassUtils { /* 获取类的方法 */ public void printMethod(Object obj){ Class cl = obj.getClass(); System.out.println("打印类的名称:" + cl.getName()); /* getMethods()获得的是类的所有的public方法,包括从父类继承来的方法 getDeclaredMethods()获取的是自己声明的方法,不问访问权限 */ Method[] method = cl.getMethods(); for(Method m:method){ Class returnType = m.getReturnType(); //打印返回值类型 System.out.print(returnType.getName() + " "); //打印方法名 System.out.print(m.getName() + "("); Class[] parameterType = m.getParameterTypes(); for(int i = 0;i<parameterType.length;i++){ if(i==parameterType.length-1) System.out.print(parameterType[i].getName()); else System.out.print(parameterType[i].getName() + ","); } System.out.println(");"); } } /* 获取类的成员变量 */ public void printField(Object obj){ Class cl = obj.getClass(); System.out.println("获取类" + cl.getName() + "的成员变量:"); Field[] fields = cl.getFields(); for(Field f:fields){ Class type = f.getType(); System.out.println(type.getName() + " " + f.getName()); } } /* 获取类的构造方法 */ public void printConstructor(Object obj){ Class cl = obj.getClass(); System.out.println("获取类" + cl.getName() + "的构造方法:"); Constructor[] constructors = cl.getDeclaredConstructors(); for(Constructor con:constructors){ System.out.print(con.getName() + "("); Class[] parametertype = con.getParameterTypes(); for(Class para:parametertype){ System.out.print(para.getName() + ","); } System.out.println(")"); } }
测试:
public static void main(String[] args) { ClassUtils classUtils = new ClassUtils(); try { //打印类中的方法 classUtils.printMethod(new Integer(1)); classUtils.printField(new Integer(1)); classUtils.printConstructor(new Integer(1)); } catch (Exception e) { e.printStackTrace(); } }
运行结果:
打印类的名称:java.lang.Integerint numberOfLeadingZeros(int);int numberOfTrailingZeros(int);int bitCount(int);boolean equals(java.lang.Object);。。。省略。。。。获取类java.lang.Integer的成员变量:int MIN_VALUEint MAX_VALUEjava.lang.Class TYPEint SIZEint BYTES获取类java.lang.Integer的构造方法:java.lang.Integer(int,)java.lang.Integer(java.lang.String,)
五、方法的反射
即通过反射来运行类中的方法。
方法反射的操作
method.invoke(对象,参数列表)
public class A { //调用无参数的print public void print(){ System.out.println("输入参数为空。。。。。"); } //调用输入为整形的print public void print(int a,int b){ System.out.println("输入参数为:" + a + " " + b); } //调用输入参数为字符串的print public void print(String a,String b){ System.out.println("输入参数为:" + a + " " + b); }}
测试代码:
public static void main(String[] args) { A a = new A(); Class cl = a.getClass(); Method m = null; Object obj = null; try { //调用无参数的print m = cl.getMethod("print",new Class[]{}); obj = m.invoke(a,new Object[]{}); //调用输入为整形的print m = cl.getMethod("print",new Class[]{int.class,int.class}); obj = m.invoke(a,new Object[]{1,2}); //调用输入参数为字符串的print m = cl.getMethod("print",new Class[]{String.class,String.class}); obj = m.invoke(a,new Object[]{"Hello","World"}); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }
六、通过反射来认识泛型的本质
Java泛型是JDK 5引入的一个特性,它允许我们定义类和接口的时候使用参数类型,泛型在集合框架中被广泛使用。Java中泛型是防止错误输入的,永远记住,泛型是一个编译时的概念,只在编译阶段有效,绕过编译泛型就无效了,来看下面的代码。
若是往list1中添加String类型元素,就会编译报错,如下代码:
ArrayList<Integer> list1 = new ArrayList<Integer>(); list1.add(100); list1.add(200); //此时如果往list1中添加String类型,就会报错,编译不通过 //list1.add("Hello"); ArrayList<String> list2 = new ArrayList<String>(); list2.add("AAAA"); list2.add("BBBB"); list2.add("CCCC");
但是执行下语句时,发现list1和list2竟然指向同一个类类型。说明一个类只对一个类类型。
//输出为trueSystem.out.println(list1.getClass()==list2.getClass());
当通过反射机制来运行方法,就可以往声明为存放Integer类型的ArrayList中存放String类型数据。即绕过了编译就绕过了泛型
ArrayList<Integer> list1 = new ArrayList<Integer>(); list1.add(100); list1.add(200); //此时如果往list1中添加String类型,就会报错,编译不通过 //list1.add("Hello"); ArrayList<String> list2 = new ArrayList<String>(); list2.add("AAAA"); list2.add("BBBB"); list2.add("CCCC"); Class cl = list1.getClass(); try { Method m = cl.getMethod("add",new Class[]{Object.class}); Object obj = m.invoke(list1,new Object[]{"Hello"}); System.out.println("list1的大小:"+list1.size()); System.out.println("list1的内容:"+list1); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }
运行结果:
list1的大小:3list1的内容:[100, 200, Hello]
- Java开发——反射机制
- Java—反射机制
- JAVA——反射机制
- java——反射机制
- Java——反射机制
- java原理—反射机制
- Java基础—反射机制
- java原理—反射机制
- iOS开发—巧用反射机制
- Java学习—— Java反射机制
- java基础知识—Java中的反射机制
- Java反射机制——反射的介绍(一)
- Java———反射机制
- java之反射机制——invoke。
- java反射机制——解析
- JAVA加强——反射机制
- 黑马程序员——Java 反射机制
- JAVA高新技术——反射机制Reflection
- Spring配置文件<context:property-placeholder>标签使用
- BZOJ 2079 [Poi2010]Guilds 巧解
- nltk练习题
- Binary Search:658. Find K Closest Elements
- 2017.10.22 诸神眷顾的幻想乡 失败总结
- Java开发——反射机制
- 数组或列表切分
- HashCode()方法
- 序列化以及反序列化
- Android studio自动生成布局代码
- 一些比较好的论文集合链接
- DialogFragment实现DatePicker
- 基于UE4+ OpenCV 的混合现实 (webCamera, mix-reality, blue screen matting)
- 高精度阶乘