• Java原来如此反射机制


    在Java运行时环境中,对于任意一个类,能知道这个类有哪些属性和方法。对于任意一个对象,能调用它的任意一个方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。

    Java反射机制主要提供了以下功能。

    1.      在运行时判断任意一个对象所属的类。

    2.      在运行时构造任意一个类的对象。

    3.      在运行时判断任意一个类所具有的成员变量和方法。

    4.      在运行时调用任意一个对象的方法。

    反射机制是Java被视为动态语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其方法修饰符,父类,实现的接口,属性,方法等信息,并可于运行时改变属性内容或调用方法。

    Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体,或对其属性设值,或唤起其方法。这种“看透class”的能力被称为introspection(內省,内观,反省)。Reflection和introspection是常被并提的两个术语。

    在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:

    Class类:代表一个类。

    Field类:代表类的成员变量(成员变量也称为类的属性)。

    Method类:代表类的方法。

    Constructor类:代表类的构造方法。

    Array类:提供了动态创建数组,以及访问数组的元素的静态方法。

    要想使用反射,首先需要获得待处理类或对象所对应的Class对象。

    获取某个类或某个对象所对应的class对象的常用的3种方式:

    1.      使用Class类的静态方法forName:Class.forName(“java.lang.String”);

    2.      使用类的.class语法:String.class;

    3.      使用对象的getClass()方法:String s = “aa”;Class<?> clazz = s.getClass();

    在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API中的核心类,它有以下方法

    getName():获得类的完整名字。

    getFields():获得类的public类型的属性。

    getDeclaredFields():获得类的所有属性。

    getMethods():获得类的public类型的方法。

    getDeclaredMethods():获得类的所有方法。

    getMethod(String name,Class[]parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。

    getConstructors():获得类的public类型的构造方法。

    getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。

    newInstance():通过类的不带参数的构造方法创建这个类的一个对象。

    以下程序演示了Reflection API的基本作用,它读取命令行参数指定的类名,然后打印这个类所具有的方法信息。

    package com.zhouyu.reflect;
    
    import java.lang.reflect.Method;
    
    public class ReflectTest
    {
        public static void main(String[] args)
        {
            try
            {
                Class<?> classType = Class.forName(args[0]);
                Method[] methods = classType.getDeclaredMethods();
                for(Method method : methods)
                {
                    System.out.println(method);
                }
            }
            catch(Exception e)
            {
                System.out.println(e.toString());
            }
        }
    }
    

    以下代码运用反射机制调用InvokeTester对象的add()和echo()方法:

    package com.zhouyu.reflect;
    
    import java.lang.reflect.*;
    
    public class InvokeTester
    {
        public int add(int num1,int num2)
        {
            return num1 + num2;
        }
    
        public String echo(String message)
        {
            return "hello" + message;
        }
    
        public static void main(String[] args) throws Exception
        {
    /*
            //传统方式
            InvokeTester invokeTester = new InvokeTester();
            System.out.println(invokeTester.add(1,2));
            System.out.println(invokeTester.echo("Tom"));
    */
    
            //反射方式
            Class<?> classType = InvokeTester.class;
            Object invokeTester = classType.newInstance();
            Method addMethod = classType.getMethod("add",new Class[]{int.class,int.class});
            Object result = addMethod.invoke(invokeTester,new Object[]{1,2});
            System.out.println((Integer)result);
    
            Method echoMethod = classType.getMethod("echo",new Class[]{String.class});
            Object resultStr = echoMethod.invoke(invokeTester,new Object[]{"Tom"});
            System.out.println((String)resultStr);
        }
    }
    

    Method类的invoke(Objectobj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。Invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。

    若想通过类的不带参数的构造方法来生成对象,我们有两种方式:

    1.      先获取Class对象,然后通过该Class对象的newInstance()方法直接生成即可:

    Class<?> classType = String.class;

    Object obj = classType.newInstance();

    2.      先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成:

    Class<?> classType = Customer.class;

    Constructor cons = classType.getConstructor(new Class[]{});

    Object obj = cons.newInstance(new Object[]{});

    若想通过类的带参数的构造方法生成对象,只能使用下面这一种方式:

    Class<?> classType = Customer.class;

    Constructor cons = classType.getConstructor(newClass[]{String.class,int.class});

    Object obj = cons.newInstance(new Object[]{“hello”,3});

    实例

    package com.zhouyu.reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class ReflectTester
    {
        //该方法实现对Customer对象的拷贝操作
        public Object copy(Object object)
        {
            Object objectCopy = null;
            try
            {
                Class<?> classType = object.getClass();
    /*
                //不带参数的第一种方法
                Object obj = classType.newInstance();
    */
                //不带参数的第二种方法
                Constructor cons = classType.getConstructor(new Class[]{});
                objectCopy = cons.newInstance(new Object[]{});
    /*
                //带参数的
                Constructor cons2 = classType.getConstructor(new Class[]{String.class,int.class});
                Object obj3 = cons2.newInstance(new Object[]{"Tom",32});
    
                System.out.println(obj);
                System.out.println(obj2);
                System.out.println(obj3);
    */
                // 获得对象的所有成员变量
                Field[] fields = classType.getDeclaredFields();
    
                for (Field field : fields)
                {
                    String name = field.getName();
    
                    String firstLetter = name.substring(0, 1).toUpperCase();// 将属性的首字母转换为大写
    
                    String getMethodName = "get" + firstLetter + name.substring(1);
                    String setMethodName = "set" + firstLetter + name.substring(1);
    
                    Method getMethod = classType.getMethod(getMethodName,
                            new Class[] {});
    
                    Method setMethod = classType.getMethod(setMethodName,
                            new Class[] { field.getType() });
    
                    Object value = getMethod.invoke(object, new Object[] {});
    
                    setMethod.invoke(objectCopy, new Object[] { value });
                }
    
    
            }
            catch (Exception e)
            {
                System.out.println(e.toString());
            }
            return objectCopy;
        }
    
        public static void main(String[] args)
        {
            Customer customer = new Customer("Tom", 20);
            customer.setId(1L);
    
            ReflectTester test = new ReflectTester();
    
            Customer customer2 = (Customer) test.copy(customer);
    
            System.out.println(customer2.getId() + "," + customer2.getName() + ","
                    + customer2.getAge());
        }
    }
    
    class Customer
    {
        private Long id;
    
        private String name;
    
        private int age;
    
        public Customer()
        {
    
        }
    
        public Customer(String name, int age)
        {
            this.name = name;
            this.age = age;
        }
    
        public Long getId()
        {
            return id;
        }
    
        public void setId(Long id)
        {
            this.id = id;
        }
    
        public String getName()
        {
            return name;
        }
    
        public void setName(String name)
        {
            this.name = name;
        }
    
        public int getAge()
        {
            return age;
        }
    
        public void setAge(int age)
        {
            this.age = age;
        }
    }
    

    Java.lang.Array类提供了动态创建和访问数组元素的各种静态方法。

    实例

    package com.zhouyu.reflect;
    
    import java.lang.reflect.Array;
    
    public class ArrayTester1
    {
    	public static void main(String[] args) throws Exception
    	{
    		Class<?> classType = Class.forName("java.lang.String");
    		
    		Object array = Array.newInstance(classType, 10);
    		
    		Array.set(array, 5, "hello");
    		
    		String str = (String)Array.get(array, 5);
    		
    		System.out.println(str);
    	}
    }
    
  • 相关阅读:
    MySQL性能调优——索引详解与索引的优化
    Linux命令之文件搜索
    MySQL中的行级锁,表级锁,页级锁
    MySQL存储引擎
    Linux软链接和硬链接
    linux学习笔记
    在浏览器中输入一个网址后,发生了什么?
    二叉排序树
    有序表查找
    为view设置虚线边框
  • 原文地址:https://www.cnblogs.com/zyaizz/p/3442646.html
Copyright © 2020-2023  润新知