java-反射知识

Class类的方法:

在这里插入图片描述

获取构造函数

getConstructor方法,反射返回一个Constructor类对象,包括子类的构造器
getDeclaredConstructor方法,也是反射返回一个Constructor类对象,不包括继承的子类构造器

//返回 Constructor 对象数组
Constructor<?>[] getDeclaredConstructors()
Constructor<?>[] getConstructors()       

// 返回指定参数的 Constructor 对象
Constructor<T> getConstructor(Class<?>... parameterTypes)     
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 

获取成员变量

getFiled方法,反射返回一个Field类对象,仅包括public声明的字段属性。
getDeclaredFiled方法,反射返回一个Field类对象,包括所有声明的字段属性

// 返回 Field 对象数组
Field[] getFields() 
Field[] getDeclaredFields() 

// 返回指定的 Field 对象 
Field getField(String name) 
Field getDeclaredField(String name) 

获取成员方法

getMethod方法,反射返回的是一个Method类对象,返回的是公共成员方法
getDeclaredMethod方法,反射返回一个Method类对象,返回的是所有声明的成员方法。

// 返回 Method 对象数组 
Method[] getMethods() 
Method[] getDeclaredMethods() 

/ 返回指定的 Method 对象 
Method getMethod(String name, Class<?>... parameterTypes) 
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 

获取注解方法

// 返回指定 Annotation 对象
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) {
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {

// 返回 Annotation 对象数组
Annotation[] getDeclaredAnnotations()
public Annotation[] getAnnotations ()

创建对象的方法

forName(String ClassName)静态方法,获取一个类的Class对象,在类加载器的加载阶段就获取到了。
isInstance方法,是一个Native方法,与instanceof关键字产生的效果是一样的。
newInstance方法,创建指定类型T的一个实例,主要是反射出来其构造器,再调用构造器创建新实例对象。
cast强制类型转换方法

// 创建此 Class 对象所表示的类的一个新实例
T newInstance() 

返回字符串(String)的方法

// 返回底层类的规范化名称 
String getCanonicalName() 

// 返回全限定名(全限定名:包名.类名)
String getName() 

// 返回源代码中给出的底层类的简称
String getSimpleName() 

返回 boolean 的方法

// 判断是不是局部类,也就是方法里面的类 
boolean isLocalClass()     

// 判断是不是成员内部类,也就是一个类里面定义的类
boolean isMemberClass()    

// 判断当前类是不是匿名类,匿名类一般用于实例化接口
boolean isAnonymousClass() 

// 如果指定类型的注释存在于此元素上
isAnnotationPresent (Class<? extends Annotation> annotationClass)

// 判断当前Class对象是否是注释类型
boolean isAnnotation() ;

// 判断该类是否是枚举类
boolean isEnum() 

// 判断指定的 Object 是否 Class 的实例
boolean isInstance(Object obj) 

// 判断指定的 Class 对象是否表示一个接口类型
boolean isInterface() 

// 判断指定的 Class 对象是否表示一个基本类型
boolean isPrimitive() 

获取 Class 的修饰符

//返回此类或接口以整数编码的 Java 语言修饰符。
public int getModifiers()

我们可以使用 Class.getModifiers() 获得调用类的修饰符的二进制值,然后使
用 Modifier.toString(int modifiers) 将获取到的二进制值转换为字符串。

如何得到Class的对象呢?有三种方法可以的获取:

1、调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。例如:

MyObject x;

Class c1 = x.getClass();

2、使用Class类的中静态forName()方法获得与字符串对应的Class对象。例如:

Class c2=Class.forName("MyObject"),Employee必须是接口或者类的名字。

3、获取Class类型对象的第三个方法非常简单。如果T是一个Java类型,那么T.class就代表了匹配的类对象。例如

Class cl1 = Manager.class;

Class cl2 = int.class;

Class cl3 = Double[].class;

注意:Class对象实际上描述的只是类型,而这类型未必是类或者接口。例如上面的int.class是一个Class类型的对象。由于历史原因,数组类型的getName方法会返回奇怪的名字。

Class的一些使用技巧

1、forName和newInstance结合起来使用,可以根据存储在字符串中的类名创建对象。例如

Class<?> clazz = Class.forName("类名");
Object obj = clazz.newInstance();

2、虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象。例如:

if(e.getClass() == Employee.class){}
package xq.com.cn;

/**
 * Created by lenovo on 2017/7/4.
 */
public class ClassDemos {

    /**
     * 构造函数
     */
    public ClassDemos() {
        System.out.println("构造方法:classDemo!");
    }

    public static void main(String[] args) throws Exception {
        /**
         *  Class.forName(String):要求JVM查找并加载String指定的类
         *  返回String字符串指定的类
         */
        Class clazz = Class.forName("xq.com.cn.ClassDemos");
        System.out.println("forName==" + clazz);//class xq.com.cn.ClassDemos
        /**
         * clazz.newInstance()
         * 返回的类所代表的一个实例和new ClassDemo()效果是一样的。
         */
        ClassDemos classDemo = (ClassDemos) clazz.newInstance();
        System.out.println("newInstance==" + classDemo);//xq.com.cn.ClassDemos@1540e19d
    }

}

打印结果:

forName==class xq.com.cn.ClassDemos
构造方法:classDemo!
newInstance==xq.com.cn.ClassDemos@1540e19d

可见:
Class.forName(“”)返回的是类
Class.forName(“”).newInstance()返回的是类的对象

// 以下为一样的效果。 

A a = (A)Class.forName("pacage.A").newInstance(); 

A a = new A();

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:1、这个 类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。

newInstance()和new的区别:

首先,newInstance( )是一个方法,而new是一个关键字,
其次,Class下的newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数,而使用 new关键字生成对象没有这个限制。

newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。

newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。

forName()方法

这个方法总是返回要加载的类的Class类的实例
1、forName(String className)单参数时, initialize=true
a.总是使用当前类装载器(也就是装载执行forName()请求的类 的类装载器)
b.总是初始化这个被装载的类(当然也包括:装载、连接、初始化)
2、forName(String className, boolean initialize, ClassLoader loader)
a.loader指定装载参数类所用的类装载器,如果null则用bootstrp装载器。
b.initialize=true时,肯定连接,而且初始化了;
c.false时,绝对不会初始化,但是可能被连接了,但是这里有个例外,如果在调用这个forName()前,已经被初始化了,那么返回的类型也肯定是被初始化的(当然,这里也暗含着:被同一个loader所装载的,而且这个类被初始化了)

关于用户自定义的类装载器的loadClass()方法
1、loadClass(String name)单参数时, resolve=false
a.如果这个类已经被这个类装载器所装载,那么,返回这个已经被装载的类型的Class的实例,否则,就用这个自定义的类装载器来装载这个class,这时不知道是否被连接。绝对不会被初始化
b.这时唯一可以保证的是,这个类被装载了。但是不知道这个类是不是被连接和初始化了
2、loadClass(String name, boolean resolve)
a.resolve=true时,则保证已经装载,而且已经连接了。resolve=falses时,则仅仅是去装载这个类,不关心是否连接了,所以此时可能被连接了,也可能没有被连接

参考: 关于Class.forName(className).newInstance()介绍

反射的使用:

写一个简单的类:

package xq.com.cn;

/**
 * Created by lenovo on 2017/7/4.
 */
public class Simple {

    private void displayMessage(String strMsg) {//注意方法私有Private
        System.out.println("message is:" + strMsg);
    }

}

测试类:

import xq.com.cn.Simple;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by lenovo on 2017/7/4.
 */
public class Test {

    public static void main(String[] args) {
		
		/*获取类的方法一:  通过类直接获取*/
        Class<Simple> simpleClass1 = Simple.class;
        System.out.println("class111==" + simpleClass1);//直接获取类

		/*获取类的方法二:  通过对象获取*/
        Simple simple = new Simple();
        Class<? extends Simple> aClass = simple.getClass();//通过对象获取类
        System.out.println("class222===" + aClass);

        try {
	        /*获取类的方法三:  通过反射获取*/
            Class simpleClass = Class.forName("xq.com.cn.Simple");//通过反射获取类
            System.out.println("class333===" + simpleClass);
            Object simpelObject = simpleClass.newInstance();//获取类的实例
            System.out.println("object===" + simpelObject);

            Class[] args1 = new Class[1];
            args1[0] = String.class;
            //获取类的方法,参数为:方法名,参数类型
            Method simpleMethod = simpleClass.getDeclaredMethod("displayMessage", args1);

            //类中的方法为private,故必须进行此操作,
            //如果变量为private则变量需要调用此方法才可访问
            simpleMethod.setAccessible(true);

            String[] argments = new String[1];
            argments[0] = "Hello,world";
            //方法的调用,参数为:对象,参数
            simpleMethod.invoke(simpelObject, argments);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

}

打印结果

class111==class xq.com.cn.Simple
class222===class xq.com.cn.Simple
class333===class xq.com.cn.Simple
object===xq.com.cn.Simple@1540e19d
message is:Hello,world

getDeclaredMethod与getMethod 区别:

getDeclaredMethod() 获取的是类自身声明的所有方法,包含public、protected和private方法。

getMethod () 获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。

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

java.lang.Class.getDeclaredMethod()方法返回一个Method对象,它反映此Class对象所表示的类或接口的指定已声明方法。

name 参数是一个字符串,指定所需的方法的简单名称,即方法名
parameterTypes 参数是一个数组的Class对象识别方法的形参类型,在声明的顺序。

参考:

java.lang.Class.getDeclaredMethod()方法详解

JAVA 反射-getDeclaredMethod()实例

反射中getMethods 与 getDeclaredMethods 的区别

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值