Java架构师第三步——Java反射(读书笔记)

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

包名: java.lang.reflect.*

    Java反射机制是Java语言被视为"准动态"语言的关键性质。Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的内部信息(包括其modifiers(诸如public, static等等)、superclass(例如Object)、实现interfaces(例如Serializable),也包括fields和 methods的所有信息),动态地生成此类,并调用其方法或修改其域(甚至是本身声明为private的域或方法)。

    主要提供了以下功能:

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

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

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

    在运行时调用任意一个对象的方法;

    生成动态代理。

 

1. Object

    1.1 Class<?> getClass()

    Returns the runtime class of this Object.

例: KeyBoard k = new KeyBoard();

     Class<?> clazz = k.getClass(); 或 Class clazz = k.getClass();

 

2. Class

        Class对象是Java反射的基础,它包含了与类相关的信息,事实上,Class对象就是用来创建类的所有对象的。Class对象是java.lang.Class<T>这个类生成的对象,其中类型参数T表示由此 Class 对象建模的类的类型。例如,String.class的类型是 Class<String>;如果将被建模的类未知,则使用Class<?>。以下是Java API的描述:

        Class类的实例表示正在运行的 Java应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象。基本的Java类型(boolean、byte、 char、short、int、long、float和double)和关键字void也表示为Class对象。

        Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。

        每个类都有一个Class对象。换言之,每当编写并且编译了一个新类,就会产生一个Class对象(更恰当的说,是被保存在一个同名的.class文件中)。如果我们想生成这个类的对象,运行这个程序的Java虚拟机(JVM)将使用类加载器子系统,类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件,并将其载入,一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。

获取Class对象有三种方式:

       (1) Object类的getClass()方法,例:

            Class c1 = new String("").getClass();

       (2) Class类的静态方法forName(),例:

            Class c2 = Class.forName(className);

        当使用Class.forName()方法时,必须提供完全限定类名。即类名要包括所有包名。

       (3) 使用类字面常量或TYPE字段,例:

            Class c3 = Manager.class;

            Class c4 = int.class;

            Class c5 = Double[].class;

        这种方式不仅更简单,而且更安全,因为它在编译时就会受到检查,并且根除了对forName方法的调用,也更高效,建议使用“.class”的形式

        TYPE是基本数据类型的包装类型的一个标准字段,它是一个引用,指向对应的基本数据类型的Class对象

 

 

使用Java反射,从类中可以获取以下信息:

(1) 类名

(2) 类修饰符 (public, private, synchronized等)

(3) 包信息

(4) 父类

(5) 实现的接口

(6) 构造函数

(7) 方法

(8) 字段

(9) 注解

(10) 内部类

 

2.1 类名(getName(), getSimpleName())

    从Class对象中可以获取两个不同的类名。完全限定类名(包括包名)可以使用getName()或getCanonicalName()方法获取,例如:

        Class myClazz = MyObject.class;

        String className = myClazz.getName();

        String className1 = myClazz.getCanonicalName();

    如果想要获取不含包名的类名可以使用getSimpleName() 方法,如下:

        String simpleClassName = myClazz.getSimpleName();

 

    2.2 修饰符(getModifiers())

    使用Class对象可以获取一个类的修饰符。类的修饰符即关键字"public","private", "static"等. 如下:

        int modifiers = myClazz.getModifiers();

    修饰符被包装进一个int内,每一个修饰符都是一个标志位(置位或清零)。可以使用java.lang.reflect.Modifier类中的以下方法来检验修饰符:

        Modifier.isAbstract(int modifiers)

        Modifier.isFinal(int modifiers)

        Modifier.isInterface(int modifiers)

        Modifier.isNative(int modifiers)

        Modifier.isPrivate(int modifiers)

        Modifier.isProtected(int modifiers)

        Modifier.isPublic(int modifiers)

        Modifier.isStatic(int modifiers)

        Modifier.isStrict(int modifiers)

        Modifier.isSynchronized(int modifiers)

        Modifier.isTransient(int modifiers)

        Modifier.isVolatile(int modifiers)

 

    2.3 包信息(getPackage())

    使用Class对象可以获取包信息java.lang.Package,如下:

        Package package = myClazz.getPackage();

        String packageName = package.getname();

    从Package对象中你可以访问诸如名字等包信息。您还可以访问类路径上这个包位于JAR文件中Manifest这个文件中指定的信息。

 

    2.4 父类(getSuperclass())

    通过Class对象可以获取类的父类,如下:

        Class superclass = myClazz.getSuperclass();

    父类的Class对象和其它Class对象一样是一个Class对象,可以继续使用反射。

 

    2.5 实现的接口(getInterfaces()), 只有给定类声明实现的接口才会返回

    通过给定的类可以获取这个类所实现的接口列表,如下:

        Class[] interfaces = myClazz.getInterfaces();

    一个类可以实现多个接口。因此返回一个Class数组。在Java反射机制中,接口也由Class对象表示。

    只有给定类声明实现的接口才会返回。例如,如果类A的父类B实现了一个接口C,但类A并没有声明它也实现了C,那么C不会被返回到数组中。即使类A实际上实现了接口C,因为它的父类B实现了C。

    为了得到一个给定的类实现接口的完整列表,需要递归访问类和其超类。

 

    2.6 构造函数

//获取一个公有的构造函数,参数为指定参数
public Constructor<T> getConstructor (Class...<?> parameterTypes)
//获取目标类所有的公有构造函数
public Constructor[]<?> getConstructors ()
// 获取目标类的一个构造函数,参数为指定参数
public Constructor<T> getDeclaredConstructor (Class...<?> parameterTypes)
// 获取目标类所有的公有构造函数
public Constructor[]<?> getDeclaredConstructors ()

    2.7 方法

    这里需要注意的是 getDeclaredMethod 和 getDeclaredMethods 包含private、protected、default、public的函数,并且通过这两个函数获取到的只是在自身中定义的函数,也包括自己实现的接口,从父类和接口中继承的函数不能够获取到。而 getMethod 和 getMethods 只包含 public 函数,父类和接口中继承的公有函数也能够获取到。

 

//获取该类中的指定参数的某一方法, 可以是private、protected、default、public的, (不包含从父类和接口继承的).

public Method getDeclaredMethod (String name, Class...<?> parameterTypes)

//获取该类中的所有函数(不包含从父类继承的函数).
public Method[] getDeclaredMethods ()

//获取该类指定参数的某一公有函数, (包含从父类和接口类继承下来的)
public Method getMethod (String name, Class...<?> parameterTypes)

//获取该类所有公有函数, (包含从父类和接口类集成下来的函数)
public Method[] getMethods ()

    2.8 字段

    getDeclaredField 和 getDeclaredFields 包含 private、protected、default、public 的属性,并且通过这两个函数获取到的只是在自身中定义的属性,从父类中集成的属性不能够获取到。而 getField 和 getFields 只包含 public 属性,父类中的公有属性也能够获取到。

// 获取 Class 对象中指定属性名的某一属性

public Method getDeclaredField (String name)

// 获取该 Class 对象中的所有属性( 不包含从父类继承的属性 )
public Method[] getDeclaredFields ()
// 获取指定的Class对象中指定属性名的某一公有属性
public Method getField (String name)
// 获取该Class对象中的所有公有属性 ( 包含从父类和接口类继承下来的公有属性 )
public Method[] getFields ()

    2.9 注解

// 获取该类某一指定公有注解
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
// 获取该类所有公有注解
public Annotation[] getAnnotations()
// 获取该类某一注解
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass)
// 获取该类所有注解
public Annotation[] getDeclaredAnnotations()

    2.10 内部类

// 获取该类公有内部类(包含父类)
public Class<?>[] getClasses()
// 获取该类所有内部类,包含私有内部类。
public Class<?>[] getDeclaredClasses()
// 获取该类的外部类
public Class<?> getDeclaringClass()

    2.11 其它方法

// ([自身类.class]).isAssignableFrom([自身类.class]或[其子类.class])  返回true

isAssignableFrom(Class<?> cls)

 

// ([自身类.class]).isInstance([自身类的实例obj]或[其子类的实例obj])  返回true

isInstance(Object obj)

 

// 这里不是Class成员方法,是一个运算符,放在这里一起比较;

// [实例obj] instanceof [自身类、其父类、抽象类或接口],右边使用的是简单类名,而不是Class。

instanceof

 

// 生成本类的对象,只能调用无参构造。我们使用new的时候,这个要new的类可以没有加载。使用newInstance时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。Class的静态方法forName()调用了启动类加载器(就是加载javaAPI的那个加载器)。newInstance实际上是把new这个方式分解为两步,即,首先调用class的加载方法加载某个类,然后实例化。这样分步的好处是显而易见的。我们可以在调用Class的静态加载方法forName()时获得更好的灵活性(传入的className可以是从任何地方获取的),提供给了我们降耦的手段。

newInstance()

 

// 返回当前clazz是否为成员类;

isMemberClass()

 

// 返回当前类是否为接口;

isInterface()

 

 

3. Constructor

// 返回当前Constructor实例所在的Class.

Class<T> getDeclaringClass()

 

// 返回当前Constructor实例参数个数.

int getParameterCount()

 

// 返回当前Constructor实例各参数对应的Class类型.

Class<?>[] getParameterTypes()

 

// 返回当前Constructor实例的各参数类型.

TypeVariable<Constructor<T>>[] getTypeParameters()

 

// 返回当前Constructor实例对应的方法修饰符.

int getModifiers()

 

// 返回当前方法名.

String getName()

 

// 使用当前Constructor实例构造一个该Constructor实例所在的Class的实例,相当于调用其对应参数个数的构造方法.

T newInstance(Object... initargs)

 

 

4. Field

// 返回指定对象obj上Field对象表示的字段的值。

Object get(Object obj)

 

// 将指定对象变量obj上此Field对象表示的字段设置为指定的新值。

void set(Object obj, Object value)

 

// 返回一个Class对象,它标识了此Field对象所表示字段的声明类型。

Class<?> getType()

 

// 返回表示类或接口的Class对象,该类或接口声明了由此Field对象表示的字段。

Class<?> getDeclaringClass()

 

// 返回此Field对象表示的字段的名称。

String getName()

 

// 以整数形式返回由此Field对象表示的字段的 Java 语言修饰符。

int getModifiers()

 

 

5. Method

// 以指定参数调用obj对象的此Method所表示的方法。

Object invoke(Object obj, Object... args)

 

// 返回此Method实例参数个数.

int getParameterCount()

 

// 返回此Method实例各参数对应的Class类型.

Class<?>[] getParameterTypes()

 

// 返回此Method实例的各参数类型.

TypeVariable<Constructor<T>>[] getTypeParameters()

 

// 返回此Method实例的返回值类型.

Class<?> getReturnType()

 

// 返回表示类或接口的Class对象,该类或接口声明了由此Method对象表示的方法。

Class<?> getDeclaringClass()


// 返回此Method对象表示的方法的名称。

String getName()

 

// 以整数形式返回由此Method对象表示的方法的 Java 语言修饰符。

int getModifiers()

转载于:https://my.oschina.net/u/3448620/blog/967956

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值