Java反射机制(看着源码学)

Java反射机制( java.lang.reflect )

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

获取 Class 对象方法:

Class.forName(), classLoader.loadClass(), class.getClass()

Class 类方法:

getClassLoader(): ClassLoader
forName(String className): Class<?>
getDeclaredMethod(String name, Class<?>... parameterTypes): Method
getDeclaredField(String name): Field
getConstructor(Class<?>... parameterTypes): Constructor<T>

Class.forName()classLoader.loadClass() 的区别:

  1. Class.forName() 在类加载的时候会执行静态代码块, 而 classLoader.loadClass() 只有在调用 newInstance() 时才会执行静态代码块

  2. 初始化不同:
    Class.forName() 会对类初始化,而loadClass()只会装载或链接。可见的效果就是类中静态初始化段及字节码中对所有静态成员的初始工作的执行(这个过程在类的所有父类中递归地调用)。这点就与 classLoader.loadClass() 不同。 classLoader.loadClass() 加载的类对象是在第一次被调用时才进行初始化的。你可以利用上述的差异.比如,要加载一个静态初始化开销很大的类,你就可以选择提前加载该类(以确保它在classpath下),但不进行初始化,直到第一次使用该类的域或方法时才进行初始化

  3. 类加载器不同:
    Class.forName(String) 方法(只有一个参数),使用调用者的类加载器来加载,也就是用加载了调用 forName() 方法的代码的那个类加载器。当然,它也有个重载的方法,可以指定加载器。相应的, classLoader.loadClass() 方法是一个实例方法(非静态方法),调用时需要自己指定类加载器,那么这个类加载器就可能是也可能不是加载调用代码的类加载器(调用代码类加载器通过getClassLoader())获得

Class.forName(String) :

/**
     * Returns the {@code Class} object associated with the class or
     * interface with the given string name.  Invoking this method is
     * equivalent to:
     *
     * <blockquote>
     *  {@code Class.forName(className, true, currentLoader)}
     * </blockquote>
     *
     * where {@code currentLoader} denotes the defining class loader of
     * the current class.
     *
     * <p> For example, the following code fragment returns the
     * runtime {@code Class} descriptor for the class named
     * {@code java.lang.Thread}:
     *
     * <blockquote>
     *   {@code Class t = Class.forName("java.lang.Thread")}
     * </blockquote>
     * <p>
     * A call to {@code forName("X")} causes the class named                                //会被初始化
     * {@code X} to be initialized.
     *
     * @param      className   the fully qualified name of the desired class.
     * @return     the {@code Class} object for the class with the
     *             specified name.
     * @exception LinkageError if the linkage fails
     * @exception ExceptionInInitializerError if the initialization provoked
     *            by this method fails
     * @exception ClassNotFoundException if the class cannot be located
     */
    @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

classLoader.loadClass() :

/**
     * Loads the class with the specified <a href="#binary-name">binary name</a>.
     * This method searches for classes in the same manner as the {@link
     * #loadClass(String, boolean)} method.  It is invoked by the Java virtual
     * machine to resolve class references.  Invoking this method is equivalent
     * to invoking {@link #loadClass(String, boolean) loadClass(name,
     * false)}.
     *
     * @param  name
     *         The <a href="#binary-name">binary name</a> of the class
     *
     * @return  The resulting {@code Class} object
     *
     * @throws  ClassNotFoundException
     *          If the class was not found
     */
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

注意:源码中的 binary name 指的是类的原名(如: Objectbinary namejava.lang.Object )

测试用例:

public class Line {
    static {
        System.out.println("Line - 静态代码块执行了");
    }
}

public class Point {
    static {
        System.out.println("Point - 静态代码块执行了");
    }
}

public class ReflectTest {
    public static void main(String[] args) {
        String wholeNameLine = "SourceDoc.Line";
        String wholeNamePoint = "SourceDoc.Point";
        System.out.println("下面是测试ClassLoader.loadClass()的效果");
        testClassloader(wholeNameLine, wholeNamePoint);

        System.out.println("----------------------------------");
        System.out.println("下面是测试Class.forName()的效果");
        testForName(wholeNameLine, wholeNamePoint);
    }

    private static void testClassloader(String wholeNameLine, String wholeNamePoint) {
        Class<?> line;
        Class<?> point;
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        try {
            line = classLoader.loadClass(wholeNameLine);
            point = classLoader.loadClass(wholeNamePoint);

            System.out.println("line   " + line.getName());
            System.out.println("point   " + point.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void testForName(String wholeNameLine, String wholeNamePoint) {
        try {
            Class<?> line = Class.forName(wholeNameLine);
            Class<?> point = Class.forName(wholeNamePoint);
            System.out.println("line   " + line.getName());
            System.out.println("point   " + point.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

执行结果如下:

下面是测试Classloader的效果
line   SourceDoc.Line
point   SourceDoc.Point
----------------------------------
下面是测试Class.forName()的效果
Line - 静态代码块执行了
Point - 静态代码块执行了
line   SourceDoc.Line
point   SourceDoc.Point
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值