记得大三时在图书馆看过这本书,当时一口气就看完了,参加工作后又回过头来再看,还是收益很多,我是先看的这本书,然后再看了深入理解jvm虚拟机这本经典之作,必须反复看。现在又回过头来看 透析java本质的36个话题 这本书,全书一共5章,我谨以5篇博文纪念。
1、开门见山—测试你的java水平
当时赶脚自己连java新手都不是,大哭o(╥﹏╥)o
上面的问题都会在我的这5篇博文中找到答案
2、世外隐者—隐居深山的关键字
2.1 、 goto与const
Java中取消了goto的使用,取而代之的是使用循环标签 outer
需要注意的是continue 和break 只针对第一次循环有效 ,对于多次循环只能用循环标签
下面是使用outer的例子
public class TestOuter {
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
System.out.println("i=" + i + ", j=" + j);
}
}
}
}
这是一个双层循环
我们使用outer跳出第二层循环
public class TestOuter {
public static void main(String[] args) {
//在外层循环处添加outer标签 outer标签使用格式为 字母: break 字母
//所一冒号前面只要是合法标识符就好了
outer:for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
if (i==0&&j==1){
break outer;//如果只是break 它只跳出内层循环
}
System.out.println("i=" + i + ", j=" + j);
}
}
}
}
2.2、true、false与null
运行报错
2.3、关键字列表
3、疑团满腹—标识符更深层次的的思考
3.1、标识符定义规则
这个好多面试题的答案就是这个,嗯嗯嗯呃呃
合法的标识符的个数
public static void main(String[] args) {
int start=0;
int part=0;
for(int i=0x0000;i<0x10ffff;i++) {
if(Character.isJavaIdentifierStart(i)) {
//判断int数据对应的字符是否可以作为java标识符的首字母
start++;
}
if(Character.isJavaIdentifierPart(i)) {
//判断int数据对应的字符是否可以作为java标识符的一部分
part++;
}
}
System.out.println("Unicode字符集个数"+(0x10ffff+1));//1114112
System.out.println("可作为标识符首字母个数"+start);//101296
System.out.println("可作为标识符一部分的个数"+part);//103584
System.out.println("二者只差"+(part-start));//2288
}
3.2、“$” 惹的祸
public class Test${
public static void main(String[] args) {
System.out.println("我的类名有 $ ");
}
}
这个可以正常运行
再看一个
public class Test$User{
public static void main(String[] args) {
System.out.println("我的类名为 Test$User ");
}
}
class Test{
class User{
void print(){
System.out.println("我是Test中内部类User类中的print方法 !");
}
}
}
这下报错了
3.3、标识符的最大长度
这里class中常量字符串的存储在 深入理解jvm虚拟机 这本书里有介绍
4、鞭长莫及---我的字符串你不能用
4.1、转义字符介绍
public class Test{
public static void main(String[] args) {
char c1 ='\u0027'; //等价于 char c11 ="'"; 单引号
char c2 ='\u005c'; //等价于 char c22 ="/"; 反斜杠
String s ="\u0022"; //等价于 String ss ="""; 双引号
//上述三行Unicode转义不正确,经过转义以后,单引号和双引号都没有合理的匹配。
//而\是转义字符需要与其他字符结合使用
//\u代表Unicode转义
char c3 ='\400';
char c4 ='\28';
//这两行时八进制转义,自然只能出现0-7;
//而且他的合理范围是0-255
//\400的十进制是256.超过了这个范围
}
}
对于Unicode字符集及其编码的了解可以看看这个
http://www.cnblogs.com/wangduo/p/6225538.html
https://www.zhihu.com/question/23374078
https://www.cnblogs.com/pureEve/p/6542809.html
4.2、三种转义的联系
public class Test{
public static void main(String[] args) {
//字符A的三种表现形式
char c1 ='A';
char c2 ='\u0041';
char c3 ='\101';
//字符串双引号 “ 的三种现形式
char e1 ='\"';
char e2 ='\u0022';
char e3 ='\42';
System.out.println(c1==c2&&c2==c3);
System.out.println(e1==e2&&e2==e3);
}
}
可见,就本例而言,三种方式是等价的
4.3、三种转义的区别
先看这个例子
public class Test{
public static char c1 = '\u00a';
public static char c2 = '\u00d';
public static void main(String[] args) {
System.out.println(c1);
System.out.println(c2);
}
}
编译报错了
注释掉字段并删掉main函数
public class Test{
//public static char c1 = '\u00a';
//public static char c2 = '\u00d';
}
继续报错
书上还有个小问题题
其实第一个代码应该如下
public class Test{
// char c1 = '\u00a';
// char c2 = '\u00d';
//上面两行代码是书上的,如果换成下面两行仍不能通过编译,
//会报这个错误 Error:(8, 28) java: 无法从静态上下文中引用非静态 变量 c1
char c1 = 'a';
char c2 = 'd';
public static void main(String[] args) {
System.out.println(c1);
System.out.println(c2);
}
}
所有我给测试的类的字段加了静态公有
再回到上面编译报错的问题
4.4、增补字符串
这个就先给个定义,很繁琐我也很懵懂
5、 移星换斗—从byte b=1谈类型转换的神秘
5.1、无形的转换
public class Test{
public static void print(short value){
System.out.println(value);
}
/*public static void print(long value){
System.out.println(value);
}*/
public static void main(String[] args) {
print(60);//13行
}
}
报错
5.2、整型的转换
public class Test{
public static void main(String[] args) {
//这三行为隐式转换,编译期可以自行处理
byte b = -23;
short s = 60;
char c = '中';
//下面的需要转换运算符
b= (byte) c;
c= (char) b;
s= (short) c;
c= (char) s;
b= (byte) -b;
s= (short) (s+b);
b= (byte) (b+1);
b=+1;//正确 等价于b= (byte) (b+1);
//符合运算符在赋值时可以自动将运算结果转换为左侧的操作类型
}
}
此处 代码省略
6、扑朔迷离-浮点类型的种种悬疑
6.1、浮点类型只是近似的存储
public class Test{
public static void main(String[] args) {
double d1 = 0.1;
double d2 = 0.2;
double d3 = d1+d2;
System.out.println(d3);
}
}
运行
下面在看看浮点类型存储的值
public class Test{
public static void main(String[] args) {
System.out.println("使用BigDecimal存储的浮点类型值,它能更精确的输出浮点数的值");
for(int i=1;i<=9;i++){
double d = Double.parseDouble("0." + i);
System.out.println(d);
BigDecimal bd=new BigDecimal(d);
System.out.println(bd);
}
}
}
6.2、数量级差很大的浮点数
看程序
public class Test{
public static void main(String[] args) {
float f1 =30000;
float f2 =f1+1;
System.out.println(f1);
System.out.println(f2);
System.out.println("f2>f1为"+(f2>f1));
float f3= 30000000;
float f4 = f3+1;
System.out.println(f3);
System.out.println(f4);
System.out.println("f4>f3为"+(f4>f3));
}
}
运行
6.3、整形到浮点类型的转换
6.4、从浮点类型到整形的转换
--1 如果浮点值为NaN,结果为0L,
--2 如果浮点值为+Infinity,则为long类型的最大(小)值
--3 如果浮点值不是±Infinity,则将浮点值向0舍入为整型值
---- 如果该整型值再long类型的取值范围内,结果就是long类型的整型值。
---- 如果该整型值不在long类型的取值范围内,则为long类型的最大(小)值
--1 如果浮点值为NaN,结果为0(int类型),
--2 如果浮点值为+Infinity,则为int类型的最大(小)值
--3 如果浮点值不是±Infinity,则将浮点值向0舍入为整型值
---- 如果该整型值再int类型的取值范围内,结果就是int类型的整型值。
---- 如果该整型值不在int类型的取值范围内,则为int类型的最大(小)值
下面的程序来验证上面的规则
public class Test{
public static void main(String[] args) {
//public static final double NaN = 0.0d / 0.0
double d = Double.NaN;
System.out.println("(long)Double.NaN="+(long)d);
System.out.println("(int)Double.NaN="+(int)d);
System.out.println();
d=3e30;//很大的浮点正数值
System.out.println("(long)3e30="+(long)d);
System.out.println("(int)3e30="+(int)d);
System.out.println();
d=-8e28;//很小的浮点负数值
System.out.println("(long)-8e28="+(long)d);
System.out.println("(int)-8e28="+(int)d);
System.out.println();
d=Double.POSITIVE_INFINITY;//正无穷
System.out.println("(long)infinity="+(long)d);
System.out.println("(int)infinity="+(int)d);
System.out.println();
d=Double.NEGATIVE_INFINITY;//负无穷
System.out.println("(long)-infinity="+(long)d);
System.out.println("(int)-infinity="+(int)d);
System.out.println();
d=-12345678.6;//在int类型的取值范围内
System.out.println("(long)-12345678.6="+(long)d);
System.out.println("(int)-12345678.6="+(int)d);
System.out.println("(byte)-12475678.6="+(byte)d);
System.out.println("(int)(char)-12345678.6="+(int)(char)d);
System.out.println("(short)-12345678.6="+(short)d);
System.out.println();
}
}
运行
在第三点 浮点类型的收缩转换中
浮点类型先收缩转换为int类型再转换为目标类型(byte short char)
对应程序中的最后几句
浮点类型先收缩转换为int类型如果不是特殊值需要向0取整,那什么是向0取整呢,写个例子看看
public class Test{
public static void main(String[] args) {
double d = 12345678.6;
System.out.println("(int)-12345678.6="+(int)d);
d=-1.123456789;
System.out.println("(int)-1.123456789="+(int)d);
d=-1.923456789;
System.out.println("(int)-1.923456789="+(int)d);
d=1234567899.87654321;
System.out.println("(int)1234567899.87654321="+(int)d);
}
}
可见本文提到的收缩转换中的向0取整仅仅是把小数点后面的数字截掉了
注意,计算机中是使用补码的运算的
7、水落石出-浮点结构的最终解密
7.1、浮点类型的存储
这里先说说十进制的浮点数与二进制的转换
https://www.cnblogs.com/xkfz007/articles/2590472.html
下来再了解下 浮点类型中什么是指数
https://blog.youkuaiyun.com/hdlover/article/details/4424547
对于指数本来以为很简单,实际上概念也很混淆,就用一段代码来验证下
float f1 =8.1f; System.out.println(f1);//8.1 f1 =8.123456f; System.out.println(f1); //8.123456 f1 =8000000.123456f;//整数部分8后面有6个零 System.out.println(f1); //8000000.0 f1 =80000000.123456f;//整数部分8后面有7个零 System.out.println(f1);//8.0E7 f1 =800000000.123456f;//整数部分8后面有8个零 System.out.println(f1);//8.0E8,有的书上说E后面的数字就是他的指数 f1 =812345678.123456f;//整数部分8后面还有8位数字 System.out.println(f1);//8.1234566E8 f1 =0.11223344556677888f; System.out.println(f1);//0.112233445
/**
* floa转换为2进制
*/
//我们知道7的二进制为 4+2+1 即 0111
//我们知道8的二进制为 1000
System.out.println(Integer.toBinaryString(7));//111
System.out.println(Integer.toBinaryString(8));//1000
//即Integer.toBinaryString就是一个数的二进制表现形式
f1=8.1f;
System.out.println("8.1f的二进制为"+ Integer.toBinaryString(Float.floatToIntBits(f1)));
f1=99.5f;
int fi = Float.floatToIntBits(f1);
System.out.println("99.5f的二进制为"+ Integer.toBinaryString(fi));
//100 0010 1100 0111 0000 0000 0000 0000
//float是32位的前面可以补一个0
//0100 0010 1100 0111 0000 0000 0000 0000
继续往下看
7.2、近似存储
7.3、浮点数值之间的间隙
回过头在讨论下指数域
一个数表示成 x.……*2^n,这个n就数指数域要存的值
7.4、最近舍入模式
8、龙虎争霸-基本for循环和增强for循环
8.1、语法对比
先看一下二者在操作数组和集合之间的差别
public static void main(String[] args) {
int[] array = new int[] {1,2,3};
List<String> list = new ArrayList<String>();
list.add("top");
list.add("middle");
list.add("bottom");
//基本for循环
for(int i = 0;i<array.length;i++) {
System.out.println(array[i]);
}
Iterator<String> iterator = list.iterator();
//相当于while(iterator.hasNext())
for(;iterator.hasNext();) {
System.out.println(iterator.next());
}
//增强for循环,for each
for (int i : array) {
System.out.println(i);
}
for (String string : list) {
System.out.println(string);
}
}
8.2、加强for循环的极限
8.3、加强for循环的处理实现