您的位置:首页 > 编程语言 > Java开发

Java高级之类结构的认识

2016-05-20 19:36 295 查看
        本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!

Java体系包括,各种版本的虚拟机,可执行文件,各种第三方类库,Java API类库,Java语言
发展史:91年James Gosling博士带领开发出Oak,95年互联网兴起来变成Java,并正式改名,并提出“一次编译到处执行”的口号。96年1.0正式发布,代表技术有Java虚拟机,AWT和Applet-以前很喜欢的Swing开发套件;
97年1.1,代表技术有Jar文件格式、JDBC、JavaBeans、RMI、内部类、反射等
98年1.2,拆分三个方向,就是J2ME,J2EE,J2SE 99年正式使用HotSpot,代表技术JIT、Collections集合类等
2000年1.3,代表技术有数学运算、TimeApi、JNDI(正式应用)等,此后2年发布一次
2002年1.4,走向成熟,正则表达式、XML解析器等出现
2004年1.5,自动装箱、泛型、注解、枚举、可变长参数、循环等语法
2006年1.6,提供动态语言支持、编译API和HTTP服务器API,对锁、同步、垃圾回收、类加载做了大量优化
2009年1.7,由于涉及sun收购,之后的发布节奏也被打乱,提供新的G1收集器、加强对非JAVA语言的调用、升级类加载架构
2012年1.8,支持接口有默认实现方法、支持Lamda表达式(android studio已支持)、TimerAPI的全新优化。

Java的类结构是对变量,各种访问标记,接口和继承,同步、枚举,注解,内部类,异常、方法等的组合

类文件是以8个字节为基础单位的二进制流

类文件和图片都有魔数,用来标识它可以被虚拟机接受,即0xCAFEBABE-全大写,只是为了方便大家记忆;在很多地方都有应用,因为文件后缀名可以改变,而它不能改变。

Java类文件的前4位代表它是否能被虚拟机接受,之后是版本号,5和6代表次版本号,7和8代表主版本号
紧接下来的是常量,大概有11种表结构,除了常见的String,Integer,Float,Double,Long以外,还有Class,Utf-8,Field,Method,InterfaceMethod,NameAndType类型,数量不确定

接着是访问标志有8种,public,final,abstract,interface,super,enum,annotation,synthetic(非用户代码产生的类)

接着是“继承”索引,this索引和super索引,除Object以外,其他索引值均不为0,代表有父类;索引集合描述这个类实现了哪些接口,从左到右按顺序排列,有几个计数器值为几

再接下来是字段表集合,描述所有的变量(如作用范围-public,并变性-final,并发可见-volatile等)和返回值(基本数据类型和类),基本数据类型的全限定名,开头都是其英文大写,如'[()V; '和'[[Ljava/lang/String';前者代表一个空返回值,后者代表一个String二维数组,类都以L开头作表示;全限定名可以理解为对象的地址。

接下来到方法表集合了,跟字段表一样,但某些访问控制答不能修饰方法,如volatile和transient关键字,方法名加尖括号表示,如<init>-指实例构造器,<cinit>-指类构造器,编译后的代码存在一个"Code"的属性里
属性表,类、方法体、常量表中都有属性表
1、Code属性指编译后的字节码,还有它的长度,栈的最大深度,最大存储空间,一个方法编译后不允许超过65535个字节码指令,一个指令=1Slot=32位,这是最小的存储单位,而float和int都是32位;一般还可以分为源码和元数据(即对源码的描述,如类,字段,方法等)
public static int getFinally() {
int a = 1;
try {
a = 2;
return a;
} catch (Exception e) {
// TODO: handle exception
a = 3;
return a;
} finally {
a = 4;
}
}上面是用一段源码,来对字节码指令进行分析,很多人看见后,都很想对照自己的结果,准确答案是2
跟你的结果是否一致,为什么是2而不是4呢?
这段代码可以分为三层来分析:
第一层如果try没有任何问题,则执行a=2 return a
第二层,如果try出错,则执行finally,再执行catch语句,a=3 return a
第三层,如果try无错,catch无错,而出现了其他error,则直接执行finally语句的a=4
这个地方可以这样理想,按照正常的Java指令没有打乱的情况下,先执行try return时已经执行a的write方法,则finally中仅执行了a的assign方法,此时a已经为2。不懂变量加载过程的,可以查看:Java高级之内存模型分析
2、Exceptions属性 列举出可检查出的异常如catch语句后和throws的异常
3、LineNumberTable属性 描写源码行号与字节码行号的关系,即这段代码位于哪一行,用于异常抛出时定位
4、LocalVariableTable属性 定义后别人引用,不会产生参数是arg0,arg1的情况
5、SourceFile属性,用于记录Class源码文件名称,主要异常抛出时可以定位是哪个文件
6、ConstantValue属性,通知虚拟机自动定义为静态变量,只能为基本数据类型和String类型
7、InnerClasses属性 显然定义内部类的,数量位置等
8、Deprecated及Synthetic 前者是定义废弃类,方法,变量等,后者指非源码产生由编译器自动加的东西。

Class文件是虚拟机解释的入口,了解其内部结构,有助于对代码进行分析定位错误,以及热加载等其他功能的理解。

以下是拓展知识

1位=1bit 最小的计算机单位,指0和1
byte=8bit 字节 取值范围 -128到127 记忆技巧 2^字节次方
char =2byte Unicode
short=2byte 取值-2^15到2^15-1
int =4byte 取值-2^31到2^31-1
float=4byte
long=8byte 取值-2^63到2^63-1 意义2个int或float
double=8byte  
boolean 无意义
一个汉字是2byte,一个英文字母1byte(GBK和GB2312编码的环境中)
以上有个规律,就是次方数都是奇数,偶数达不到,同时咱们来测一下int的大小是不是2的31次方-1
public class TestInteger {
public static void main(String[] args) {
int size = 0x7fffffff;// Integer.MAX_VALUE
Integer oral = 2;
for (int i = 0; i < 4; i++) {
oral *= oral;
}
for (int i = 0; i < 15; i++) {
oral *= 2;
}
System.out.println(size == oral - 1);
System.out.println(size);
System.out.println(oral * -1);
}
}
输出结果:
true
2147483647
-2147483648

得出证明:在电脑上,测算出int的结果跟虚拟机的设置一致(注意,不能把4写成5,要考虑到int存值大小)。
至于实验过程中,有人讲跟操作系统的位数有关。结果研究64位和32位的区别,发现:只是前者执行8个字节指令,后者执行4个;其次前者最大支持内存128,后者支持到[b]4G(可使用3.25G)。但是java是运行在虚拟机,即其中的编译器上,一般现在都是4个字节,除非有特殊的处理器除外,可能是2个字节(必须大于等于short的长度)。因此,使用不同大小的处理器,可以设计出适应不同软件的更优硬件出来。[/b]
虚拟机的存储区域,一般常说的有栈和堆,栈放指针和基本数据类型,而堆放对象,还有一种需要熟悉的是常量存储,就是存代码内部(方法里的);还有两种拓展了解:寄存器位于处理器内部,极少,处理极快;非RAM存储,如持久化对象和流对象,特指数据流传输和硬盘对象。除了常量存储存在只读存储器(ROM-Only)和寄存器,其他都存在随机访问存储器(RAM-Acess)里。
位操作介绍四种,位与(&),位或(|),位否(~)和异或(^)
位与,同为1则为1,否则为0
位或,有一个1则为1,否同为0
位否,1变0,0变1 计算方式~x=-(x+1)
异或,不同则为1,相同则为0
int a = 0x010101;
int b = 0x110100;
System.out.println(a & b);
System.out.println("位与操作:"+0x010100);
System.out.println(a | b);
System.out.println("位或操作:"+0x110101);
System.out.println(a ^ b);
System.out.println("异或操作:"+0x100001);结果
65792
位于操作:65792

1114369
位或操作:1114369

1048577
异或操作:1048577

Tips:负数操作 要先获得补码再操作,然后变源码+1操作
另外一个例子:
System.out.println((1 & 0) + "," + (1 & 1) + "," + (0 & 0));//两个为1才为1,否则为0
System.out.println((1 | 0) + "," + (1 | 1) + "," + (0 | 0));//有一个为1则为1,否则为0
System.out.println((1 ^ 0) + "," + (1 ^ 1) + "," + (0 ^ 0));//只有一个为1才为1,否则为0

结果:
0,1,0
1,1,0
1,0,0

图片的大小=图片width*height*颜色深度
格式有四种(A-Alpha不透明度 R-Red G-Green B-Blue)
ALPHA_8格式  8位=1byte
ARGB_4444格式 16位=4+4+4+4=2byte
RGB_565格式 16位=5+6+5=2byte
ARGB_8888格式 32位=8+8+8+8=4byte
借用格式来压缩图片是一种不错的办法。
以下是图片魔数
图像文件头
  1)1-2:(这里的数字代表的是"字",即两个字节,下同)图像文件头。0x4d42='BM',表示是Windows支持的BMP格式。(注意:查ascii表B 0x42,M0x4d,bfType 为两个字节,B为low字节,M为high字节所以bfType=0x4D42,而不是0x424D,但注意)
  2)3-6:整个文件大小。4690 0000,为00009046h=36934。
  3)7-8:保留,必须设置为0。
  4)9-10:保留,必须设置为0。
  5)11-14:从文件开始到位图数据之间的偏移量(14+40+4*(2^biBitCount))。4600 0000,为00000046h=70,上面的文件头就是35字=70字节。位图信息头  6)15-18:位图图信息头长度。
  7) 19-22:位图宽度,以像素为单位。8000 0000,为00000080h=128。
  8)23-26:位图高度,以像素为单位。9000 0000,为00000090h=144。
  9)27-28:位图的位面数,该值总是1。0100,为0001h=1。
  10)29-30:每个像素的位数。有1(单色),4(16色),8(256色),16(64K色,高彩色),24(16M色,真彩色),32(4096M色,增强型真彩色)。1000为0010h=16。
  11)31-34:压缩说明:有0(不压缩),1(RLE 8,8位RLE压缩),2(RLE 4,4位RLE压缩,3(Bitfields,位域存放)。RLE简单地说是采用像素数+像素值的方式进行压缩。T408采用的是位域存放方式,用两个字节表示一个像素,位域分配为r5b6g5。图中0300 0000为00000003h=3。
  12)35-38:用字节数表示的位图数据的大小,该数必须是4的倍数,数值上等于(≥位图宽度的最小的4的倍数)×位图高度×每个像素位数。0090 0000为00009000h=80×90×2h=36864。
  13)39-42:用象素/米表示的水平分辨率。A00F 0000为0000 0FA0h=4000。
  14)43-46:用象素/米表示的垂直分辨率。A00F 0000为0000 0FA0h=4000。
  15)47-50:位图使用的颜色索引数。设为0的话,则说明使用所有调色板项。
  16)51-54:对图象显示有重要影响的颜色索引的数目。如果是0,表示都重要。 Java中的switch语句支持整型和枚举,整型包括byte,short,int,char对象的hashcode存在的价值在于第一可以判断两个对象是否相等,第二用于容器类快速查找闭包:在一定的逻辑或者方法内存在的变量,安全性极高,应用在局部范围。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: