美文网首页
Java的反射机制

Java的反射机制

作者: liycode | 来源:发表于2016-05-30 22:21 被阅读238次

本人翻译并整理自Oracle官方文档

Java的反射机制允许在程序运行时去获取一个类(class)的成员变量和方法。

一、Classes

每个对象不是引用类型就是基本类型。引用类型全部继承自java.lang.Object。类、枚举类型、数组和接口都是引用类型。还有一套固定的基本类型:boolean, byte, short, int, long, char, floatdouble

对于每种类型的对象,Java虚拟机会实例化出一个不可变的java.lang.Class对象的实例,它提供了一些方法去检查这个对象的运行时属性包括它的成员和类型信息。Class类同时也提供了创造新的类和对象的能力。最重要的是它是所有反射API(Reflection APIs)的出发点。

1.1 获得Class对象-反射操作的入口

所有反射操作的出发点是java.lang.Class。因为有java.lang.reflect.ReflectPermission这个异常, java.lang.reflect下的类都没有公共的构造函数。为了获得这些类必须调用Class里的合适方法。这里有若干种方法来获得一个Class对象,取决于代码是否能访问某个对象,是否知道这个类的名称,类型(TYPE),或者一个已有的Class对象。

1.1.1 Object.getClass()

如果一个对象的实例是可以获得的,那么最简单的获得它的Class是调用Object.getClass()。当然它只在这个实例是继承自Object才可行。下面是一些例子:

Class c = "foo".getClass();

byte[] bytes = new byte[1024];
Class c = bytes.getClass();

1.1.2 .class 语法

如果类型是可以获得的但是没有对象的实例,那么可以通过在type后追加".class"来获得它的Class。这也是最简单的方法来获得一个基本类型的Class。

boolean b;
Class c = b.getClass();   // 编译错误

Class c = boolean.class;  // 正确

Class c = int[][][].class;

1.1.3 Class.forName()

如果一个类的 完全限定名(fully-qualified) 可以获得,可以通过静态方法Class.forName()来获得相应的Class。不能被用于基本类型。使用这种方法获得某个数组类的语法是Class.getName()。这个语法适用于引用和原始类型。

Class c = Class.forName("com.duke.MyLocaleServiceProvider");

Class cDoubleArray = Class.forName("[D");  // 与double[].class作用相同

1.1.4 基本类型包装类的TYPE成员变量

除了.class语法外还有一种方式可以获得基本类型的Class。每种基本类型和void都有一个包装类在java.lang被用来基本类型装箱成引用类型。每个包装类包含一个成员变量TYPE相当于Class对基本类型的包装。

Class c = Double.TYPE;

Class c = Void.TYPE;

1.1.5 方法返回的Class

这里有几个Reflection APIs返回Class对象但是需要某个Class已经被直接或间接的获得。

Class.getSuperclass() // 返回某个Class的父类Class

Class.getClasses() // 返回某个类的所有成员的Class对象
Class<?>[] c = Character.class.getClasses(); // Character包含2个成员对象Character.Subset 和Character.UnicodeBlock

1.2 访问Class的声明信息

某个类可能在被声明时使用一个或多个影响运行行为的修饰符。

  • 访问修饰符:public, protectedprivate
  • 要求重写的修饰符:abstract
  • 限制单实例的修饰符:static
  • 禁止修改值的修饰符:final
  • 强制严格浮点行为的修饰符:strictfp
  • 注解

不是所有的修饰符可以用在所有的类上,例如一个接口不能被声明为final,一个枚举类不能是abstract

java.lang.reflect.Modifier包含了所有可能的修饰符的声明。Class.getModifiers()方法返回了某个类的修饰符的集合。

下面这个例子展示了如何获得一个类的声明组件,包括修饰符,泛型类型参数,实现的接口和集成路径。如果Class实现了java.lang.reflect.AnnotatedElement接口,那么也能查询到运行时注解。

import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import static java.lang.System.out;

public class ClassDeclarationSpy {

    public static void main(String... args) {
        try {
            Class<?> c = Class.forName(args[0]); // 根据输入的类名通过反射获得其Class

            out.format("Class:%n  %s%n%n", c.getCanonicalName()); // 获得完全限定名

            out.format("Modifiers:%n  %s%n%n",
                   Modifier.toString(c.getModifiers())); // 获得修饰符

            out.format("Type Parameters:%n");
            TypeVariable[] tv = c.getTypeParameters();
            if (tv.length != 0) {
                out.format("  ");

                for (TypeVariable t : tv)
                    out.format("%s ", t.getName()); // 输出类型参数

                out.format("%n%n");
            } else {
                  out.format("  -- No Type Parameters --%n%n");
            }

            out.format("Implemented Interfaces:%n");
            Type[] intfs = c.getGenericInterfaces();

            if (intfs.length != 0) {
                for (Type intf : intfs)
                    out.format("  %s%n", intf.toString()); // 输出实现的接口
                out.format("%n");
            } else {
                  out.format("  -- No Implemented Interfaces --%n%n");
            }

            out.format("Inheritance Path:%n");
            List<Class> l = new ArrayList<Class>();
            printAncestor(c, l);
            if (l.size() != 0) {
                for (Class<?> cl : l)
                    out.format("  %s%n", cl.getCanonicalName());

                out.format("%n");
            } else {
                  out.format("  -- No Super Classes --%n%n");
            }

            out.format("Annotations:%n");
            Annotation[] ann = c.getAnnotations();
            if (ann.length != 0) {
                for (Annotation a : ann)
                    out.format("  %s%n", a.toString()); // 输出注解

                out.format("%n");
            } else {
                  out.format("  -- No Annotations --%n%n");
            }

              // 生产环境的代码应该更优雅的处理这个异常
        } catch (ClassNotFoundException x) {
            x.printStackTrace();
        }
    }

    private static void printAncestor(Class<?> c, List<Class> l) {
        Class<?> ancestor = c.getSuperclass(); // 获得其父类
        if (ancestor != null) {
            l.add(ancestor);
            printAncestor(ancestor, l);
        }
    }
}

下面看看使用上面程序的实例:

$ java ClassDeclarationSpy java.util.concurrent.ConcurrentNavigableMap
Class:
  java.util.concurrent.ConcurrentNavigableMap

Modifiers:
  public abstract interface

Type Parameters:
  K V

Implemented Interfaces:
  java.util.concurrent.ConcurrentMap<K, V>
  java.util.NavigableMap<K, V>

Inheritance Path:
  -- No Super Classes --

Annotations:
  -- No Annotations --

这是一个真实的类java.util.concurrent.ConcurrentNavigableMap,它的源代码是:

public interface ConcurrentNavigableMap<K,V>
    extends ConcurrentMap<K,V>, NavigableMap<K,V>

注意,既然这是一个接口,那么它隐式的为abstract,编译器会为每个接口添加这个修饰符。

1.3 探索Class的成员

相关文章

  • Java反射机制入门

    Java反射机制入门 一、什么是反射 JAVA反射机制(The JAVA reflection mechanism...

  • 反射之一

    总结内容源自一下文章粗浅看java反射机制反射机制应用实践谈谈java反射机制Java Reflection(反射...

  • 反射之二

    总结内容源自一下文章粗浅看java反射机制反射机制应用实践谈谈java反射机制Java Reflection(反射...

  • java反射机制

    java的反射机制 1 JAVA的反射机制是什么?反射机制能做什么?反射机制的优点与缺点2 认识 Class...

  • Java基础之反射

    Java基础之—反射(非常重要)Java中反射机制详解Java进阶之reflection(反射机制)——反射概念与...

  • 反射之三

    总结内容源自以下文章 粗浅看java反射机制 反射机制应用实践 谈谈java反射机制 Java Reflectio...

  • Java中反射的用途

    Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在。灵活掌握Java反射机制,对大家以后学习框...

  • 详解Java反射机制(Reflection)

    详解Java反射机制(Reflection) 反射机制的作用 JAVA反射机制是在运行状态中,对于任意一个类,都能...

  • Chapter 13 . 反射机制

    阅读原文 Chapter 13 . 反射机制 13.1 Java反射机制研究及应用 Java Reflection...

  • Java 反射教程

    Java 反射机制教程 Java 反射机制可以让我们在编译期(Compile Time)之外的运行期(Runtim...

网友评论

      本文标题:Java的反射机制

      本文链接:https://www.haomeiwen.com/subject/hfjcdttx.html