JavaEE-Java开发框架的基础-反射机制

JavaEE-Java开发框架的基础-反射机制

概述

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

Class类

我们知道类是具有相同属性或者行为的一类事物,那么类本身也可以再被抽象,因为类们也有共同的属性和行为(比如类都有属性,都有构造器,都有方法,都能调用方法),所以把类们又抽象成了一个类Class

众所周知Java有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象

Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象

在学习Class类的过程中我们还需要学习Field类,Method类,Constructor类
Field类:类属性的抽象
Method类:类方法的抽象
Constructor类:类构造器的抽象

获取指定类的属性、方法、构造器

public class Test {
	
	public static void main(String[] args) throws ClassNotFoundException {
		
		//List<?> list = new ArrayList();
		//根据一个类的全名字符串来获得一个类的类对象
		Class<?> clazz = Class.forName("java.util.HashMap");
		//获得传递过来的类的所有方法
		Method[] methods = clazz.getDeclaredMethods();
		
		//System.out.println(Arrays.toString(methods));
		for(Method m : methods){
			System.out.println(m);
		}
		System.out.println("---------------------------------");
		//获得类的所有属性
		Field[] fields = clazz.getDeclaredFields();
		for(Field f : fields){
			System.out.println(f);
		}
		System.out.println("---------------------------------");
		//获得类的所有的构造器
		Constructor<?>[] cs = clazz.getDeclaredConstructors();
		
		for(Constructor c : cs){
			System.out.println(c);
		}
		
		
	}

}

结果:

创建类对象的三种方式


public class ReflectDemo {
	
	public static void main(String[] args) throws ClassNotFoundException {

		test();
	}
	//第一种无参,以类的完整字符串作为参数
	public static void test(){
		Class<?> clazz = Class.forName("java.util.HashMap");
	}
	
	//第二种含参,参数为对象
	public static void test(Object obj){
		Class<?> clazz = obj.getClass();	
	}
	//第三种无参,直接以类.class创建
	public static void test(){
		Class<?> clazz = Person.class;	
	
	}
}

反射必须掌握的方法

获得具体属性:

Field field = class1.getDeclaredField("address");
		System.out.println(field);

获得具体方法;

红框代表可变参数,其实可以理解为数组,数组内容为要反射的方法的参数类型,如果无参数,设置一个空的Class数组即可,或者第二个参数设置为null,如果有参数,数组内容参数的类型如String,就设置String.class

Method method = class1.getDeclaredMethod("getName", new Class[]{});
Method method1 = class1.getDeclaredMethod("setName", new Class[]{String.class});
System.out.println(method);
System.out.println(method1);

获得具体构造器:

Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{Integer.class, String.class, String.class});

获取实例:

//根据类的无参构造器来获得一个对象
Object instance = constructor.newInstance(new Object[]{构造器参数});

反射调用方法:

如果底层方法是实例方法(对象方法),第一个参数就是该对象实例,一般以instance为参数即可,第二个参数是方法的参数列表,invoke的返回值就是实例方法的返回值
如果底层方法是静态的(类方法),那么可以忽略指定的 obj 参数,该参数可以为 null
如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null

Method[] method = class1.getDeclaredMethod(参数);
method.invoke(instance,'方法的参数')

实例:通过反射方式赋值:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class testReflect {

    public static void main(String[] args) throws Exception {
        Class<?> class1 = Class.forName("com.Person");
        //获得无参构造器
        Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{});
        //根据类的无参构造器来获得一个对象
        Object instance = constructor.newInstance(new Object[]{});
        System.out.println(instance);
        //获得类的所有方法
        Method[] methods = class1.getDeclaredMethods();
        for(Method m :methods){
            //获得方法的名字
            String name = m.getName();
            //获得是否以set开始
            boolean startsWith = name.startsWith("set");
            if(startsWith){
                //获得到了set字符串的后面的值
                String fieldName = name.substring(3);
                //获得属性的名字
                fieldName = fieldName.substring(0, 1).toLowerCase()+fieldName.substring(1);
                //获得方法所对应的属性
                Field field = class1.getDeclaredField(fieldName);
                //获得属性的具体类型,获得属性对应的类型
                Class<?> type = field.getType();
                if(type == Integer.class){
                    //反射调用set方法
                    m.invoke(instance, new Object[]{1});
                }
                if(type == String.class && "address".equals(fieldName)){
                    //反射调用set方法
                    m.invoke(instance, new Object[]{"北京"});
                }
                if(type == String.class && "name".equals(fieldName)){
                    //反射调用set方法
                    m.invoke(instance, new Object[]{"张三"});
                }
            }
        }
        System.out.println(instance);

    }
}

实例:通过反射拷贝对象:

import com.Person;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class testReflect {

    public static void main(String[] args) throws Exception {
        Person p = new Person();
        p.setAddress("长春");
        p.setName("李四");
        p.setAge(11);

        Object object = copyObject(p);
        System.out.println(object);

    }

    public static Object copyObject(Object obj) throws Exception{
        //获得传递过来的对象的类对象
        Class<?> class1 = obj.getClass();
        //获得属性
        Field[] fields = class1.getDeclaredFields();
        //获得构造器
        Constructor<?> constructor = class1.getConstructor(new Class[]{});
        //创建一个对象
        Object instance = constructor.newInstance(new Object[]{});
        for(Field f :fields){
            //获得属性的name
            String fname = f.getName();
            //获得属性的类型
            Class<?> type = f.getType();
            //获得属性对应的set和get方法名
            String setMethodName = "set"+fname.substring(0, 1).toUpperCase()+fname.substring(1);
            String getMethodName = "get"+fname.substring(0, 1).toUpperCase()+fname.substring(1);
            //获得get方法
            Method gmethod = class1.getDeclaredMethod(getMethodName, null);
            //调用get方法获得被拷贝的对象的一个属性值
            Object gresult = gmethod.invoke(obj, null);
            //获得set方法
            Method smethod = class1.getDeclaredMethod(setMethodName, new Class[]{gmethod.getReturnType()});
            smethod.invoke(instance, new Object[]{gresult});
        }



        return instance;
    }

}

高阶斗法-破坏私有属性:

由于设置了private的属性通过反射无法直接设置值,可以如下做

		//获得构造器
		Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{});
		//根据类的默认构造器来获得一个对象
		Object instance = constructor.newInstance(new Object[]{});
		//根据方法名字来获得属性对象
		Field field = class1.getDeclaredField("name");
		//破坏掉私有属性
		field.setAccessible(true);
		//设置值
		field.set(instance, "张三");

发布了153 篇原创文章 · 获赞 93 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/JunSIrhl/article/details/104013715
今日推荐