精华内容
下载资源
问答
  • Java反射中,为什么推荐Class.forName()获取class
    千次阅读
    2021-03-06 09:10:30

    一、Java反射中获取Class对象的三种方式

    在Java反射中,反射的入口就是class,获取class的方式有三种

    1. Class.class;
    2. Class.forName();
    3. 对象.getClass()

    对三者的简单理解

    1. Class.class的形式会使JVM使用类加载器将类装入内存(前提是类还没有装入内存),不做类的初始化工作,返回Class对象。
    2. Class.forName()的形式会装入类并做类的静态初始化,返回Class对象。
    3. 对象.getClass的形式会对类进行静态初始化、非静态初始化,返回引用运行时真正所指的对象(因为子对象的引用可能会赋给父对象的引用变量中)所属的类的Class对象。

    静态初始化是指在加载类的时候初始化,而非静态初始化是new对象的时候初始化。

    三种情况在生成Class对象的时候都会判断内存中是否已经加载此类。

    注:只有使用Class.forName()时才会进行异常处理,因为Class.forName()要加载类路径,避免找不到的情况发生。

    二、Class.forName源码分析

    Class.forName(String className);这个方法的源码是

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

    Class.forName()调用forName0方法,forName0的第二个参数被默认设置为true,这个参数代表是否对加载的类进行初始化,设置为true表示进行类初始化,代表会执行类中的静态代码块,以及对静态常量的赋值等操作。

    可以清楚的看到Class.forName()方法实际上是调用ClassLoader来实现的。

    ClassLoader是遵循双亲委派模型,调用启动类加载器的类加载器,实现的功能是“通过一个类的全限定名来获取描述此类的二进制字节流”,获取到二进制流后放到JVM中。

    三、为什么推荐Class.forName()获取class?

    Class.forName(),我相信我们第一次接触它的时候,大多数是在学习JDBC的时候。

    使用JDBC时通常使用Class.forName()方法来加载数据库连接驱动。这是因为在JDBC规范中明确要求Driver(数据库驱动)类必须向DriverManager注册自己。

    以MySQL的驱动为例解释:

    public class Driver extends NonRegisteringDriver implements java.sql.Driver {  
    
        static {  
            try {  
                java.sql.DriverManager.registerDriver(new Driver());  
            } catch (SQLException E) {  
                throw new RuntimeException("Can't register driver!");  
            }  
        } 
        ... 
    }

    通过源码可以看出Driver注册到DriverManager中的操作写在了静态代码块中,这就是为什么在写JDBC时使用Class.forName()的原因。

    Class.forName()在加载数据库驱动时,是一种破坏双亲委派机制的使用,通过Application ClassLoader来加载一个第三方类,并没有使用父级的Bootstrap ClassLoad加载器。

    总之一句话,推荐使用Class.forName()方法获取Class的最重要原因就是Class.forName()方法做了类的静态初始化(Class.class方法没有进行类的静态初始化;对象.getClass()方法虽然也做了静态初始化,但还需要new一个对象出来,不是很方便)。

     

     

    参考:

    简单谈谈你对 Java 中 Class.forName()、Class.class、getClass() 三者的理解?

    在Java的反射中,Class.forName和ClassLoader的区别

    更多相关内容
  • Class.forName()用法详解

    万次阅读 多人点赞 2020-07-18 15:12:39
    4 Class.forName()用法 4.1 什么时候用Class.forName()? 4.2 newInstance和new关键字的区别 5 应用问题解析 情景一:载入数据库驱动的时候 情景二:使用AIDL与电话管理Servic进行通信 1.什么是class对象 类...

    目录

    1.什么是class对象

    2.获得class对象的三种方法

    3.class的作用和方法

    4 Class.forName()用法

    4.1 什么时候用Class.forName()?

    4.2 newInstance和new关键字的区别

    5 应用问题解析

    情景一:载入数据库驱动的时候

    情景二:使用AIDL与电话管理Servic进行通信


    1.什么是class对象

          类是程序的一部分,每个类都有一个class对象。换言之,每当编写并且编译了一个新类,就会产生一个class对象(更恰当的说,是被保存在一个同名的class文件中)。为了生成这个类的对象,运行这个程序的Java虚拟机(jvm)将使用被称为“类加载器”的子系统。

        所有的类都是在对其第一次使用的时候被加载到JVM中。如当程序创建对第一个静态成员的引用时,就会加载这个类。或者使用new关键字创建新的对象的时候。

        因此java程序在它运行之前并非完全加载,其各个部分是在必须的时候才加载的。类加载器首先检查这个类的class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件。

    实际上在Java中每个类都有且只有一个Class对象。

         Class 没有公共构造方法,因此不能显式地声明一个Class对象,Class 对象是在载入类时由Java 虚拟机以及通过调用类载入器中的 defineClass 方法自己主动构造的。

    Class类被创建后的对象就是Class对象,注意,Class对象表示的是自己手动编写类的类型信息,比如创建一个Shapes类,那么,JVM就会创建一个Shapes对应Class类的Class对象,该Class对象保存了Shapes类相关的类型信息。实际上在Java中每个类都有一个Class对象,每当我们编写并且编译一个新创建的类就会产生一个对应Class对象并且这个Class对象会被保存在同名.class文件里(编译后的字节码文件保存的就是Class对象),那为什么需要这样一个Class对象呢?是这样的,当我们new一个新对象或者引用静态成员变量时,Java虚拟机(JVM)中的类加载器子系统会将对应Class对象加载到JVM中,然后JVM再根据这个类型信息相关的Class对象创建我们需要实例对象或者提供静态变量的引用值。需要特别注意的是,手动编写的每个class类,无论创建多少个实例对象,在JVM中都只有一个Class对象,即在内存中每个类有且只有一个相对应的Class对象,挺拗口,通过下图理解(内存中的简易现象图):

    到这我们也就可以得出以下几点信息:

    • Class类也是类的一种,与class关键字是不一样的。

    • 手动编写的类被编译后会产生一个Class对象,其表示的是创建的类的类型信息,而且这个Class对象保存在同名.class的文件中(字节码文件),比如创建一个Shapes类,编译Shapes类后就会创建其包含Shapes类相关类型信息的Class对象,并保存在Shapes.class字节码文件中。

    • 每个通过关键字class标识的类,在内存中有且只有一个与之对应的Class对象来描述其类型信息,无论创建多少个实例对象,其依据的都是用一个Class对象。

    • Class类只存私有构造函数,因此对应Class对象只能有JVM创建和加载

    • Class类的对象作用是运行时提供或获得某个对象的类型信息,这点对于反射技术很重要(关于反射稍后分析)。

    2.获得class对象的三种方法

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

    MyObject x;
    Class c1 = x.getClass();

    .Object.getClass();  Object中自带的方法,getclass(),返回一个class对象。

    2、使用Class类的中静态forName()方法获得与字符串相应的Class对象。比如: 
        Class c2=Class.forName("MyObject"),MyObject必须是接口或者类的名字。

    class.forname()  

    Class c=Class.forName("类的全限定名")

       传入string类型参数,要求jvm查找并加载指定的类,返回的是一个class对象的引用。

    3、获取Class类型对象的第三个方法很easy。假设T是一个Java类型。那么T.class就代表了匹配的类对象。

    比如

    Class cl1 = Manager.class;
    Class cl2 = int.class;
    Class cl3 = Double[].class;

    注意:Class对象实际上描写叙述的仅仅是类型。而这类型未必是类或者接口。

    比如上面的int.class是一个Class类型的对象。

    因为历史原因。数组类型的getName方法会返回奇怪的名字。

    3.class的作用和方法

    • getname():以string类型返回class对象表示的实体(类,接口,数组,基本类型,void等)名称
    • newInstance():创建一个实例,只能调用默认构造器。
    • getsuperclass():返回class表示的实体超类的名称
    • getSimpleName()。不办含包名的类名。
    • isInterfence:告诉你这个class对象是否表示某个接口。

    1、getName() 

    一个Class对象描写叙述了一个特定类的属性,Class类中最经常使用的方法getName以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。

    2、newInstance()

    Class另一个实用的方法能够为类创建一个实例,这种方法叫做newInstance()。比如:
        x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调用默认构造器(无參数构造器)初始化新建对象。

    3、getClassLoader() 

    返回该类的类载入器。

       4、getComponentType() 
        返回表示数组组件类型的 Class。

       5、getSuperclass() 
        返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。

       6、isArray() 
        判定此 Class 对象是否表示一个数组类。

    1、forName和newInstance结合起来使用,能够依据存储在字符串中的类名创建对象。比如
        Object obj = Class.forName(s).newInstance();

    2、虚拟机为每种类型管理一个独一无二的Class对象。因此能够使用==操作符来比較类对象。比如:
        if(e.getClass() == Employee.class)...

    4 Class.forName()用法

    主要功能
    Class.forName(xxx.xx.xx)返回的是一个类。
    Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。

    Class.forName是一个静态方法,相同能够用来载入类。

    该方法有两种形式:Class.forName(String name, boolean initialize, ClassLoader loader)和 Class.forName(String className)。

    第一种形式的參数 name表示的是类的全名;initialize表示是否初始化类。loader表示载入时使用的类载入器。

    另外一种形式则相当于设置了參数 initialize的值为 true。loader的值为当前类的类载入器

    4.1 什么时候用Class.forName()?

        先来个热身,给你一个字符串变量,它代表一个类的包名和类名,你怎么实例化它?你第一想到的肯定是new,但是注意一点:
    A a = (A)Class.forName(“pacage.A”).newInstance();
    这和你 A a = new A(); 是一样的效果。

    现在言归正传。
    动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象时需要用到:

    • String str = “用户输入的字符串” ;
    • Class t = Class.forName(str);
    • t.newInstance();

    在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?

    它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。

    4.2 newInstance和new关键字的区别

    Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。 例如:

    class c = Class.forName(“Example”);
    factory = (ExampleInterface)c.newInstance();

    其中ExampleInterface是Example的接口,可以写成如下形式:

    String className = “Example”;
    class c = Class.forName(className);
    factory = (ExampleInterface)c.newInstance();

    进一步可以写成如下形式:

    String className = readfromXMlConfig;//从xml 配置文件中获得字符串
    class c = Class.forName(className);
    factory = (ExampleInterface)c.newInstance();

    上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。

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

    现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。

    这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。

    最后用最简单的描述来区分new关键字和newInstance()方法的区别: 

    • newInstance: 弱类型。低效率。只能调用无参构造。 
    • new: 强类型。相对高效。能调用任何public构造。
    • Class.forName(“”)返回的是类。
    • Class.forName(“”).newInstance()返回的是object

    5 应用问题解析

    情景一:载入数据库驱动的时候

    Class.forName的一个非经常见的使用方法是在载入数据库驱动的时候

    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    Connection con=DriverManager.getConnection("jdbc:sqlserver://localhost:1433;DatabaseName==JSP","jph","jph");  

    为什么在我们载入数据库驱动包的时候有的却没有调用newInstance( )方法呢?

    即有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一些:Class.forName(xxx.xx.xx).newInstance()。为什么会有这两种写法呢? 

     通过查询Java Documentation我们会发现使用Class.forName( )静态方法的目的是为了动态加载类。通常编码过程中,在加载完成后,一般还要调用Class下的newInstance( )静态方法来实例化对象以便操作。因此,单使用Class.forName( )是动态加载类是没有用的,其最终目的是为了实例化对象。

    刚才提到,Class.forName("");的作用是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码 段。而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC Driver的 Driver类的代码都必须类似如下:

    public class MyJDBCDriver implements Driver {
       static {
         DriverManager.registerDriver(new MyJDBCDriver());
      }
      }

     既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。

     既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。

    public class ProxoolDriver implements Driver {
    
        private static final Log LOG = LogFactory.getLog(ProxoolDriver.class);
    
        static {
            try {
                DriverManager.registerDriver(new ProxoolDriver());
            } catch (SQLException e) {
                System.out.println(e.toString());
            }
        }
    
    }

    情景二:使用AIDL与电话管理Servic进行通信

    Method method =Class.forName("android.os.ServiceManager")
    
             .getMethod("getService",String.class);
    
    // 获取远程TELEPHONY_SERVICE的IBinder对象的代理
    
    IBinder binder =(IBinder) method.invoke(null, new Object[] { TELEPHONY_SERVICE});
    
    // 将IBinder对象的代理转换为ITelephony对象
    
    ITelephonytelephony = ITelephony.Stub.asInterface(binder);
    
    // 挂断电话
    
    telephony.endCall();
    

     

    展开全文
  • Jvm把class文件字节码加载到内存中,并将这些静态数据装换成运行时数据区中方法区的类型数据,在运行时数据区堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。 *注:方法区不仅仅是存放...

    欢迎大家关注我的公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。

    一、区别

    java类装载过程分为3步:

    在这里插入图片描述

    1、加载
    Jvm把class文件字节码加载到内存中,并将这些静态数据装换成运行时数据区中方法区的类型数据,在运行时数据区堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。
    *注:方法区不仅仅是存放方法,它存放的是类的类型信息。

    2、链接:执行下面的校验、准备和解析步骤,其中解析步骤是可选的
    a:校验:检查加载的class文件的正确性和安全性
    b:准备:为类变量分配存储空间并设置类变量初始值,类变量随类型信息存放在方法区中,生命周期很长,使用不当和容易造成内存泄漏。
    *注:类变量就是static变量;初始值指的是类变量类型的默认值而不是实际要赋的值
    c:解析:jvm将常量池内的符号引用转换为直接引用

    3、初始化:执行类变量赋值和静态代码块

    在了解了类装载过程之后我们继续比较二者区别:
    Classloder.loaderClass(String name)
    其实该方法内部调用的是:Classloder. loadClass(name, false)
    方法:Classloder. loadClass(String name, boolean resolve)
    a:参数name代表类的全限定类名
    b:参数resolve代表是否解析,resolve为true是解析该类

    Class.forName(String name)
    其实该方法内部调用的是:Class.forName(className, true, ClassLoader.getClassLoader(caller))
    方法:Class.forName0(String name, boolean initialize, ClassLoader loader)

    参数name代表全限定类名

    参数initialize表示是否初始化该类,为true是初始化该类

    参数loader 对应的类加载器

    两者最大的区别
    Class.forName得到的class是已经初始化完成的
    Classloder.loaderClass得到的class是还没有链接的

    二、代码演示

    java中class.forName()和classLoader都可用来对类进行加载。
    class.forName()前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。
    而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
    Class.forName(name, initialize, loader)带参函数也可控制是否加载static块。并且只有调用了newInstance()方法采用调用构造函数,创建类的对象。

    看下Class.forName()源码:

    	//Class.forName(String className)  这是1.8的源码
        public static Class<?> forName(String className) throws ClassNotFoundException {
            Class<?> caller = Reflection.getCallerClass();
            return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
        }
    	//注意第二个参数,是指Class被loading后是不是必须被初始化。 不初始化就是不执行static的代码即静态代码
    

    接着测试代码证明上面的结论是OK的,如下:

    package com.reflect;
    
    public class Line {
        static {
            System.out.println("静态代码块执行: loading line");
        }
    }
    
    package com.reflect;
    
    public class Point {
        static {
            System.out.println("静态代码块执行: loading point");
        }
    }
    
    package com.reflect;
    
    public class ClassloaderAndForNameTest {
        public static void main(String[] args) {
            String wholeNameLine = "com.reflect.Line";
            String wholeNamePoint = "com.reflect.Point";
            System.out.println("下面是测试Classloader的效果");
            testClassloader(wholeNameLine, wholeNamePoint);
            System.out.println("----------------------------------");
            System.out.println("下面是测试Class.forName的效果");
            testForName(wholeNameLine, wholeNamePoint);
        }
    
        /**
         * classloader
         * @param wholeNameLine
         * @param wholeNamePoint
         */
        private static void testClassloader(String wholeNameLine, String wholeNamePoint) {
            Class<?> line;
            Class<?> point;
            ClassLoader loader = ClassLoader.getSystemClassLoader();
            try {
                line = loader.loadClass(wholeNameLine);
                point = loader.loadClass(wholeNamePoint);
                System.out.println("line " + line.getName());
                System.out.println("point " + point.getName());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Class.forName
         * @param wholeNameLine
         * @param wholeNamePoint
         */
        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 (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
        }
    }
    

    输出结果:

    下面是测试Classloader的效果
    line com.reflect.Line
    point com.reflect.Point
    ----------------------------------
    下面是测试Class.forName的效果
    静态代码块执行: loading line
    静态代码块执行: loading point
    line   com.reflect.Line
    point   com.reflect.Point
    

    备注:

    根据运行结果,可以看到,classloader并没有执行静态代码块,如开头的理论所说。

    而下面的Class.forName则是夹在完之后,就里面执行了静态代码块,可以看到,2个类,line和point的静态代码块执行结果是一起的,然后才是各自的打印结果。

    也说明上面理论是OK的。

    ==========================================================

    接下来修改下Line的代码,添加了几个静态的方法和变量。

    package com.reflect;
    
    public class Line {
        static {
            System.out.println("静态代码块执行: loading line");
        }
    
        public static String s = getString();
    
        private static String getString() {
            System.out.println("给静态变量赋值的静态方法执行:loading line");
            return "mask";
        }
    
        public static void test() {
            System.out.println("普通静态方法执行:loading line");
        }
    
        {
            System.out.println("普通代码块");
        }
    
        public Line() {
            System.out.println("构造方法执行");
        }
    
    }
    

    可以看到,除了原来的简单的一个静态代码块以外,我又添加了构造方法,静态方法,以及静态变量,且,静态变量被一个静态方法赋值。

    然后,看执行结果。

    下面是测试Classloader的效果
    line com.reflect.Line
    point com.reflect.Point
    ----------------------------------
    下面是测试Class.forName的效果
    静态代码块执行: loading line
    给静态变量赋值的静态方法执行:loading line
    静态代码块执行: loading point
    line   com.reflect.Line
    point   com.reflect.Point
    

    除了,静态代码块的执行外,竟然还有一个静态方法被执行,就是给静态变量赋值的静态方法被执行了。

    三、应用场景

    在我们熟悉的Spring框架中的IOC的实现就是使用的ClassLoader。

    而在我们使用JDBC时通常是使用Class.forName()方法来加载数据库连接驱动。这是因为在JDBC规范中明确要求Driver(数据库驱动)类必须向DriverManager注册自己

    以MySQL的驱动为例解释:

    public class Driver extends NonRegisteringDriver implements java.sql.Driver {  
        // ~ Static fields/initializers  
        // ---------------------------------------------  
      
        //  
        // Register ourselves with the DriverManager  
        //  
        static {  
            try {  
                java.sql.DriverManager.registerDriver(new Driver());  
            } catch (SQLException E) {  
                throw new RuntimeException("Can't register driver!");  
            }  
        }  
      
        // ~ Constructors  
        // -----------------------------------------------------------  
      
        /** 
         * 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()  
        }  
    }
    

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

    展开全文
  • class.forName()详解

    千次阅读 2020-02-27 16:59:26
    class.forName()方法的作用: 它的作用就是按参数中指定的字符串形式的类名去搜索并加载相应的类,如果该类字节码已经被加载过,则返回代表该字节码的Class实例对象,否则,按类加载器的委托机制去搜索和加载该类,...

    class.forName()方法的作用:

    它的作用就是按参数中指定的字符串形式的类名去搜索并加载相应的类,如果该类字节码已经被加载过,则返回代表该字节码的Class实例对象,否则,按类加载器的委托机制去搜索和加载该类,如果所有的类加载器都无法加载到该类,则抛出ClassNotFoundException。加载完这个Class字节码后,接着就可以使用Class字节码的newInstance方法去创建该类的实例对象了。

    class.forName(xxx.xx.x)返回的是一个类
    任何class都要装载在虚拟机上才能运行,class.forName(xxx
    的作用就是将类装载到虚拟机上。
    A a = (A)Class.forName("pacage.A").newInstance();
    和
    A a = new A();
    都是在实例化类A,但是他们创建对象的方式不一样,前者使用类加载的机制,
    后者是创建一个类,前者创建类时,类已经被加载了,后者没有加载。
    

    newInstance()方法调用默认构造器(无参数构造器)初始化新建对象。

    为什么要使用class.forname()

    有时候,我们程序中所有使用的具体类名在设计时(即开发时)无法确定,只有程序运行时才能确定,这时候就需要使用Class.forName去动态加载该类,这个类名通常是在配置文件中配置的。Java中工厂模式经常使用newInstance()方法来创建对象, 例如:
    class c = Class.forName(“Example”);
    factory = (ExampleInterface)c.newInstance();

    其中ExampleInterface是Example的接口,可以写成如下形式: 
    String className = "Example"; 
    class c = Class.forName(className); 
    factory = (ExampleInterface)c.newInstance();
    
    进一步可以写成如下形式: 
    String className = readfromXMlConfig;//从xml 配置文件中获得字符串 
    class c = Class.forName(className); 
    factory = (ExampleInterface)c.newInstance();
    
    上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,
    只要他们继承ExampleInterface就可以。
    

    new 关键字和newInstance的区别:

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

    摘要:

    1.  jvm在装载类时会执行类的静态代码段,要记住静态代码是和class绑定的,class装载成功就表示执行了你的静态代码了,而且以后不会再执行这段静态代码了。
      
    2.  Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。
      
    3.  动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象
      
      String str = 用户输入的字符串  
      
      Class t = Class.forName(str);  
      
      t.newInstance(); 
      


    Class.forName的一个很常见的用法是在加载数据库驱动的时候。

    如:

    Class.forName(“com.microsoft.sqlserver.jdbc.SQLServerDriver”);
    Connection con=DriverManager.getConnection(“jdbc:sqlserver://localhost:1433;DatabaseName==JSP”,“jph”,“jph”);

    为什么在我们加载数据库驱动包的时候有的却没有调用newInstance( )方法呢?
    即有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢?

    刚才提到,Class.forName("");的作用是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码段。

    而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBCDriver的Driver类的代码都必须类似如下:
    public classMyJDBCDriver implements Driver {

    static{
    
       DriverManager.registerDriver(new MyJDBCDriver());
    

    }

    }

    既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。
    参考文献:https://blog.csdn.net/liletian2104/article/details/34415143
    https://blog.csdn.net/fengyuzhengfan/article/details/38086743

    展开全文
  • 问:简单谈谈你对 Java 中 Class.forName()、Class.class、getClass() 三者的理解? Class.class 的形式会使 JVM 将使用类装载器将类装入内存(前提是类还没有装入内存),不做类的初始化工作,返回 Class 对象。 ...
  • Class对象一般使用于反射情况下,通过反射可以在运行期获取对应类的Class类型信息,Class中存储了类的几乎所有信息,当然这些信息是未初始化...2.Class.forName("包名.类名") ,装入类,默认同时进行静态...
  • Class.forName()无论引入哪个类都会报错。。。 ![图片说明](https://img-ask.csdn.net/upload/201912/30/1577707093_329553.png) 多谢各位大佬。。
  • 1、Class.forName()和ClassLoader.loadClass()和new XX的区别 Class.forName():将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static代码块。 ClassLoader.loadClass():只会将.class文件加载到...
  • 反射中,Class.forName和ClassLoader区别

    千次阅读 多人点赞 2019-02-20 17:53:01
    今天浏览其他博客的时候,看到一个问题问“反射中,Class.forName和ClassLoader区别”,思考后,发现自己知道这两个都可以用来进行类的加载,但是其区别确实还不了解,经查阅相关资料学习后总结如下: 一、类加载...
  • ClassLoader和Class.forname的区别

    千次阅读 2020-06-24 21:37:41
    类加载 类加载大致分为5个阶段: 加载:java类运行时候会生成一个class字节码...对于class.forName和classloader来说针对的就是第一个过程,也就是加载过程。不过这俩虽然有一定的相似性,但是区别还是挺大的。 在ja
  • class.forName( )报错

    千次阅读 2020-07-16 21:45:19
    从属性配置文件.properties中读取类名,调用class.forName( )方法获取该类字节码时,发生ClassNotFound错误: properties文件: name="Thread.TheThirdThread" 获取字节码并new对象: FileReader reader = new ...
  • 使用软件IntelliJ IDEA在学习spring框架时,通过读取配置文件Properties并使用Class.forName()进行反射时报错:java.lang.ClassNotFoundException 解决方法: 1. class.forName(string); 参数string应该是 包名....
  • Java中Class.forName()用法详解

    万次阅读 多人点赞 2018-11-22 20:10:59
    Class.forName()主要功能 Class.forName(xxx.xx.xx)返回的是一个类, Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。 下面,通过解答以下三个问题的来详细...
  • Class.forName(xxx.xx.xx) 返回的是一个类 首先你要明白在java里面任何class都要装载在虚拟机上才能运行。这句话就是装载类用的(和new 不一样,要分清楚)。 至于什么时候用,你可以考虑一下这个问题,给你一个字符...
  • ,分步的好处是我们在调用class的静态加载方法class.forname ()获得更加的灵活性,提供了一种 解耦 的方法 工厂设计模式简介 1.需要 配置文件 以键值对存储 如accountDao:cn.baidu.dao.imp.AccountDaoImpl 2....
  • Class.forName("com.mysql.jdbc.Driver")理解

    千次阅读 2019-01-15 22:23:18
     为了理解操作jdbc时需要先使用Class.forName("com.mysql.jdbc.Driver")这行代码的作用。解析:  1.使用Class.forName("com.mysql.jdbc.Driver")后,jvm会加载这个类  2.加载这个类后,进入...
  • 调用 Class.forName 其实相当于调用了 Class.forName(className, true, currentLoader), 这个方法的第二个参数表示是否需要初始化类。源码中设置为 true, 因此 Class.forName 获取到 Class 对象时, 会自动对类进行...
  • 理解Class.forName(Com.mysql.cj.jdbc.Driver) Class.forName("com.mysql.cj.jdbc.Driver"); 在使用jdbc的时候这行代码必不可少,我们来仔细理解一下这行代码的意义...Class.forName()是一个反射,但是他没有返回一个
  • Class.forName()用法及与new的区别

    千次阅读 2017-08-11 15:46:09
    Class类概念Class类用来描述一个类的结构,比如描述一个类有哪些成员,有哪些方法等。有多种方法可以获取一个类对应的Class类实例,比如:[java] view plain copy//第一种方式获取描述Dog类结构的Class类实例 ...
  • 但是又不只如何解决,怎么会SpringBoot项目中Class.forName("a.b.c.Demo")与组件中Class.forName("a.b.c.Demo")得出来的Class不一致!这个问题暂时不深入了解,先把这个问题解决 解决方案: 组件中创建一个接口类 ...
  • java Class.forName 内部类

    千次阅读 2019-10-29 16:59:06
    对于正常类的 Class.forName(package.ClassName) 对于内部类 Class.forName(package.外部类名$内部类名)
  • 最近在面试过程中有被问到,在Java反射中Class.forName()加载类和使用ClassLoader加载类的区别。当时没有想出来后来自己研究了一下就写下来记录一下。 解释 在java中Class.forName()和ClassLoader都可以对类进行...
  • 加载Class.forName(“com.mysql.jdbc.Driver”)报错 代码 package jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql...
  • class.forName

    千次阅读 2017-07-23 09:02:23
    对于大部分人来说,第一次见到class.forName(String className)这句代码应该是在使用jdbc方式连接数据库的时候。但这句代码本质上是什么含义,做了什么工作呢?本文将回答此问题。 理解Class.forName方法需要一些...
  • 利用反射机制加载类时,提示错误: java.lang.ClassNotFoundException,原因是未加类包名所致,解决如下...Class c = Class.forName("所动态加载自定义的类所在的包报名." + cName); 则错误解决!!! ...
  • Class.forName()的作用

    万次阅读 多人点赞 2019-05-30 21:25:19
    装载一个类并且对其进行实例化的操作。 装载过程中使用到的类加载器是当前类... Class.forName(String className)使用装载当前类的类装载器来装载制定的类,因为class.forName(String name)方法内部调用了Class.fo...
  • 对于大部分人来说,第一次见到class.forName(String className)这句代码应该是在使用jdbc方式连接数据库的时候。但这句代码本质上是什么含义,做了什么工作呢?本文将回答此问题。 理解Class.forName方法需要一些...
  • class.forName()方法有什么作用

    千次阅读 2018-06-20 09:22:49
    JVM规定了几种必须对类执行初始化的场景,class.forName就是其中一种,它会让jvm对指定的类执行加载、连接、初始化操作,其结果是: 1.jvm会查找指定路径类的class文件,然后将class文件读入内存,为该类生成一个...
  • Class.forName的作用

    千次阅读 2018-07-13 16:24:12
    这个Class.forName究竟什么的英文鬼。连接数据库几大步。看以下代码?1234五67891011121314151617181920212223242526import com.mysql.jdbc.Driver; import java.sql.*; /** * @author ho...
  • class.forname和classloader区别

    千次阅读 2018-10-06 14:17:51
    Java中class是如何加载到JVM中的: 1.class加载到JVM中有三个步骤 &nbsp;&nbsp;&nbsp; 装载:(loading)找到class对应的字节码文件。 &nbsp;&nbsp;&nbsp; 连接:(linking)将对应的字节码...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,536,411
精华内容 1,014,564
关键字:

class.forname