首页 > 代码库 > Java编程思想(十六) —— 联系JVM再谈Class
Java编程思想(十六) —— 联系JVM再谈Class
编程思想这个专栏停了好久了,主要是把精力放在了其他知识上,现在继续补上。
前面两篇写到RTTI和简单的反射介绍,先回顾一下:
RTTI,运行时类型信息,多态的应用,类型转换其实是发生在运行期间。
Class对象:
编程思想讲到的定义,Java使用Class对象来执行其RTTI,类是程序的一部分,每个类都有一个Class对象,其实每编写和编译一个新类,就会产生一个Class对象,其实这个对象时被保存在同名的.class文件中的。生成这个类对象,其实是JVM(Java虚拟机)使用了“类加载器”的子系统。
补充一下百度的定义:
在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。最后一句是重点。而class是一个类名的标志,class A,A是一个类,而Class是一个对象。
是不是很模糊,这些概念,Class哪里冒出来,事实上还有一个ClassLoader。为了搞清楚关系,这种肯定是虚拟机方面的除了《深入理解JVM》,特定去问了RednaxelaFX大哥还有什么书籍比较好。他推荐了《Inside the Java Virtual Machine》。看了五章之后,大体有个方向,这本书也推荐其他人,不是太难懂,在我大二的时候看一本红色封面的JVM的书看得真心蛋疼,一来就是代码直接转汇编,所以说,合适的时候看合适的书是很重要的。
《Inside the Java Virtual Machine》一书笔记:
先把握整个体系结构的4个技术:
语言
class文件
api
jvm
书中有点分析得很有道理,所谓的跨平台,是因为class文件 ,二进制文件 ,但是像c++ c这些, 编译和链接之后的二进制文件是在系统直接运行,为目标处理器的机器语言
不具有跨平台性,而class文件是虚拟机的“机器语言”。
而为了处处能运行的原因,使得java图形界面的api比较复杂,为什么awt和swing没有广泛的使用开来,个人认为一个是需要对应的java环境,一个是开发效率问题。
还有很有趣的一点:在dos窗口运行的java文件时,java HelloWorld的时候,是不是从来没有想过java是什么含义,其实java就是叫系统运行JVM,加载HelloWorld后运行其main方法。
现在看一下JVM的体系结构图:
这个图中的东西又可以和Java编程思想(一) —— 一切都是对象及内存分配联系起来。
每个虚拟机实例的方法区和堆由该实例里面的所有线程共享,堆存放对象。
新线程的创建 会有自己的pc寄存器(程序计数器)以及一个java栈(保存线程的局部变量 参数 返回值 运算中间结果)。
java栈由栈帧stack frame或者说是帧frame组成 ,线程调用一个方法,压入一个新的栈帧,返回时弹出。
到了学习的重点所在,对于每个被装载的类型,虚拟机都会相应的为其创建Class类的实例,
Class.forName(java.lang.Object) 的到代表Object的Class对象的引用 。
如果无法将请求的类型转载进当今命名空间,forName会抛出classnotfoundexception。
另外一个方法,getClass 也可以拿到类的Class对象。Class对象中有getName和getClassLoader方法。
直接上例子:
两个方法返回的是已装载类型的信息,getName拿到的是全限定名 ,类所属包+类名,如果是Object类,其实就是java.lang.object。
getClassLoader 返回classLoader引用 ,如果为启动类装载器 ,则为null。
new与Class.newInstace的区别。
都是创建实例,具体的不同是什么?
参考了:http://www.coderanch.com/t/516460/java/java/newInstance-difference-bet
T. Huy Nguyen说的
An obvious difference is that the class‘s fully qualified name can be dynamically constructed/read from file/changed when you use "newInstance".
"newInstance" also requires the Java class to have an no-arg constructor, else you will get error at runtime. If you do the same with "new", you will immediately get error at compile time.
明显的区别就是你用newInstance的时候,class的名字可以动态的从文件/变化中动态地构造/读取。
newInstance要求Java类需要有一个无参构造器,不然会出现运行期错误。同样的情况在new中,编译期间就出现错误了。
总结:
对于每个被装载的类型,虚拟机都会相应的为其创建Class类的实例。
虚拟机在方法区会存储类型信息:
类型的全限定名。
直接超类的全限定名。
类型为接口类型还是类类型。
访问修饰符。
而这些东西,在编程的时候怎么拿到,就靠Class类了,接下来你会问,拿到又怎样呢?
用处就是反射,光靠一个类名,我可以拿到很多信息,也可以对其进行操控,这就是作用所在了。
书中有点分析得很有道理,所谓的跨平台,是因为class文件 ,二进制文件 ,但是像c++ c这些, 编译和链接之后的二进制文件是在系统直接运行,为目标处理器的机器语言
不具有跨平台性,而class文件是虚拟机的“机器语言”。
而为了处处能运行的原因,使得java图形界面的api比较复杂,为什么awt和swing没有广泛的使用开来,个人认为一个是需要对应的java环境,一个是开发效率问题。
还有很有趣的一点:在dos窗口运行的java文件时,java HelloWorld的时候,是不是从来没有想过java是什么含义,其实java就是叫系统运行JVM,加载HelloWorld后运行其main方法。
现在看一下JVM的体系结构图:
这个图中的东西又可以和Java编程思想(一) —— 一切都是对象及内存分配联系起来。
每个虚拟机实例的方法区和堆由该实例里面的所有线程共享,堆存放对象。
新线程的创建 会有自己的pc寄存器(程序计数器)以及一个java栈(保存线程的局部变量 参数 返回值 运算中间结果)。
java栈由栈帧stack frame或者说是帧frame组成 ,线程调用一个方法,压入一个新的栈帧,返回时弹出。
到了学习的重点所在,对于每个被装载的类型,虚拟机都会相应的为其创建Class类的实例,
Class.forName(java.lang.Object) 的到代表Object的Class对象的引用 。
如果无法将请求的类型转载进当今命名空间,forName会抛出classnotfoundexception。
另外一个方法,getClass 也可以拿到类的Class对象。Class对象中有getName和getClassLoader方法。
直接上例子:
public class TestClass { public static void main(String[] args) { Class c = Object.class.getClass(); Class c1 = Object.class; Object o = new Object(); Class oc = o.getClass(); Class ct = null; try { ct = Class.forName("java.lang.Object"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } TestClass t = new TestClass(); Class tclass = t.getClass(); System.out.println(tclass.getClassLoader()); System.out.println(c.getClassLoader()); System.out.println(oc.getClassLoader()); System.out.println(ct.getClassLoader()); System.out.println(c1.getClassLoader()); System.out.println(tclass.getName()); System.out.println(c.getName()); System.out.println(oc.getName()); System.out.println(ct.getName()); System.out.println(c1.getName()); } } output: sun.misc.Launcher$AppClassLoader@da4a1c9 null null null null TestClass java.lang.Class java.lang.Object java.lang.Object java.lang.Object
两个方法返回的是已装载类型的信息,getName拿到的是全限定名 ,类所属包+类名,如果是Object类,其实就是java.lang.object。
object.class指的是Class对象引用了,装载的为object,再getClass的时候,装载的就变成了Class引用,所以getName拿到的就是Class了,而Object.class.getName()装载的是Object,所以getName拿到的全限定名为Object。
类装载器有两种:启动类 和 自定义类 ,前者是jvm定义好的 ,后面是自己写的。getClassLoader 返回classLoader引用 ,如果为启动类装载器 ,则为null。
new与Class.newInstace的区别。
都是创建实例,具体的不同是什么?
参考了:http://www.coderanch.com/t/516460/java/java/newInstance-difference-bet
T. Huy Nguyen说的
An obvious difference is that the class‘s fully qualified name can be dynamically constructed/read from file/changed when you use "newInstance".
"newInstance" also requires the Java class to have an no-arg constructor, else you will get error at runtime. If you do the same with "new", you will immediately get error at compile time.
明显的区别就是你用newInstance的时候,class的名字可以动态的从文件/变化中动态地构造/读取。
newInstance要求Java类需要有一个无参构造器,不然会出现运行期错误。同样的情况在new中,编译期间就出现错误了。
总结:
对于每个被装载的类型,虚拟机都会相应的为其创建Class类的实例。
虚拟机在方法区会存储类型信息:
类型的全限定名。
直接超类的全限定名。
类型为接口类型还是类类型。
访问修饰符。
而这些东西,在编程的时候怎么拿到,就靠Class类了,接下来你会问,拿到又怎样呢?
用处就是反射,光靠一个类名,我可以拿到很多信息,也可以对其进行操控,这就是作用所在了。
Java编程思想(十六) —— 联系JVM再谈Class
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。