Java反射作为其动态语言的标志性特点之一我们很有必要掌握,至少得知道其基本用法~ ~本文尝试着从构造器、属性、方法这三点进行讲解反射的用法。在开始之前我先准备好了一个Person类,此类包含了有参构造器、无参构造器、私有属性、公开属性、以及私有方法和公开方法。


package com.geo.reflect;

public class Person {
    public String name = "张三";
    protected String sex = "男";
    private int age = 23;
    public boolean isOnline = false;

    private Person() {
    }

    public Person(String name, int age, boolean isonline) {
        this.name = name;
        this.age = age;
        this.isOnline = isonline;
    }

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String getSex() {
        return sex;
    }

    private void setSex(String sex) {
        this.sex = sex;
    }

    protected int getAge() {
        return age;
    }

    protected void setAge(int age) {
        this.age = age;
    }

    public boolean getOnline() {
        return isOnline;
    }

    public void setOnline(boolean isonline) {
        this.isOnline = isonline;
    }

    @Override
    public String toString() {
        return "Hi~I am Person Class";
    }

}

一、反射构造器

1.获取一个String类型参数的构造器


//获取带有一个String类型的构造器,即Person(String str)
			Constructor consParamStr = mClass.getConstructor(String.class);
			System.out.println(consParamStr);

--------------------------  以下文打印结果 ----------------------------
public com.geo.reflect.Person(java.lang.String)

2.获取三个参数的构造器


// 获取带有三个参数的构造器
			Class[] cla = { String.class, Integer.class, Boolean.class };
			Constructor consParamThr = mClass.getConstructor(cla);
			System.out.println(consParamThr);

--------------------------  以下文打印结果 ----------------------------
public com.geo.reflect.Person(java.lang.String,int,boolean)



 


   执行以上代码你会发现会报错,根本执行不通过,因为Person类的三参构造器public Person(String name, int age, boolean isonline)的第二个和第三个参数并不是Integer.class和Boolean.class,而应该改为

Integer.TYPE和Boolean.TYPE或 int.class和boolean.class即可,修改后的代码如下:


// 获取带有三个参数的构造器
			Class[] cla = { String.class, Integer.TYPE, Boolean.TYPE};
			Constructor consParamThr = mClass.getConstructor(cla);
			System.out.println(consParamThr);
--------------------------  以下文打印结果 ----------------------------
public com.geo.reflect.Person(java.lang.String,int,boolean)




3.一次性获取所有构造器


Constructor[] cons = mClass.getConstructors();
			System.out.println("构造器个数:"+cons.length);
			for(Constructor cu : cons){
				System.out.println("构造器名称:"+cu.getName());
			}

--------------------------  以下文打印结果 ----------------------------
构造器个数:3
构造器名称:com.geo.reflect.Person
构造器名称:com.geo.reflect.Person
构造器名称:com.geo.reflect.Person





    可以看到,即使Person类有一个私有构造器也会获取到。

4.获取构造器参数和参数类型


Class[] cla = { String.class, Integer.TYPE, boolean.class};
			Constructor consParamThr = mClass.getConstructor(cla);
			System.out.println("构造器名称:"+consParamThr);
			//获取构造器参数
			System.out.println("构造器参数个数:"+consParamThr.getParameterCount());
			Parameter[] params = consParamThr.getParameters();
			for(Parameter pam : params){
				System.out.println("参数类型:"+pam.getType());
				System.out.println("参数名称:"+pam.getName());
			}

--------------------------  以下文打印结果 ----------------------------
构造器名称:public com.geo.reflect.Person(java.lang.String,int,boolean)构造器参数个数:3参数类型:class java.lang.String参数名称:arg0参数类型:int参数名称:arg1参数类型:boolean参数名称:arg2






5.根据构造器创建实例


Class[] cla = { String.class, Integer.TYPE, Boolean.TYPE};
			Constructor consParamThr = mClass.getConstructor(cla);
			System.out.println("构造器名称:"+consParamThr);
			//获取构造器参数
			System.out.println("构造器参数个数:"+consParamThr.getParameterCount());
			Parameter[] params = consParamThr.getParameters();
			for(Parameter pam : params){
				System.out.println("参数类型:"+pam.getType());
				System.out.println("参数名称:"+pam.getName());
			}
			try {
				//注意在使用构造器创建对象时,需要传递像应的参数值,就像我们在new对象一样
				Object instance = consParamThr.newInstance("伍佰",33,true);
				
				System.out.println(instance.toString());
			} catch (InstantiationException | IllegalAccessException
					| IllegalArgumentException | InvocationTargetException e) {
			}
--------------------------  以下文打印结果 ----------------------------





构造器名称:public com.geo.reflect.Person(java.lang.String,int,boolean)


构造器参数个数:3


参数类型:class java.lang.String


参数名称:arg0


参数类型:int


参数名称:arg1


参数类型:boolean


参数名称:arg2


姓名:伍佰  性别:男  年龄:33



   

在使用构造器的时候需要注意,如果我们的类没有empty的构造器或者构造器是private类型的,那么我们是无法使用该构造器来创建实例的,这个规则和Java语法一致(即如果类没有构造器那么默认的就是无参数构造器,如果存在有参构造器,那么在创建实例的时候就不会使用无参数构造器),因此,我们的Person类中有一个私有的构造器,所以下面的代码会报错:

   

try {
                                //获取无参构造器
                                Constructor noParamCs = mClass.getConstructor(null);
				//此时调用会报错
				Object instance = noParamCs.newInstance(null);
				
				System.out.println(instance.toString());
			} catch (InstantiationException | IllegalAccessException
					| IllegalArgumentException | InvocationTargetException e) {
			}

--------------------------  以下文打印结果 ----------------------------






 java.lang.NoSuchMethodException: com.geo.reflect.Person.<init>()    at java.lang.Class.getConstructor0(Unknown Source)    at java.lang.Class.getConstructor(Unknown Source)    at com.geo.reflect.MainRefl.reflectCons(MainRefl.java:47)    at com.geo.reflect.MainRefl.main(MainRefl.java:23)

   

因此,私有构造器虽然可以反射获取到,但是并不能用来创建实例,解决办法是将私有构造器该为public或者将所有的构造器删除(此时类默认的就是无参构造器)

二、反射属性

1.根据指定字段字符串获取属性


try {
			Field nameFe = mClass.getDeclaredField("name");
			Field sexFe = mClass.getDeclaredField("sex");
			Field ageFe = mClass.getDeclaredField("age");
			System.out.println(nameFe.getName() + "\t" + sexFe.getName() + "\t"
					+ ageFe.getName());
		} catch (NoSuchFieldException | SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
--------------------------  以下文打印结果 ----------------------------
name    sex    age








2.反射获取到属性值

     要想反射获取到属性的值,该属性的值必须是static类型的。

Field nameFe = mClass.getDeclaredField("name");
			Field sexFe = mClass.getDeclaredField("sex");
			Field ageFe = mClass.getDeclaredField("age");
			System.out.println(nameFe.getName() + "\t" + sexFe.getName() + "\t"
					+ ageFe.getName() + "=" + ageFe.getInt("age"));



三、反射方法

1.获取所有方法

Method[] methods = mClass.getDeclaredMethods();
		for(Method me : methods){
			System.out.println("名字:"+me.getName());
			System.out.println("参数个数"+me.getParameterCount());
			Parameter[] params = me.getParameters();
			for(Parameter pa: params){
				System.out.printf("参数名字:"+pa.getName());
				System.out.println("\n参数类型:"+pa.getType());
			}
			System.out.println("\n=========================");
		}


2.根据方法名获取方法


Method method = mClass.getDeclaredMethod("setName", String.class);

    注意,在根据方法名获取方法的时候第二个参数是方法参数的类型,如果是无参函数就直接给个nuull即可,如下:


Method method = mClass.getDeclaredMethod("getName", null);

3.反射出方法并调用invoke


//反射创建实例
			Person person = (Person) mClass.newInstance();
			//反射出方法
			Method method = mClass.getDeclaredMethod("setName", String.class);
			//设置名字为“刘邦”
			method.invoke(person, "刘邦");
			//最后打印结果就是刘邦
			System.out.println(person.getName());