所有分类
  • 所有分类
  • 未分类

Java反射-通过反射实例化对象

简介

本文用示例介绍Java通过反射来实例化对象的方法。

Class.forName和ClassLoader的区别

关系

Class.forName()方法也是调用的 ClassLoader 来实现的。

区别

Class.forNameClassLoader
灵活度灵活度低。 例如:加载的类只能是classpath下的灵活度高。 例如:可以自己编写加载类的方法:比如通过读取类文件的二进制数据,这个时候文件可以不存在ClassPath中。
是否进行初始化是。 forName方法最后调用 forName0(本地方法),第二个参数设置为了 true,代表对加载的类进行初始化(执行静态代码块、对静态变量赋值)否。

forName

 @CallerSensitive
 public static Class<?> forName(String className)
             throws ClassNotFoundException {
     Class<?> caller = Reflection.getCallerClass();
     return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
 }

它有个重载(可以手动选择在加载类时是否要对其类进行初始化。)

  public static Class<?> forName(String name, boolean initialize,
                                 ClassLoader loader){}

实例(forName)

package org.example.a;

class Test {
    static {
        System.out.println("静态代码块");
    }
    public static final String title = getTitle();

    private static String getTitle(){
        System.out.println("执行getTitle()");
        return "TITLE";
    }
}

public class Demo {
    public static void main(String[] args) {
        Class<?> c = null;
        try {
            c = Class.forName("org.example.a.Test");
        }catch (Exception e){
            e.printStackTrace();
        }

        Test test = null;
        try {
            test = (Test) c.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

执行结果

静态代码块
执行getTitle() 

实例(ClassLoader)

package org.example.a;

class Test {
    static {
        System.out.println("静态代码块");
    }
    public static final String title = getTitle();

    private static String getTitle(){
        System.out.println("执行getTitle()");
        return "TITLE";
    }
}

public class Demo {
    public static void main(String[] args) {
        Class<?> c = null;
        try {
            c = ClassLoader.getSystemClassLoader().loadClass("org.example.a.Test");
        }catch (Exception e){
            e.printStackTrace();
        }

        Test test = null;
        try {
            test = (Test) c.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

执行结果

无任何输出。

无参与有参构造

 前边示例是无参构造,也可以有参构造:

package org.example.a;

import java.lang.reflect.Constructor;

class Test {
    String name;
    public Test(String name) {
        this.name = name;
    }

    static {
        System.out.println("静态代码块");
    }
    public static final String title = getTitle();

    private static String getTitle(){
        System.out.println("执行getTitle()");
        return "TITLE";
    }
}

public class Demo {
    public static void main(String[] args) {
        Class<?> c = null;
        try {
            c = Class.forName("org.example.a.Test");
        }catch (Exception e){
            e.printStackTrace();
        }

        Constructor<?> cons[] = c.getConstructors();

        Test test = null;
        try {
            test = (Test) cons[0].newInstance("Tony");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

执行结果

静态代码块
执行getTitle()

JDBC为什么用Class.forName

JDBC 规范中明确要求 Driver(数据库驱动)类必须向 DriverManager 注册。

以 MySQL 的驱动为例,我们看到 Driver 注册到 DriverManager 中的操作写在了静态代码块中,这就是为什么在写 JDBC 时使用 Class.forName() 的原因了。

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }
    /**
     * Construct a new driver and register it with DriverManager
     * 
     * @throws SQLException
     *             if a database error occurs.
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}
12

评论4

请先

  1. 这里是不是应该先执行静态代码快,再给静态变量赋值?
    CanCanNeed 2023-11-03 0
    • 是的。详细的类加载过程可以看这里:https://way2j.com/a/406
      自学精灵 2023-11-03 2
      • 但博主你的 JVM原理–类加载过程这篇文章里面是先赋值再执行的静态代码块
        CanCanNeed 2023-11-03 0
        • 我上边的回复的意思是:此文章里是先执行静态代码块。 实际上,静态代码块和静态变量赋值是由代码的顺序决定的,谁在上边谁先执行,这个链接很详细:https://way2j.com/a/406
          自学精灵 2023-11-04 2
显示验证码
没有账号?注册  忘记密码?

社交账号快速登录