java反射机制

Posted timfruit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java反射机制相关的知识,希望对你有一定的参考价值。

java反射机制

   很喜欢这句话——“当我们面对一项新的知识时,我们往往需要知道三方面,它是什么,它能做什么,它比原有知识强在哪里,我们该怎么使用它。当你能够解决这些问题时,便意味着你已经对这项知识入门了。”

 


 

 一、定义(是什么)

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

   一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl、Python、Ruby是动态语言,C++、Java、C#不是动态语言。

  尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)

 

 

 二、功能

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

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

  3)在运行时判断任意一个类所属的成员变量和方法

  4)在运行时调用类的任意方法

  5)生成动态代理

 

 

三、为什么用

  一般情况下,我们使用一个事先知道的类或方法,如通过new方法获取对应对象。当某些类经常变化,或者不确定,或者编译期未知时,可以通过反射,在运行时获取该类的属性、方法,或者调用某些方法。

 

 

四、Class(Java反射的起源)

   Class类是Java反射的起源,如果没有Class,就不能调用反射相关的api。

  在Java应用中,Class类的实例代表了classes和interfaces,也包括enum, annotation, array, 8种原生数据类型(byte, short, int, long, float, double, char, boolean)以及 void。Class类的构造器是私有的,意味着Class对象只能由JVM自动生成,每当class字节码被JVM加载或者defineClass()方法被调用时,Class对象就会由JVM自动生成。

  

public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, AnnotatedElement {

/*
     * 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对象的途径

package com.ttx.java.reflect;

/**
 * 使用java中的反射
 * @author TimFruit
 * @date 18-9-23 下午9:06
 */
public class TestReflect {

    //http://www.importnew.com/23902.html
    public static void main(String[] args) throws ClassNotFoundException {
        ClassPathway pathway=new ClassPathway();
        System.out.println(pathway.getClassByClass());   //==>  class com.ttx.java.reflect.ClassPathway
        System.out.println(pathway.getClassByGetClassMethod());   //==>  class com.ttx.java.reflect.ClassPathway
        System.out.println(pathway.getClassByGetSupperClassMethod());    //==>  class java.lang.Object
        System.out.println(pathway.getClassByForNameMethod());    //==>  class com.ttx.java.reflect.ClassPathway
    }

}


/**
 * 获取class对象的途径
 */
class ClassPathway{


    Class getClassByClass(){
        return ClassPathway.class;
    }


    Class getClassByGetClassMethod(){//常用,由对象获取对应的类
        ClassPathway pathway=new ClassPathway();
        return pathway.getClass();
    }


    Class getClassByGetSupperClassMethod(){
        ClassPathway pathway=new ClassPathway();
        Class pathwayClazz=pathway.getClass();
        return pathwayClazz.getSuperclass();
    }


    Class getClassByForNameMethod() throws ClassNotFoundException {//常用,通过静态方法以及对应的类名获取
        return Class.forName("com.ttx.java.reflect.ClassPathway");
    }

}

 

 

 六、反射可使用的api (怎样用)

 

package com.ttx.java.reflect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 使用反射中的api
 * @author TimFruit
 * @date 18-10-5 上午12:13
 */
public class ClassAPITests {

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        //反射的主要作用是运行时观察类的属性、方法,并且调用方法

        People tim=new People("tim");
        Class clazz=tim.getClass();


        //1.获取构造器 并构造实例
        constructInstance(clazz);                        // ==>  张三 - com.ttx.java.reflect.People@4f47d241

        //2.获取方法  并调用方法
        invokeMethod(clazz,"work",tim);      // ==>  tim正在工作...

        //3.识别标注的注解,调用对应的方法
        invokeMethod(clazz,InvokeMethod.class,tim);     // ==>  tim正在工作...

        //4.设置属性
        setProperty(clazz,tim,"name","ttx-new-name");
        System.out.println(tim.getName());              // ==>  ttx-new-name


        //5.
        methodsAndDeclaredMethodsDifferences(clazz);
        /*  ==>

        getMethods()...
        个数:12
        work | toString | getName | setName | wait | wait | wait | equals | hashCode | getClass | notify | notifyAll |

        getDeclaredMethods()...
        个数:5
        work | testMethod | toString | getName | setName |
         */

    }


    public static void constructInstance(Class targetClazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //1.获取构造器 并构造实例
        Constructor constructor=targetClazz.getConstructor(String.class);
        Object obj=constructor.newInstance("张三");//新建实例
        System.out.println(obj);
    }


    public static void invokeMethod(Class targetClazz,String methodName,Object invokeObj) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //2.获取方法  并调用方法
        Method workMethod=targetClazz.getMethod(methodName);
        workMethod.invoke(invokeObj);  //第一个参数为调用的对象   类似tim.work()
    }


    public static void invokeMethod(Class targetClazz, Class annotationClazz,Object invokeObj) throws InvocationTargetException, IllegalAccessException {
        //3.识别标注的注解,调用对应的方法
        Method[] methods=targetClazz.getMethods();
        for(Method method : methods){
            Annotation annotation=method.getAnnotation(annotationClazz);
            if(annotation!=null){
                method.invoke(invokeObj);
            }
        }
    }

    public static void setProperty(Class targetClazz, Object targetObj, String propertyName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field field=targetClazz.getDeclaredField(propertyName); //获取属性

        field.setAccessible(true); //设置私有(private)属性可以直接访问
        field.set(targetObj,value);
    }


    public static void methodsAndDeclaredMethodsDifferences(Class targetClazz){

        Method[] methods=targetClazz.getMethods();  //用于获取类所有public的方法,包括继承的方法
        System.out.println("\\r\\ngetMethods()...");
        System.out.println("个数:"+methods.length);
        for(Method method: methods){
            System.out.print(method.getName() +" | ");
        }

        Method[] declaredMethods=targetClazz.getDeclaredMethods(); //用于获取自身类声明的方法,包括public, protected, private的方法
        System.out.println("\\r\\ngetDeclaredMethods()...");
        System.out.println("个数:"+declaredMethods.length);
        for(Method method: declaredMethods){
            System.out.print(method.getName() +" | ");
        }

    }

}

 

public class People {

    private String name;

    public People() {
    }

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

    public String getName() {
        return name;
    }

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

    @InvokeMethod
    public void work(){
        System.out.println(name+"正在工作...");
    }

    @Override
    public String toString() {
        return name+" - "+super.toString();
    }


    private void testMethod(){
        System.out.println("用于测试getMethods和getDeclaredMethods的区别");
    }

}

 

/**
 * 用于反射识别方法
 * @author TimFruit
 * @date 18-10-5 上午12:48
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InvokeMethod {
}

 

 

学习资料:

  JAVA反射机制_百度百科

  Java反射机制

以上是关于java反射机制的主要内容,如果未能解决你的问题,请参考以下文章

反射机制入门

反射机制入门

java 反射代码片段

深入理解java的反射机制

Java反射机制

Java核心技术梳理-类加载机制与反射