java-反射

来源:互联网 发布:大拿韩代 淘宝 编辑:程序博客网 时间:2024/06/07 00:10
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.Simpleclass222===class xq.com.cn.Simpleclass333===class xq.com.cn.Simpleobject===xq.com.cn.Simple@1540e19dmessage 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 的区别

原创粉丝点击