一、ClassLoader
当运行一个Java 程序时,JVM启动,运行bootstrap classLoader(启动类加载器),将Java核心的API加载进来;接着调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class;这就是一个程序最基本的加载过程。
最常用的两个方法应该是ClassLoader.loadClass(String name , boolean resolve)和Class.forName(String name) ,这两个方法都是用来加载Class的,但在作用上却有一些区别。
loadClass的方法是被保护的,用户能够直接调用的是loadClass(String name) , resolve默认为false,即不解析类,则说明loadClass在加载类的时候不对该类进行解析,因此不会初始化该类。forName(String name ) 等同于Class.forName("className",true,CALLCLASS.class.getClassLoader),即在加载的时候就会将该类进行解释和初始化。
在JVM加载类时需要经过三个步骤:装载、连接、初始化。
装载:
1.通过类的全名产生对应类的二进制数据流。(注意,如果没找到对应类文件,只有在类实际使用时才抛出错误。)
2.分析并将这些二进制数据流转换为方法区(JVM 的架构:方法区、堆,栈,本地方法栈,pc 寄存器)特定的数据结构(这些数据结构是实现有关的,不同 JVM 有不同实现)。这里处理了部分检验,比如类文件的魔数的验证,检查文件是否过长或者过短,确定是否有父类(除了 Obecjt 类)。
3.创建对应类的 java.lang.Class 实例(注意,有了对应的 Class 实例,并不意味着这个类已经完成了加载链链接!)。
连接:
1.验证,即验证class是否符合规则,如检查 final class 又没有被继承,检查静态变量的正确性等等;
2.准备,对类的成员变量分配空间。虽然有初始值,但这个时候不会对他们进行初始化(因为这里不会执行任何 Java 代码)。具体如下:所有原始类型的值都为 0。如 float: 0f, int: 0, boolean: 0(注意 boolean 底层实现大多使用 int),引用类型则为 null。
3.解释,为类、接口、方法、成员变量的符号引用定位直接引用。这一步是可选的,可以在符号引用第一次被使用时完成,即所谓的延迟解析(late resolution)。但对用户而言,这一步永远是延迟解析的,即使运行时会执行 early resolution,但程序不会显示的在第一次判断出错误时抛出错误,而会在对应的类第一次主动使用的时候抛出错误!
初始化:
1.如果基类没有被初始化,初始化基类。
2.有类构造函数,则执行类构造函数。
说明:Java中字符只以一种形式存在,那就是Unicode。
二、类型转换
简单数据类型由低级到高级的顺序为(byte,short,char)- int - long - float - double ;
低级到高级可自动转换,高级到低级、同级之间都需要强制转换。
1. 默认1.0表示的是double型,如果需要表示float,需写为1.0f。
2. 当char x= ‘x‘ ; int i = 10; 公式false? i : x 输出的值为120,因为两者都是变量,会将低级升级到高级的表示形式;false?10:x ,x的输出仍为x,是因为Java编程规范中提到当两个表达式有一个是常量表达式(10),另外一个是T类型,且常量表达式可以被T表示时,输出结果是T类型。
3.三目运算是右结合性。
三、异常
Error和exception都是继承自Throwable类。
Error是不可控制的,经常用来表示系统错误或者底层资源的错误。
Exception可以是可被控制(checked) 或不可控制的(unchecked),应该在应用层进行处理,throw表示抛出一个异常,throws是在方法体外部声明可能会抛出某些异常。
程序必须捕获或声明所有的非运行时异常。
原文:http://www.cnblogs.com/xuexue-bit/p/5125933.html