初涉Java反射机制
来源:互联网 发布:昆仑 知乎 编辑:程序博客网 时间:2024/05/29 18:16
1、Class类
1)任何一个类都是(java.lang.)Class的实例,这个实例对象有三个表示对象。如下所示:
public class ClassDemo1 { public static void main(String[] args) { Foo f = new Foo(); //第一种方式:通过类名获得(由这种方式可得任何一个类都有一个隐含的静态成员变量class) Class c1=Foo.class; //第二种方式:通过该类的对象名,用getClass方法获得 Class c2=f.getClass(); //第三种方式:通过 Class.forName("类全称");获得 try { Class c3 = Class.forName("com.java.demo.Foo"); } catch (ClassNotFoundException e) { e.printStackTrace(); } /** * c1、c2表示Foo类的类类型(class type) * 类也是对象,是(java.lang.)Class的实例对象 * 该类的类类型可以创建该类型的对象实例,如通过c1、c2创建Foo的实例 * eg: */ try { Foo foo = (Foo)c2.newInstance();//注意:要用无参数的构造方法才能newInstance() }catch (Exception e) { e.printStackTrace(); } }}class Foo{}
2)Class.forName(“类全名”);不仅表示类的类类型,还代表了动态加载。
3)编译时刻加载的类是静态加载类、运行时加载类是动态加载类。new创建对象是静态加载类,在编译时刻就需要加载所有可能使用到的类。
4)基本的数据类型、void关键字都存在类类型。
eg:
5)Method、Field、Constructor类分别封装了关于方法、成员变量、构造函数的操作。
import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;public class ClassUtils { /* * 获取类的方法信息 */ public static void printClassMethod(Object obj) { System.out.println("-----------打印方法信息------------"); Class c = obj.getClass();// 首先要获取类的类类型 System.out.println("类的名称是:" + c.getName()); /** * Method类,方法对象 一个成员方法就是一个Method对象 * getMethods()方法就是获取所有的public函数,包括父类继承而来的 * getDeclaredMethods()获取的是自己声明的方法 */ Method[] ms = c.getMethods(); for (int i = 0; i < ms.length; i++) { Class returnType = ms[i].getReturnType();// 得到方法的返回值类型的类类型 System.out.print(returnType.getName() + " ");// 打印返回值类型的名称 System.out.print(ms[i].getName());// 得到方法的名称 // 获取参数类型,得到的是参数类表的类型的类类型 Class[] paramTypes = ms[i].getParameterTypes(); System.out.print("("); for (Class class1 : paramTypes) { System.out.print(class1.getTypeName() + ","); } System.out.println(")"); } } /* * 获取类的成员变量信息 */ public static void printClassMenbers(Object obj) { System.out.println("-----------打印成员变量信息------------"); Class c = obj.getClass(); /** * 成员变量也是对象,是java.lang.reflect.Field的对象 Field封装了关于成员变量的操作 * getFields()方法获取的是所有的public的成员信息 getDeclaredFields获取的是该类自己声明的成员变量的信息 */ Field[] fs = c.getFields(); // c.getDeclaredFields() for (Field field : fs) { Class fieldType = field.getType();// 得到成员变量的类型的类类型 String typeName = fieldType.getName();// 得到成员变量的名称 String fieldName = field.getName();// 得到成员变量的名称 System.out.println(typeName + " " + fieldName); } } /** * 构造函数也是对象,是java.lang.Constructor中封装了构造函数的信息 * getConstructors()方法获取到所有public的构造函数 getDeclaredConstructors()得到所有的构造函数 */ public static void printClassConstructor(Object obj) { System.out.println("-----------打印构造函数信息------------"); Class c = obj.getClass(); Constructor[] cs = c.getDeclaredConstructors(); for (Constructor constructor : cs) { System.out.print(constructor.getName() + "(");// 得到构造函数的名称 // 获取构造函数的参数列表,得到的是参数类表的类类型 Class[] paramTypes = constructor.getParameterTypes(); for (Class class1 : paramTypes) { System.out.print(class1.getTypeName() + " " + class1.getName()); } System.out.println(")"); } }}
2、方法的反射操作
1)反射调用一般分为3个步骤:
(1)得到要调用类的类类型(可从上面介绍的3种方式获得)。
(2)得到要调用的类中的方法(Method)。
(3)调用Method的invoke()方法。
eg:
A a = new A();//要获取类中的方法,也就是要获取类的信息,先要获取类的类类型Class c = a.getClass();//获取A类的类类型Method m = c.getMethod("print", int.class, int.class);//获取类的print(int a, int b);方法m.invoke(a, new Object[]{1,2});//也可以写成m.invoke(a, 1,2);
说明:当使用非反射方式调用方法时,是a.print(1,2),即通过类对象调用方法;而反射操作:方法的反射操作时用Method实例对象来进行方法调用,这a.print(1,2)的作用是一模一样的;方法如果没用返回值则返回null,有返回值则返回具体的返回值。
完整例子:
public class MethodReflectDemo { public static void main(String[] args) { A a = new A(); //要获取类中的方法,也就是要获取类的信息,先要获取类的类类型 Class c = a.getClass();//获取A类的类类型 //这个是Method[] ms = c.getMethods();是获取类的所有的public方法,而getMethod()获取的是某一个方法,具体获取哪个方法看getMethod()中传入了什么参数 try { //Method m = c.getMethod("print",new Class[]{int.class, int.class});可以写成: Method m = c.getMethod("print", int.class, int.class);//获取类的print(int a, int b);方法 m.invoke(a, new Object[]{1,2});//也可以写成m.invoke(a, 1,2); Method m1 = c.getMethod("print", new Class[]{String.class, String.class});//获取类的print(String a, String b)方法 m1.invoke(a, "hi","hello");//反射操作,调用方法 Method m2 = c.getMethod("print");//获取类的print()方法;或者写成:Method m2 = c.getMethod("print",new Class[]{}); m2.invoke(a);//反射操作,调用方法;或者写成:m2.invoke(a, new int[]{}); } catch (Exception e) { e.printStackTrace(); } }}class A { public void print(){ System.out.println("haha"); } public void print(int a, int b){ System.out.println(a+b); } public void print(String a, String b){ System.out.println(a + "," + b); }}
3、通过反射了解泛型的本质
java中集合的泛型,是防止错误输入的,只在编译时有效,绕过编译就无效了。
eg:
public class GenericList { public static void main(String[] args) { ArrayList list1 = new ArrayList();//实例一个无泛型的ArrayList对象list1 ArrayList<Integer> list2 = new ArrayList<Integer>();//实例一个Integer型的ArrayList对象list2 list1.add("abc");//在无泛型的list1中添加字符串“abc” list1.add(123);//在无泛型的list1中添加整型数据123 list2.add(123);//在泛型位Integer的list1中添加整型数据123 //list2.add("abc");//在泛型位Integer的list1中添加字符串数据“abc”,Eclipse提示出错 Class c1 = list1.getClass();//获得list1的类类型 Class c2 = list2.getClass();//获得list2的类类型 System.out.println(c1==c2);//打印“true”,说明编译之后集合的泛型是去泛型化的 /** * java中集合的泛型,是防止错误输入的,只在编译时有效,绕过编译就无效了 * 下面进行验证:通过方法的反射来操作,绕过编译 */ try { Method m = c1.getMethod("add",Object.class);//获得ArrayList中的add()方法 m.invoke(list1,11);//list1,反射调用add()方法,为list1添加整型数据 m.invoke(list2, "dfdf");//list2,反射调用add()方法,为list2添加字符串 m.invoke(list2, "dfdf123");//list2,反射调用add()方法,为list2添加字符串 System.out.println(list2.size());//运行后打印"3",说明字符串"dfdf123"插入、list2成功。 } catch (Exception e) { e.printStackTrace(); } }}
说明:本来list2只能存放int型数据的,但由于这里用的是反射操作,就绕过了编译,就绕过泛型,所以list2也能存String类的数据。也就说明了java中集合的泛型,只在编译时有效,绕过编译就无效了。
1 0
- 初涉Java反射机制
- 【反射】JAVA反射机制
- 【Java】JAVA反射机制
- Java 反射机制[Field反射]
- Java 反射机制[Method反射]
- Java反射机制笔记-反射机制
- java的反射机制
- Java的反射机制
- java反射机制详解!
- Java反射机制
- Java的反射机制
- java 反射机制--侯捷
- java反射机制
- java反射机制
- [候捷]Java反射机制
- java 反射机制
- java 反射机制初探
- 关于Java反射机制
- Mac 命令行实例
- UVa 10071 Back to High School Physics
- 常见的字符串,数字转换函数
- 数字基带传输系统——数字基带信号
- 数据结构报告
- 初涉Java反射机制
- FIFO页面置换
- HDOJ(HDU) 1985 Conversions(汇率转换)
- 源代码管理
- 两台服务器建立信任关系(root,普通用户)
- 表达式求值
- CNNs学习笔记(5): CNNs详细理解 Part2
- JSONObject和JSONArray的使用 以及JSONObject put,accumulate,element的区别
- Java位移运算符