简单了解Java反射|Java基础

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战java

前言:目前不少三方框架都有用到反射的知识,本文将要介绍反射经常使用API。json

什么是反射?

Java的反射(reflection)机制是指在程序的运行状态中,能够构造任意一个类的对象,能够了解任意一个对象所属的类,能够了解任意一个类的成员变量和方法,能够调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。数组

优缺点

  • 优势

反射提升了Java程序的灵活性和扩展性,下降耦合性,提升自适应能力。它容许程序建立和控制任何类的对象,无需提早硬编码目标类;反射是其它一些经常使用语言,如C、C++、Fortran 或者Pascal等都不具有的markdown

  • 缺点
  1. 性能问题:使用反射基本上是一种解释操做,用于字段和方法接入时要远慢于直接代码。所以Java反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
  2. 使用反射会模糊程序内部逻辑:程序人员但愿在源代码中看到程序的逻辑,反射等绕过了源代码的技术,于是会带来维护问题。反射代码比相应的直接代码更复杂。

反射则是一开始并不知道咱们要初始化的类对象是什么,天然也没法使用 new关键字来建立对象,这时,咱们使用JDK提供的反射API进行反射调用。反射就是在运行状态中,对于任意一个类,都能知道,调用且改变这个类的全部属性和方法。app

Java反射机制主要提供了如下功能:框架

  1. 在运行时构造任意一个类的对象
  2. 在运行时获取或者修改任意一个类所具备的成员变量和方法
  3. 在运行时调用任意一个对象的方法(属性)

获取Class对象

  • 经过类名获取:类名.class()
  • 经过对象获取:对象名.getClass()
  • 经过全类名获取: Class.forName(全类名)    classLoader.loadClass(全类名)
public static String str = new String("shixf");
 
    public static void main(String[] args) {
        //1.经过类名获取
        Class<String> stringClass = String.class;
        //2.经过对象获取
        Class<? extends String> strClass = str.getClass();
        //3.经过全类名获取
        try {
            //str.getClass().getName() == java.lang.String
            Class<?> aClass = Class.forName(str.getClass().getName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
复制代码

判断是否为某个类的实例

通常咱们经常用"instanceof" 关键字来判断某个类是否为一个类的实例,同时也能够借助反射中Class对象的  " isInstance()" 方法来判断是否为某个类的实例,它是一个native方法。函数

public native boolean isInstance(Object obj);
 
//判断是否为某个类的类型
public native boolean isAssignableFrom(Class<?> cls);
复制代码

反射建立实例对象

  • Class.newInstance()
  • 经过Class获取Constructor对象,在调用Constructor.newInstance()方法来建立实例.
public static Object createInstance_1(Class cls){
        if(null != cls){
            Object o = null;
            try {
                o = cls.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return o;
        }
        return null;
    }
 
    public static Object createInstance_2(Class cls){
        //获取String所对应的Class对象
         Class<?> c = String.class;
         //获取String类带一个String参数的构造器
        Constructor constructor = null;
        //根据构造器建立实例
        Object obj = null;
        try {
            constructor = c.getConstructor(String.class);
            obj = constructor.newInstance("23333");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
复制代码

获取构造器信息

/** * @param parameterTypes ...表明可传入该类型的数组,单个实例,或者不传参数, * 得到使用特殊的参数类型的public构造函数(包括父类) */
    public Constructor<T> getConstructor(Class<?>... parameterTypes) /** * 得到类的全部公共构造函数 */ public Constructor<?>[] getConstructors() /** * 得到使用特定参数类型的构造函数(包括私有) */ public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) /** * 得到类的全部构造函数 */ public Constructor<?>[] getDeclaredConstructors() 复制代码

获取类的成员变量(字段)信息

/** * 获取命名的公共字段(包含父类的public成员变量) */
public Field getField(String name) /** * 得到类的全部公共字段(包含父类的public成员变量) */ public Field[] getFields() /** * 获取类自己的属性成员(包括私有、共有、保护) */ public Field getDeclaredField(String name) /** * 获取类自己的全部属性成员(包括私有、共有、保护) */ public Field[] getDeclaredFields() 复制代码

经过反射调用方法

/** * 使用特定参数类型,得到命名的公共方法 */
public Method getMethod(String name, Class<?>... parameterTypes) /** * 得到类的全部公共方法 */ public Method[] getMethods() /** * 得到类声明的命名的方法,包括私有的。 */ public Method getDeclaredMethod(String name, Class<?>... parameterTypes) /** * 得到类声明的全部命名的方法,包括私有的。 */ public Method[] getDeclaredMethods() 复制代码

java.lang.IllegalArgumentException: wrong number of arguments

注意:当咱们获取到一个方法时,能够调用invoke()方法来调用这个方法。以及须要注意的 “wrong number of arguments”异常post

/** * * @param obj * @param args 此处须要注意,该参数为Object * @return */
public Object invoke(Object obj, Object... args) 复制代码
public class GetMethod {
 
    private static GetMethod getMethod = new GetMethod();
    private static String[] strArray = {"1","2","3"};
 
 
    public static void main(String[] args) {
        getMethod();
    }
 
    public void printStr(String[] str){
        for (String s : str) {
            System.out.println(s);
        }
    }
 
    public static void getMethod(){
        Class<?> cls = getMethod.getClass();
        try {
            Method printStr = cls.getMethod("printStr",String[].class);
            //此处须要强制转换为Object,不然抛出wrong number of arguments
            printStr.invoke(cls.newInstance(),(Object) strArray); 
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}
复制代码

利用反射建立数组

数组在 Java 里是比较特殊的一种类型,它能够赋值给一个 Object Reference 其中的 Array 类为 java.lang.reflflect.Array类。咱们经过 Array.newInstance() 建立数组对象,它的原型是 :性能

public static Object newInstance ( Class <?> componentType , int length );
复制代码

反射获取泛型真实类型

当咱们对一个泛型类进行反射时,须要获得泛型中的真是数据类型,来完成如json反序列化的操做。此时须要经过Type体系来完成。Type接口包含了一个实现类(Class)个四个接口,分别是:ui

TypeVariable: 泛型类型变量,能够泛型上下限等信息。
ParameterizedType 具体的泛型类型,能够得到元数据中泛型签名类型(泛型真是类型)
GenericArrayType 当须要描述的类型是泛型类的数组时,好比List[] , map[],此接口会做为Type的实现。
WildcardType 通配符泛型,得到上下限信息。

TypeVariable

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
 
public class TypeVariableTest<K extends Comparable & Serializable, V> {
 
    private K key;
    private V value;
 
    public static void main(String[] args) {
        try {
            Field fKey = TypeVariableTest.class.getDeclaredField("key");
            Field fValue = TypeVariableTest.class.getDeclaredField("value");
            TypeVariable genericTypeKey = (TypeVariable)fKey.getGenericType();
            TypeVariable genericTypeValue = (TypeVariable)fValue.getGenericType();
 
            System.out.println("genericTypeKey.getName(): " + genericTypeKey.getName());
            System.out.println("genericTypeValue.getName(): " + genericTypeValue.getName());
            System.out.println(genericTypeKey.getGenericDeclaration());//class Reflect.TypeVariableTest
            System.out.println(genericTypeValue.getGenericDeclaration());//class Reflect.TypeVariableTest
            System.out.println("K的上界");
            for (Type bound : genericTypeKey.getBounds()) {
                System.out.println(bound);
                //interface java.lang.Comparable
                //interface java.io.Serializable
            }
            System.out.println("V的上界");
            for (Type bound : genericTypeValue.getBounds()) {
                System.out.println(bound);
                //class java.lang.Object
            }
 
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
复制代码

ParameterizedType

public class ParameterizedTypeTest {
 
    Map<String, String> mMap;
 
    public static void main(String[] args) {
        try {
            Field map = ParameterizedTypeTest.class.getDeclaredField("mMap");
 
            System.out.println("get mMap GenericType: " + map.getGenericType());//java.util.Map<java.lang.String, java.lang.String>
 
            ParameterizedType pType = (ParameterizedType)map.getGenericType();
            System.out.println(pType.getRawType());//interface java.util.Map
 
            for (Type actualTypeArgument : pType.getActualTypeArguments()) {
                System.out.println(actualTypeArgument);//俩边class java.lang.String
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
复制代码

GenericArrayType

public class GenericArrayTypeTest<T> {
 
    List<String>[] lists;
 
    public static void main(String[] args) {
        try {
            Field field = GenericArrayTypeTest.class.getDeclaredField("lists");
            GenericArrayType genericArrayType = (GenericArrayType)field.getGenericType();
            System.out.println(genericArrayType.getGenericComponentType());//java.util.List<java.lang.String>
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
复制代码

WildcardType

public class WildcardTypeTest {
 
    private List<? extends Number> up;//上限
    private List<? super String> down;//下限
 
    public static void main(String[] args) {
        try {
            Field up = WildcardTypeTest.class.getDeclaredField("up");
            Field down = WildcardTypeTest.class.getDeclaredField("down");
            //先拿到泛型类型
            ParameterizedType parameterizedTypeUp = (ParameterizedType)up.getGenericType();
            ParameterizedType parameterizedTypeDown = (ParameterizedType)down.getGenericType();
 
            //在从泛型类型里拿到通配符类型
            WildcardType wildcardTypeUp = (WildcardType)parameterizedTypeUp.getActualTypeArguments()[0];
            WildcardType wildcardTypeDown = (WildcardType)parameterizedTypeDown.getActualTypeArguments()[0];
            System.out.println(wildcardTypeUp.getUpperBounds()[0]);//class java.lang.Number
            System.out.println(wildcardTypeDown.getLowerBounds()[0]);//class java.lang.String
 
            System.out.println(wildcardTypeUp);//? extends java.lang.Number
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
复制代码
相关文章
相关标签/搜索