浅谈JAVA中反射机制

在学习java中的反射机制之前,我们必须先了解两个问题(小伙伴们现在不能完全明白没关系,后面我会一个一个详细的和大家分享我的理解).

1.什么是反射?

    Reflection,翻译为映像,反射。JAVA反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

2.为什么需要反射?

    程序在运行时,允许改变程序的结构或变量的类型,具有这种特性的语言被称为动态语言,如Python,Ruby等,正是由于java中反射机制的存在,使java被视为准动态语言,极大扩展了java的功能与操作,具有反射机制的java具有以下几种特殊的功能。

    a.只要给定类的全名,即可通过反射获取类的所有信息。

    b.反射可以在程序运行时获取任意一个对象所属的类对象。

    c.在运行时可以获取到类中的所有属性,并对其进行操作。

    d.在运行时可以获取到类中,父类中的所有方法,并调用。

    鉴于拥有反射机制的java如此强大,目前主流的框架如Struts2,Hibernate,Spring等框架的核心全部离不开java反射的影子。

在我们有了这两个概念之后,我们就可以进行真正的学习了!

1.Class类

    java语言中,除了静态的成员,普通数据类型不是对象以外,其它的都是对象,既然如此,那么类又是谁的对象呢?没错,正如我们的标题,java中的类都是java.lang.Class类的对象。

1.1 类类型的三种表示方式

   当我们实例化一个普通对象时,我们通常这样做:

  T a = new T();
     我们是否可以类比普通对象的实例化来实例Class对象呢,答案是不能,看了Class的源代码就很容易理解这个原因(构造函数是私有的):

    /*
     * Private constructor. Only the Java Virtual Machine creates Class objects.
     * This constructor is not used and prevents the default constructor being
     * generated.
     */
    private Class(ClassLoader loader) {
        // Initialize final field for classLoader.  The initialization value of non-null
        // prevents future JIT optimizations from assuming this final field is null.
        classLoader = loader;
    }

那么我们该怎么办呢,不用担心,这里至少有三种表示方式

Class c1 = T.class;
这种方式我们也能看出,任何一个类都有一个隐含的class成员变量。

第二种是已知一个类的实例化对象,通过这个对象的getClass()方法.

Class c2 = a.getClass();

第三种是通过类的全路径来获取。

Class c3 = Class.forName("com.example.T");

说明:

c1/c2/c3是T的类型,T是a的类型。c1/c2/c3也称作为T的class type.

一个T只能有一个类型,既c1 == c2为true.

同时,也可以通过class type来获取相应类的实例(为了使逻辑清晰,异常处理我都全部省略了),但它的前提是必须要有无参数的构造方法。

T b = (T)c1.newInstance();
1.2 基本数据的类类型(type class)

    同理,基本数据类型也具有相应的type class,如:

Class f1 = int.class;
Class f2 = String.class;
Class f3 = double.class;
Class f4 = Double.class;
注意, 这里的f3和f4不同,一个是基本类型的type class,一个是包装器类型的type class.

2.Method类

    java.lang.reflect.Method类是用于表示类中,接口中方法对象的类,通过它可以操作类中私有,以及公有的全部方法。它的几个重要方法如下:


package com.example.xw;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class TestClass {
	/**
	 * 打印类的信息,包括类的成员函数,成员变量
	 * @param ob该对象所属类的信息
	 */
	public static void show(Object ob){
		
		//要获取类的信息,首先要获取类的class type.
		//传递的是哪一个子类的对象,c1就是该子类的class type。
		Class c1 = ob.getClass();
		
		//获取类的名称
		System.out.println("类的名称 : " + c1.getName());
		
		/**
		 * Method类,方法对象
		 * 一个成员方法就是一个Method对象
		 * getMethods()方法获取的是所有的public函数,包括从父类继承来的
		 * getDeclaredMethods()获取的是所有该类自己声明的方法,所有访问权限的都能获得到
		 */
		Method[] me = c1.getDeclaredMethods();
		
		for(int i = 0; i < me.length ; i ++){
			
			//得到方法的修饰符
			System.out.print(Modifier.toString(me[i].getModifiers()) + " ");
			
			//得到方法的返回值类型的class type
			Class returnType = me[i].getReturnType();
			
			//得到方法的返回值类型
			System.out.print(returnType.getName() + " ");
			
			//得到方法的名称
			System.out.print(me[i].getName() + "(");
			
			//获取参数类型
			Class[] paramTypes = me[i].getParameterTypes();
			for(Class class1 : paramTypes){
				System.out.print(class1.getName() + ",");
			}
			
			System.out.println(")");
			
			
		}
} 
在演示一下获取方法后并调用,

//该方法用于使用传递过来的实体对象获取其中的方法并调用
	public static void showUse(Object ob){
		Class c1 = ob.getClass();
		try{    //getMethod()的第一个参数是调用的哪一个函数,第二个参数是那个函数的
			//参数的class type.
                        Method me1 = c1.getMethod("getName",null);
                        //利用ob对象调用该方法,第二个参数为传递给函数的参数
                        me1.invoke(ob,new Object[]{});
			Method me2 = c1.getMethod("setName",String.class);
			me2.invoke(ob,"西游记");
                        //多参数调用                       
                        Class[] clll = {String.class , int.class};
			Method me3 = c1.getMethod("show",clll);
                        //Method me3 = c1.getMethod("show",new Class[]{String.class,int.class});                       
                        Object[] ooo = {"a",2};
			me3.invoke(ob,ooo);
		}catch(Exception e){
			e.printStackTrace();
		}
	}

3.Field类

    java.lang.reflect.Field类,是用于表示类中、接口中属性对象的类,可以操作类中私有的,以及公有的全部属性。


该方法用于使用传递过来的Class对象获取类中的属性

	
	public void show(Class c1){
		
                //可以获取到私有的属性 
		Field[] fi = c1.getDeclaredFields();
		
                //只可以获取到公有的属性
                //Field[] fi = c1.getFields();
		
                for(Field ff : fi){
			System.out.println(ff.getName());
			System.out.println(ff.getType());
		}
	}

该方法用于使用传递过来的实体类对象获取属性以及属性的值,注意如果想要获取私有属性的值,必须先声明权限,既使用setAccessible(true)方法。

	<span style="font-size:12px;">public void show(Object ob) throws IllegalArgumentException, IllegalAccessException{
		Class c1 = ob.getClass();
		Field[] fi = c1.getDeclaredFields();
		for(Field ff : fi){
			//必须设置访问权限,否则不能用ff.get(ob)取私有属性
			ff.setAccessible(true);
			System.out.println(ff.getName() + "值" + ff.get(ob));
			ff.set(ob,"1");
		}
	}</span>

4.打印构造函数的信息

    因为打印构造函数较为特殊,故把它单独放在一节。

	public static void printCon(Object ob){
		Class c1 = ob.getClass();
		Constructor[] con = c1.getDeclaredConstructors();
		for(Constructor cc : con){
			System.out.print(cc.getName() + "(");
			Class[] paramTypes = cc.getParameterTypes();
			for(Class cla : paramTypes){
				System.out.print(cla.getName() + ",");
			}
			System.out.println(")");
		}
	}

参考资料:

极客学院JAVA反射课程

慕课网JAVA反射课程

JAVA反射百度百科

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值