`
uule
  • 浏览: 6305928 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

JVM如何判断类相同

 
阅读更多

 JVM根据两个方面判断:一是类的全称;另一个是类加载器.

类的全称是相同的,那类加载器是否相同呢?

即使类的全称相同,而使用的加载器不同,那Class对象也是不同的.

 

package com.test;

public class TestClass {
	
	public static void main(String[] args){

		try {
			// 动态加载类、测试Class.forName()
			Class testTypeForName = Class.forName("com.test.TestClassType");
			System.out.println("testForName---" + testTypeForName);
			// 测试类加载器
			System.out.println("forName形式的加载器--"
					+ testTypeForName.getClassLoader());

			System.out.println();
			
			try {
				TestClassType tp = (TestClassType) testTypeForName.newInstance();
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("forName形式的加载器--"
					+ testTypeForName.getClassLoader());
			System.out.println();
			
			// 测试类名.class
			Class testTypeClass = TestClassType.class;
			System.out.println("testTypeClass---" + testTypeClass);
			System.out.println("class形式的加载器---"
					+ testTypeClass.getClassLoader());

			System.out.println();
			
			// 测试Object.getClass()
			TestClassType testGetClass = new TestClassType();
			System.out.println("testGetClass---" + testGetClass.getClass());
			System.out.println("getClass形式的加载器--"
					+ testGetClass.getClass().getClassLoader());

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}



class TestClassType {

	// 构造函数
	public TestClassType() {
		System.out.println("----构造函数---");
	}

	// 静态的参数初始化
	static {
		System.out.println("---静态参数初始化---");
	}

	// 非静态的参数初始化
	{
		System.out.println("----非静态的参数初始化---");
	}
}

 

结果:

---静态参数初始化---
testForName---class com.test.TestClassType
forName形式的加载器--sun.misc.Launcher$AppClassLoader@6b97fd

----非静态的参数初始化---
----构造函数---
forName形式的加载器--sun.misc.Launcher$AppClassLoader@6b97fd

testTypeClass---class com.test.TestClassType
class形式的加载器---sun.misc.Launcher$AppClassLoader@6b97fd

----非静态的参数初始化---
----构造函数---
testGetClass---class com.test.TestClassType
getClass形式的加载器--sun.misc.Launcher$AppClassLoader@6b97fd

 

观察结果发现:三种形式的加载器是相同的.

jvm中类相同的条件:类加载器实例+包名+类名

而java中相同的类: 包名+类名

 

一.什么时候用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关键字除了一个是方法,一个是关键字外,最主要有什么区别?

 

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

那么为什么会有两种创建对象方式?这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。

 

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:

1、这个类已经加载;

2、这个类已经连接了。

而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。

 

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

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

 

二.new 和Class.forName()有什么区别?

其实上面已经说到一些了,这里来做个总结:

首先,newInstance( )是一个方法,而new是一个关键字

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

简言之:

newInstance(): 弱类型,低效率,只能调用无参构造。

new: 强类型,相对高效,能调用任何public构造。

Class.forName(“”)返回的是类。

Class.forName(“”).newInstance()返回的是object 。

 

 

三.为什么在加载数据库驱动包的时候有用的是Class.forName( ),却没有调用newInstance( )?

在Java开发特别是数据库开发中,经常会用到Class.forName( )这个方法。

 

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

   刚才提到,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);就可以了。

 

贴出Proxool 连接池的静态初始化方法:

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());
        }
    }
}

 

 

...

分享到:
评论

相关推荐

    Android代码-JVM-Sandbox

    我想开发录制回放、故障模拟、动态日志、行链路获取等等工具,就算我开发完成了,这些工具底层实现原理相同,同时使用,要怎么消除这些工具之间的影响,怎么保证这些工具动态加载,怎么保证动态加载/

    resin-jvm 调优

    当jvm加载类时,永久域中的对象急剧增加,从而使jvm不断调整永久域大小。为了避免调整,可使用-XX:PerSize标志设置初始值。 下面把永久域初始值设置成32m,最大值设置成64m。 java -Xms512m -Xmx512m -Xmn128m -XX...

    编程文档JVM、Java基础、.rar

    类加载,类加载器 对象初始化 编译 JiT:即时编译 两大无关性 平台无关性: 每一台平台解释器不同,但是虚拟机相同,跨平台的原因。 一个程序对应一个虚拟机,多个程序对应多个虚拟机, 虚拟机之间数据不共享 什么...

    Java学习笔记

    类: 创建对象的模板 具有相同特征的一类 事物的高度抽象集合概念 对象是类的实例化,类是对象的抽象 化。 引用 4.动态更新 5.简单! 没有指针和相关的内存操作 new 内存操作 gc 内存回收清理 Java 中的回收机制: ...

    深入理解JVM-java虚拟机栈.docx

    Java虚拟机栈也是线程私有的,它的生命周期与线程相同(随线程而生,随线程而灭) 2. 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常; 如果虚拟机栈可以动态扩展,如果扩展时无法申请...

    深入理解JVM实战篇-String类1

    A2:当一个String实例调 用 intern() 方法时,Java查找常量池中是否有相同Unicode 的字符串常量,如果有,则返回其的引用,如果没有,则在

    jvm-sandbox:基于JVM的实时非侵入AOP框架容器

    JVM沙箱容器,一种JVM的非侵入式运行期AOP解决方案基于JVM的实时非侵入AOP框架容器目标人群好强大,也曾技痒想做一个更便捷,更适合自己的问题定位工具,既可支持在线远程监控排查,也可支持单机版问题定位。...

    荧光粉:荧光粉:JVM的动态污染跟踪

    如果您想复制OOPSLA 2014实验,则确定获得相同版本的最简单方法是在一起使用,并按照。 跑步 Phosphor通过修改应用程序的字节码来执行数据流跟踪。 为了完整起见,Phosphor还修改了JRE提供的类的字节码。 使用...

    java8看不到源码-jvms-compare:JVM比较-使用基准

    上执行相同的基准测试,例如 GraalVM CE、GraalVM EE、OpenJDK 11、Oracle JDK 11。 目前正在测试什么? 顺序 JDK 版本 笔记 01 Oracle JDK 11 11.0.6 02 Graal VM EE 19.3.1 03 Graal VM CE 19.3.1 04 采用带热点的...

    面向对象详解和JVM底层内存分析

    通过类,你可以创建多个具有相同特征和行为的对象。例如,"汽车"是一个类,而每辆具体的汽车则是该类的实例。 封装: 封装是面向对象编程的重要特征,它将数据和操作数据的方法捆绑在一起,并对外部隐藏对象的内部...

    JVM面试专题1

    3. 该区域是被线程共享的 4. 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用 2. 虚拟机栈是线程私有的,它的生命周期与线程相同 3.

    JvmGC收集器

    java虚拟机3种不同类型GC收集器,详细分析之间的相同或不同的地方。

    Java中类与对象的生命周期

     不同的jvm对于类的装载时机并不相同,有些在遇到这个类时装载这个类(虽然并不知道这个类是否会被用到),另一些则在真正用到一个类的时候才对它进行装载。  ● 连接阶段。连接阶段一般情况下在一

    【Java基础】JDK、JRE、JVM之间的关系

    3.JDK、JRE、JVM的区别 3.1 Java为什么能跨平台,实现一次编写,多处运行? 1.编译器、调试器 JAVA编译器(javac.exe) JAVA编译器的作用是将(.java文件)编译成字节码文件,是最基本的开发工具。编译时首先读入java...

    varhandle2:JVM 原子操作的安全而有效的实现

    JVM 原子操作的安全而有效的实现。 这个 API 允许使用不安全的操作(a la sun.misc.Unsafe)是一种安全的方式,但与使用 sun.misc.Unsafe 一样有效。 主要思想是基本上让 JIT 生成完全(或大部分)相同的代码,...

    探索Java语言与JVM中的Lambda表达式

    Lambda表达式是自JavaSE5引入泛型以来最重大的Java语言新特性,本文将介绍Lamdba的设计初衷,应用场景与基本语法。...其中一些术语彼此之间会有一些细微的不同,但基本上它们都指代相同的功能。虽然一开始会觉得L

    使用HOCON文件的JVM语言的配置库-Python开发

    如果您有疑问或正在处理请求,或者只是好奇,请加入聊天室:以纯Java实现的概述,不依赖任何项,支持三种格式的文件:Java属性,JSON和人性化的JSON超集合并所有格式的多个文件,可以从文件,URL或类路径加载。...

    bcdiff:命令行 JVM 字节码差异工具

    差异bcdiff 是一个用 Scala 编写的命令行 JVM 类文件差异工具。 bcdiff 支持: 显示两个类文件(名称、标志、实现的接口...)之间元数据的差异, 在两个类文件之间以一种聪明的标签感知方式区分匹配方法(具有相同...

Global site tag (gtag.js) - Google Analytics