java反射机制

摘要:本文主要介绍Java的反射机制,内容涵盖反射的基本概念、主要作用、相关类、主要API,以及反射的应用示例。

1 关于反射

1.1 基本概念

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

1.2 主要作用

反射机制主要提供了以下功能:
1. 在运行时判断任意一个对象所属的类;
2. 在运行时构造任意一个类的对象;
3. 在运行时判断任意一个类所具有的成员变量和方法;
4. 在运行时调用任意一个对象的方法;
5. 生成动态代理。

2 java.lang.reflect

2.1 包的概述

  提供类和接口,以获得关于类和对象的反射信息。在安全限制内,反射允许编程访问关于加载类的字段、方法和构造方法的信息,并允许使用反射字段、方法和构造方法对其底层对等项进行操作。
  Array提供动态创建和访问数组的静态方法。
  此包中的类以及 java.lang.Class 可以适应以下应用程序的需要:调试程序、解释程序、对象检查程序、类浏览程序,以及服务。

2.2 类的摘要

这里写图片描述

3 Class类

3.1 类的声明

public final class Class<T> extends Object implements Serializable, GenericDeclaration, Type, AnnotatedElementClass

3.2 类的概述

  Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。基本的Java类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。
  以下示例使用 Class 对象来显示对象的类名:

void printClassName(Object obj) {
    System.out.println(obj.getClass().getName());
}

  还可以使用一个类字面值(JLS Section 15.8.2)来获取指定类型(或 void)的 Class 对象。例如:
System.out.println("The name of class Foo is: "+Foo.class.getName());

3.3 方法概述

(1)public static Class<?> forName(String className) throws ClassNotFoundException

返回与带有给定字符串名的类或接口相关联的 Class 对象。className - 所需类的完全限定名。

(2)public T newInstance() throws InstantiationException, IllegalAccessException

创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的new表达式实例化该类。

(3)public boolean isInstance(Object obj)

判定指定的Object是否与此Class所表示的对象赋值兼容。此方法是Java语言instanceof运算符的动态等效方法。如果指定的Object参数非空,且能够被强制转换成该Class对象所表示的引用类型,则该方法返回 true;否则返回 false。

(4)public boolean isInterface()

判定指定的 Class 对象是否表示一个接口类型。

(5)public boolean isArray()

判定此 Class 对象是否表示一个数组类。

(6)public boolean isPrimitive()

判定指定的 Class 对象是否表示一个基本类型。

(7)public boolean isSynthetic()

如果此类是复合类,则返回 true,否则 false。

(8)public String getName()

以String的形式返回此Class对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
如果此类对象表示的是非数组类型的引用类型,则返回该类的二进制名称;如果此类对象表示一个基本类型或 void,则返回的名字是一个与该基本类型或 void 所对应的 Java 语言关键字相同的 String。

(9)public ClassLoader getClassLoader()

返回该类的类加载器。

(10)public Class<? super T> getSuperclass()

返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。如果此 Class 表示 Object 类、一个接口、一个基本类型或 void,则返回 null。

(11)public Type getGenericSuperclass()

返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type。

(12)public Package getPackage()

获取此类的包。

(13)public Class<?>[] getInterfaces()

确定此对象所表示的类或接口实现的接口

(14)public Class<?> getComponentType()

返回表示数组组件类型的 Class。如果此类不表示数组类,则此方法返回 null

(15)public int getModifiers()

返回此类或接口以整数编码的 Java 语言修饰符。修饰符由 Java 虚拟机的 public、protected、private、final、static、abstract 和 interface 对应的常量组成

(16)public Class<?>[] getClasses()

返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class 对象所表示的类的成员的所有公共类和接口。

(17)public Field[] getFields() throws SecurityException

返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。如果该 Class 对象表示一个类,则此方法返回该类及其所有超类的公共字段。如果该 Class 对象表示一个接口,则此方法返回该接口及其所有超接口的公共字段。

(18)public Method[] getMethods() throws SecurityException

返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口的公共 member 方法。

(19)public Constructor<?>[] getConstructors() throws SecurityException

返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。

(20)public Field getField(String name) throws NoSuchFieldException, SecurityException

返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。name 指定的该类的 Field 对象

(21)public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException

返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。parameterTypes 参数是按声明顺序标识该方法形参类型的 Class 对象的一个数组。

(22)public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException

返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。parameterTypes 参数是 Class 对象的一个数组,这些 Class 对象按声明顺序标识构造方法的形参类型。

(23)public InputStream getResourceAsStream(String name)

查找具有给定名称的资源。

(24)public T cast(Object obj)

将一个对象强制转换成此 Class 对象所表示的类或接口

4 Method类

4.1 类的声明

public final class Method extends AccessibleObject implements GenericDeclaration, Member

4.2 类的概述

Method提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。

4.3 方法概述

(1)public String getName()

以 String 形式返回此 Method 对象表示的方法名称。

(2)public int getModifiers()

以整数形式返回此 Method 对象所表示方法的 Java 语言修饰符。应该使用 Modifier 类对修饰符进行解码。

(3)public TypeVariable<Method>[] getTypeParameters()

返回 TypeVariable 对象的数组,这些对象描述了由 GenericDeclaration 对象表示的按声明顺序来声明的类型变量。

(4)public Class<?> getReturnType()

返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型

(5)public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException

对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。如果底层方法是静态的,那么可以忽略指定的 obj 参数,该参数可以为 null;如果底层方法所需的形参数为0,则所提供的 args 数组长度可以为 0 或 null。如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中;如果该值的类型为一组基本类型,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。
obj - 从中调用底层方法的对象;args - 用于方法调用的参数

5 相关API

基本类

package pkg1;
import java.io.Serializable;

public class Student extends Object implements Serializable{
    private static final long serialVersionUID = 1L;
    // 共有字段和私有字段
    public String name;
    private int age;

    // 带参构造方法和无参构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Student() {
        this("no name", 0);
    }

    // 静态方法和非静态方法
    public static long serialID() {
        return serialVersionUID;
    }
    public String toString() {
        return this.name+":"+age;
    }
}

测试类

package pkg1;

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

/*
 * 反射机制相关API测试**/
public class Demo1 {
    public static void main(String[] args) throws Exception {
        //1 通过对象获得完整包名和类名
        Student s1 = new Student();
        System.out.println(s1.getClass().getName());// pkg1.Student

        //2 实例化Class对象,共3种方法
        Class<?> c21 = Class.forName("pkg1.Student");
        Class<?> c22 = new Student().getClass();
        Class<?> c23 = Student.class;
        System.out.println(c21.getName());
        System.out.println(c22.getName());
        System.out.println(c23.getName());// pkg1.Student

        //3 获取对象的父类与接口
        Class<?> superClass = c21.getSuperclass();
        System.out.println(superClass.getName());// java.lang.Object

        Class<?> interfs[] = c21.getInterfaces();
        for (Class<?> interf : interfs) {
            System.out.println(interf.getName());// java.io.Serializable
        }

        //4 获取对象的字段
        Class<?> c41 = Class.forName("pkg1.Student");
        System.out.println("========== 字段 =======");
        Field[] fields = c41.getFields();
        for (Field field :fields) {
            // 权限修饰符
            int mod = field.getModifiers();
            String pri = Modifier.toString(mod);
            // 类型
            Class<?> type = field.getType();

            System.out.println(pri+"|"+type.getName()+"|"+field.getName());// public|java.lang.String|name
        }

        System.out.println("---------------");
        //5 获取全部方法
        Method[] methods = c41.getMethods();
        for (Method method : methods) {
            // 权限修饰符
            int mod = method.getModifiers();
            String pri = Modifier.toString(mod);

            // 返回类型
            Class<?> returnTye = method.getReturnType();

            // 参数列表
            Class<?> params[] = method.getParameterTypes();
            String paramlist = "";
            for (Class<?> param : params) {
                paramlist += param.getName() +",";
            }
            System.out.println(pri+"|"+returnTye.getName()+"|"+method.getName()+"|"+paramlist);
            /*
             *  public|java.lang.String|toString|
                public static|long|serialID|
                public final|void|wait|
                public final|void|wait|long,int,
                public final native|void|wait|long,
                public|boolean|equals|java.lang.Object,
                public native|int|hashCode|
                public final native|java.lang.Class|getClass|
                public final native|void|notify|
                public final native|void|notifyAll|
            */
        }

        System.out.println("-----------------------");
        //6 获取构造函数,并实例化对象
        Constructor<?> cons[] = Class.forName("pkg1.Student").getConstructors();
        for (Constructor con : cons) {
            // 权限修饰符
            int mod = con.getModifiers();
            String pri = Modifier.toString(mod);

            // 参数类型列表
            Class<?> params[] = con.getParameterTypes();
            String paramlist = "";
            for (Class<?> param : params) {
                paramlist += param.getName()+",";
            }

            System.out.println(pri+"|"+con.getName()+"|"+paramlist);
            //public|pkg1.Student|java.lang.String,int,
            //public|pkg1.Student|
        }
        // 实例化默认构造方法
        Student stu1 = (Student)Class.forName("pkg1.Student").newInstance();
        System.out.println(stu1.toString());// no name:0
        // 实例化指定构造方法
        Student stu2 = (Student)cons[0].newInstance("panshan", 24);
        System.out.println(stu2.toString());// panshan:24
        Student stu3 = (Student)cons[1].newInstance();
        System.out.println(stu3.toString());// no name:0

        //7 调用静态方法和非静态方法
        Class<?> c71 = Class.forName("pkg1.Student");
        Method m1 = c71.getMethod("serialID");
        System.out.println(m1.invoke(c71));// 1
        Method m2 = c71.getMethod("toString");
        System.out.println(m2.invoke(c71.newInstance()));// no name:0
    }
}

6 应用示例

(1)在泛型为Integer的ArrayList中存放String类型对象

// 通过反射在擦除泛型后的集合中存储其他类型
public static void fun1() throws Exception {
    ArrayList<Integer> list = new ArrayList<>();
    Method m1 = list.getClass().getMethod("add", Object.class);
    m1.invoke(list, "a String");

    System.out.println(list.get(0));// a String
}

(2)通过反射获取数组信息

// 通过反射类Array,获取数组信息
public static void fun2() {
    int[] arr = {1, 2, 3, 4};

    Class<?> c = arr.getClass();
    System.out.println(c.getName());// [I


    System.out.println(Array.getLength(arr));// 4
    System.out.println(Array.get(arr, 0));// 1
}

(3)反射应用于工厂模式

package pkg1;

public class Demo3 {
    public static void main(String[] args) {
        Father instance1 = Factory.getInstance("pkg1.C1");
        instance1.fun();// a instance of C1

        Father instance2 = Factory.getInstance("pkg1.C2");
        instance2.fun();// a instance of C2
    }
}

// 公共父接口
interface Father {
    public abstract void fun();
}

// 实现父接口的不同子类
class C1 implements Father {
    @Override
    public void fun() {
        System.out.println("a instance of C1");
    }
}

class C2 implements Father {
    @Override
    public void fun() {
        System.out.println("a instance of C2");
    }
}

// 工厂类
class Factory {
    public static Father getInstance(String className) {
        Father instance = null;
        try {
            instance = (Father)Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return instance;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值