最近学习中遇到反射机制,可是老师只是轻描淡写的解释了一通,还是自己查资料补充一下。
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
一、Class类
1、Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性 2、对象照镜子后(反射)可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。 3、对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。 一个 Class 对象包含了特定某个类的有关信息。换句话说:任何类都是Class类的实例对象 4、Class 对象只能由系统建立对象 5、一个类在 JVM 中只会有一个Class实例
二、反射机制
反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。
作用:
在运行时判断任意一个对象所属的类;在运行时获取类的对象;在运行时访问java对象的属性,方法,构造方法等。
反射的特点:
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。
静态编译:在编译时确定类型,绑定对象,即通过。 动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性
反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
举例:一个大型的软件,当程序编译后,发布了,都会在后期不断的更新以完善整个程序,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。 想一下,王者荣耀每次出新英雄或者出新皮肤的时候都会有更新,用户在更新的时候知只是下载一个小的程序包进行安装,而不用重新安装整个王者荣耀游戏,这就是采用动态编译的例子。
反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。
三、Class中实现反射机制的类
java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
四、反射机制获取类有三种方法
在利用反射获取类的对象,对象的属性,方法,构造方法等的时候都需要创建类的类类型
package com.neuedu.reflect;
/*
* 项目名称:Java-Reflect
* @author:wzc
* @date 创建时间:2017年8月28日 下午8:41:29
* @Description:获取类的类类型
* @parameter
* */
public class JavaDemo1 {
public static void main(String[] args) {
//Food的实例对象如何表示
Food food1=new Food();
/*
* Food这个类也是一个实例对象,Class类的实例对象
* 任何一个类都是Class的实例对象,三种表示方式
* 第一种表达方式--->实际上在告诉我们任何一个类都有一个隐含的静态成员class
*/
Class class1=Food.class;
//第二种表示方式,已知该类的对象getClass
Class class2=food1.getClass();
/*
* c1,c2表示了Food类的类类型(class type)
* 任何类都是class类的实例对象
* c1 c2都代表了Food的类类型,一个类只可能是Class类的一个实例对象
*/
System.out.println(class1==class2);
//第三种表达方式
Class class3=null;
try {
class3=Class.forName("com.neuedu.reflect.Food");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(class2==class3);
}
//创建一个Food类
class Food{
public void print(){
System.out.println("hello Food");
}
}
五、创建对象
获取类的类类型以后我们就可以利用类类型创建该类的对象
package com.neuedu.reflect;
/*
* 项目名称:Java-Reflect
* @author:wzc
* @date 创建时间:2017年8月28日 下午8:41:29
* @Description:获取类的类类型
* @parameter
* */
public class JavaDemo1 {
public static void main(String[] args) {
//Food的实例对象如何表示
Food food1=new Food();
/*
* Food这个类也是一个实例对象,Class类的实例对象
* 任何一个类都是Class的实例对象,三种表示方式
* 第一种表达方式--->实际上在告诉我们任何一个类都有一个隐含的静态成员class
*/
Class class1=Food.class;
//第二种表示方式,已知该类的对象getClass
Class class2=food1.getClass();
/*
* c1,c2表示了Food类的类类型(class type)
* 任何类都是class类的实例对象
* c1 c2都代表了Food的类类型,一个类只可能是Class类的一个实例对象
*/
System.out.println(class1==class2);
//第三种表达方式
Class class3=null;
try {
class3=Class.forName("com.neuedu.reflect.Food");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(class2==class3);
//我们可以通过类的类类型创建类的对象实例
try {
Food food2 = (Food) class1.newInstance();
food2.print();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//创建一个Food类
class Food{
public void print(){
System.out.println("hello Food");
}
}
六、获取类的相关信息: 类名,方法名,方法的返回值类型,方法的参数列表
package com.neuedu.Uttil;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/*
* 项目名称:Java-Reflect
* @author:wzc
* @date 创建时间:2017年8月29日 下午1:22:15
* @Description: 1.利用反射打印类的信息
* 2.利用反射打印类的成员变量
* 3.利用反射打印类的构造方法
* @parameter
* */
public class Uttil {
/*
* 打印类的信息,打印类的返回值类型,类类名,参数列表
*
* */
public static void PrintClass(Object obj){
Class cInt=obj.getClass();
System.out.println("类的名称:"+cInt.getName());
/*
* Method类,方法对象
* 一个成员方法就是一个Method对象
* getMethods()方法获取的是所有的public的函数,包括父类继承而来的
* getDeclaredMethods()获取的是所有该类自己声明的方法,
*
* */
Method[] ms=cInt.getMethods();
System.out.println("[类的返回值类型],[类的名称],[类的参数列表]");
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();
for (Class class1 : paramTypes) {
System.out.print(class1.getName()+",");
}
System.out.println(")");
}
}
}
测试一下:
public class JunitTest {
@Test
public void test() {
String string="hello";
//Uttil.PrintClass(string);
}
}
执行结果:
七、获取类的属性
/*
* 成员变量也是对象
* java.lang.reflect.Field;
* Filed类封装了关于成员变量的操作
* getFields()方法获取的是所有的public的成员变量的信息
* getDeclaredFields获取的是该类自己声明的成员变量的信息
*
*
* */
public static void printFieldInfo(Object obj) {
//获取类的成员变量
Class class1=obj.getClass();
Field[] fields=class1.getDeclaredFields();
for (Field field : fields) {
//得到成员变量的类型的类类型
//得到成员变量的类型名
Class fieldType=field.getType();
String typeName=fieldType.getName();
//得到成员变量的名称
String fieldName=field.getName();
System.out.println(typeName+" "+fieldName);
}
}
测试一下:
@Test
public void test() {
Uttil.printFieldInfo(new Integer(1));
}
结果:
八、获取类的构造方法
/*
* 打印对象的构造函数
* */
public static void printConMessage(Object obj){
Class class1=obj.getClass();
/*
* 构造函数也是对象
* java.lang.Contructor中封装了构造函数的信息
* getConstructors获取所有的public的构造函数
* getDeclaredContructors得到所有的构造函数
*
*
*/
Constructor[] ct=class1.getConstructors();
for (Constructor constructor : ct) {
System.out.print(constructor.getName()+"(");
//获取构造函数的参数列表--->得到的是参数列表的类类型
Class[] paramTypes=constructor.getParameterTypes();
for (Class class2 : paramTypes) {
System.out.print(class2.getName());
}
System.out.println(")");
}
}
测试一下:
@Test
public void test() {
String string="hello";
Uttil.printConMessage(string);
}
结果:
九、通过反射来执行对象的方法
package com.neuedu.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/*
* 项目名称:Java-Reflect
* @author:wzc
* @date 创建时间:2017年8月29日 下午6:45:21
* @Description:通过反射执行类的方法
*
* @parameter
* */
public class RunMethod {
public static void main(String[] args) {
Student student=new Student("张三", 25);
//1.要获取方法,首先要获取该方法的类类型,
Class stuClass = student.getClass();
/*
* 2.获取方法、名称和参数列表
* getMethod获取的是public方法
* getDelcaredMethod自己声明的方法
*/
try {
//stuClass.getMethod("getName",new Class[]{})
//stuClass.getMethod("getName");
Method m1=stuClass.getMethod("getName", null);
//3.方法的反射操作-----以前:student.getName();
//m1.invoke(obj,args..); //方法的反射操作是用m1对象来进行方法的调用
//方法如果没有返回值返回null,有返回值返回具体的返回值,并转换成Object
m1.invoke(student);
System.out.println("==============");
m1=stuClass.getMethod("getAge", null);
Object object=m1.invoke(student, null);
System.out.println("==============");
//m1=stuClass.getMethod("getAge", int.class);
m1=stuClass.getMethod("getAge", new Class[]{int.class});
m1.invoke(student, 2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//student类
class Student{
private String name;
private int age;
public Student(){
}
public Student(String name,int age){
this.name=name;
this.age=age;
}
//无参数方法
public void getName(){
System.out.println("name:"+name);
}
//无参数方法
public void getAge(){
System.out.println("age:"+age);
}
//有参数的方法
public void getAge(int num){
System.out.println(num+"年前age:"+(age-num));
}
public void studentIn(){
System.out.println("name:"+name+",age:"+age);
}
}
今天只是记录一些反射最基础的理论,之后会在写一些反射的应用,只有应用了才能更好的理解反射的概念。
转载于:https://www.cnblogs.com/Actexpler-S/p/7450238.html