java反射---高级开发必须要懂的入门知识
来源:互联网 发布:vr视频软件 编辑:程序博客网 时间:2024/04/30 10:14
java反射说的是一套反射机制,通过这套机制我们可以访问已经装载到JVM(java虚拟机的简称)里面的某个java对象,还可以进行检测以及修改这个对象本身的信息。可以说反射机制的功能是非常强大的,在java.lang.reflect包下的类支持了这些功能。
说到反射我们绕不开的一个类Class,它到底是什么?
其实在面向对象的世界里万事万物都是对象,类也不例外;所有运行的java虚拟机中的类都是Class类的对象。
类也是对象,类是java.lang.Class类的实例对象。
知道了这个Class类的某个对象(注意这个对象是某个类,可以是java的jdk中自带的类,也可以是我们创建的类,),通过这个对象,我们就可以知道由它创建的某个实例对象的的基本信息。这个就是反射机制的直接表现形式。这样说可能有一点拗口,下面举个例子:
比如有一个类 public class A {},通过 A a=new A();我们创建了A类的一个对象 a;
Class clz=a.getClass();//这样就获得Class类的某个对象 clz //下面通过反射机制操作这个clz,我们就可以获得实例对象a的一些基本信息:比如方法,构造方法,属性,方法参数党法修饰符等
上面只是谈了一下我对反射机制的的一般理解,不知道我说明白了?下面通过代码学习一下
1.首先如何获取Class类的对象?有如下三种方式;
package com.csdn;class Person {}//Person类public class T { public static void main(String[] args) throws ClassNotFoundException { Person mPerson = new Person(); // 第一种方式(任何类里面都有一个隐含的静态成员变量class) Class p1 = Person.class; // 第二种方式(已经知道了Person类的一个对象,比如上面mPerson) Class p2 = mPerson.getClass(); // 第三种方式(Class.forName("类的全称"),会抛异常) Class p3 = Class.forName("com.csdn.Person"); System.out.println(p1 == p2);// 结果为true System.out.println(p2 == p3);// 结果为true }}
上面也打印了p1,p2和p3的堆内存比较结果都为true,结果证明他们都是同一个;
结果同样也说明:
Class类的某个对象(类)也是唯一的。
上面三种方式,不管是通过哪一种得到的Person类都是同一个,这也很好理解,因为在JVM中我们的类只可能是一个,不会存在两个一模一样的类;
2.介绍一下反射有关的几个类,当然有很多,这里只列举几个常见的;
Field类:用于操作类中的属性
Method类:用于操作类中的方法
Constructor类:提供单个构造方法的信息
Modifier类:用于解码访问修饰符(类和成员变量的访问修饰符),这个类里面全是整型常量。每个常量表示一个访问修饰符。
3.通过反射调用方法,这里要使用到Method类(方法对象),一个成员方法就是一个Method的实例对象。
为上面的Person类添加一个方法
class Person { private int height; private int addHeight(int a) { height = a + 1; return height; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; }}
下面通过Method类来进行操作,还是接着使用p1
Class<?> p1 = Person.class; /**getDeclaredMethods()获取的是本类自己声明的所有方法信息*/ Method[] mds = p1.getDeclaredMethods(); System.out.println("得到全部方法信息: "); for (int i = 0; i < mds.length; i++) { /**得到方法的访问修饰权限*/ int mModify = mds[i].getModifiers(); // Modifier类里面是所有修饰符的整形常量信息 // 比如此处 public static final int PRIVATE =0x2 代表 private // 使用Modifier.toString()方法可以将整形转化为String类型的修饰符private System.out.print(Modifier.toString(mModify) + " "); // 得到方法的返回值类型 Class<?> mReturnType = mds[i].getReturnType(); System.out.print(mReturnType.getName()); // 得到方法的名称 String mMethodName = mds[i].getName(); System.out.print(" " + mMethodName); // 获取方法的参数类型 Class<?>[] mParamType = mds[i].getParameterTypes(); System.out.print("("); // 说明当前这个方法里面没有参数类型 if (mParamType.length == 0) System.out.println(")"); for (Class<?> mClass : mParamType) { // 获取参数类型的名称 System.out.print(mClass.getName()); System.out.println(")"); } }
打印的结果如下:
/**得到全部方法信息:*/ public void setHeight(int)public int getHeight()private int addHeight(int)
这里可以看到正好就是上面我们声明的Person类里面的三个方法,通过Method类我们可以很好的获取方法信息。其实我们还可以通过Method类来调用这个方法,这里方法是private修饰的不可以使用对象对象直接调用,利用反射可以轻松做到;比如我给 private int addHeight(int a) 方法传一个实参值是2,操作如下:
Class<?> p1 = Person.class;Person mPerson = new Person();//获取到某一个特定的方法对象,第一个传进去的是方法的名称,后面传入形式参数的Class类型Method md = p1.getDeclaredMethod("addHeight", int.class);//首先要获得访问的权限,打破封装md.setAccessible(true);// 调用invoke方法来调用方法第一个是Person类的对象,第二个是传递的参数int returnValue = (Integer) md.invoke(mPerson, 2);//retrunValue是addHeight(int a)方法返回的结果System.out.println("返回值: " + returnValue);System.out.println("通过mPerson得出的结果:"+mPerson.getHeight());
打印结果是
返回值: 3通过mPerson得出的结果:3
4,使用Field类来操作属性 一个Field类实例代表一个成员变量
Class<?> p1 = Person.class; System.out.println("得到的属性是 : "); /** 得到本类声明的所有属性*/ Field[] mFields = p1.getDeclaredFields(); for (int i = 0; i < mFields.length; i++) { // 得到变量的访问修饰权限 System.out.print(Modifier.toString(mFields[i].getModifiers()) + " "); /**得到属性的类型*/ System.out.print(mFields[i].getType().getName() + " "); // 得到属性的名称 System.out.println(mFields[i].getName()); }
打印的结果:
得到的属性是 : private int height
当然同方法类似,通过Field也可以来直接为变量赋值的
Class<?> p1 = Person.class; Person mPerson = new Person(); // 获取本类声明的特定的属性,参数传入变量名称 Field mField = p1.getDeclaredField("height"); // 还是要设置一下访问权限,这步是必不可少的 mField.setAccessible(true); // 通过setInt为对象的height属性赋值为2,因为是int型所以使用setInt mField.setInt(mPerson, 2); System.out.println("mPerson的height属性值是:" + mPerson.getHeight());
打印结果:
mPerson的height属性值是:2
5,使用Constructor类来操作构造方法 一个Constructor类实例代表一个构造方法对象
再为Person类添加如下构造方法
public Person() { super(); } private Person(int height) { super(); this.height = height; }
下面使用Constructor类来操作构造方法 ,接着用p1
Class<?> p1 = Person.class; System.out.println("得到的构造方法:"); /**获取本类声明的所有构造方法*/ Constructor<?>[] mCons = p1.getDeclaredConstructors(); for (int i = 0; i < mCons.length; i++) { /** 获取构造方法的访问修修饰符*/ System.out.print(Modifier.toString(mCons[i].getModifiers()) + " "); System.out.print(mCons[i].getName()); // 得到构造方法的参数类型 Class<?>[] mConsClass = mCons[i].getParameterTypes(); System.out.print("("); for (Class<?> css : mConsClass) { System.out.print(css.getName()); } System.out.println(")"); }
打印的结果:
得到的构造方法:public com.csdn.Person()private com.csdn.Person(int)
当然了通过Constructor也可以创建Person类的对象
Class<?> p1 = Person.class; Constructor<?>[] mConstructs = p1.getDeclaredConstructors(); System.out.println(mConstructs.length); for (int i = 0; i < mConstructs.length; i++) { if (i == 0) {// 是无参的构造方法 Person person1 = (Person) mConstructs[i].newInstance(); System.out.println("打印无参的构造方法中的Height的值:"+person1.getHeight()); } else if (i == 1) {// 是有参的构造方法 mConstructs[i].setAccessible(true); Person person2 = (Person) mConstructs[i].newInstance(2); System.out.println("打印无参的构造方法中的Height的值:"+person2.getHeight()); } }
打印结果如下:
打印无参的构造方法中的Height的值:0打印无参的构造方法中的Height的值:2
说明一下:p1.getDeclaredConstructors()得到的数组中构造方法的顺序是按照,构造方法在Person类中的声明顺序排列的,因为Person类中 先是无参,后是有参,
所以得到的数组中 第一个元素是表示无参构造方法,第二个元素是有参的构造方法
上面写法不科学,这里只是为了演示,我知道Person只有两个构造方法,才这样写的。
第二个因为不是public修饰的构造方法,所以要使用setAccessible来打破访问权限.
到这里反射机制基础知识也就介绍完了,希望对大家有所帮助,有些地方可能写的也不是很好,有错误地方请指正!
- java反射---高级开发必须要懂的入门知识
- java web开发入门必须要了解的基本知识
- 成为Java架构师必须要懂的知识
- Java架构师必须要懂的知识(一)
- java中必须要掌握的知识
- 【Android高级】应用开发必须要掌握的框架<Volley>
- 高级Java程序员必须要会的知识点
- 嵌入式开发必须要懂的
- 嵌入式工程师必须要懂的知识之-------存储器
- 网站优化必须要掌握的知识
- C++中必须要知道的知识
- C++中必须要知道的知识
- 初高中必须要掌握的知识
- java反射--高级开发必须懂的
- Linux驱动开发之 二 (那些必须要了解的硬件知识 之 处理器篇)
- Linux驱动开发之 三 (那些必须要了解的硬件知识 之 存储器篇)
- Linux驱动开发之 四 (那些必须要了解的硬件知识 之 串口)
- Linux驱动开发之 五 (那些必须要了解的硬件知识 之 I2C)
- 安卓 .9图片处理讲解
- Android动画机制全解析
- 从本篇文章开始和我一起学习《意志力》这本书吧
- GIS+=地理信息+云计算技术——私有云架构设计(5)云安全规划
- 数据结构(3)--线性表实现一元多项式加法
- java反射---高级开发必须要懂的入门知识
- enum在C语言中的使用
- [BZOJ 2194] 快速傅立叶之二 · FFT
- 进程基础的一些相关函数
- ”google play 服务”(Google play services) 如何安装
- jQuery对radio,checkbox,select元素的操作
- execl家族函数总结
- 嵌入式linux文件系统相关
- ubuntu14.04安装caffe+digits