Java解惑笔记(一)

Java解惑笔记(一)
《java解惑》是由Joshua Bloch(美)、Neal Gafter(美)编著,陈昊鹏翻译的计算机语言类丛书,该书由人民邮电出版社2006年发行出版。该书特写了95个有关Java或其类库的陷阱和缺陷的谜题,其中大多数谜题都采用了短程序的方式,这些程序的行为与其看似的大相径庭。在每个谜题之后都给出了详细的解惑方案,这些解惑方案超越了对程序行为的简单解释,向读者展示了如何一劳永逸地避免底层的陷阱与缺陷。


这里是笔记,所以不要脸的贴上原创标签,但是一切荣誉与属于原作者,我只是个读者和搬运工。
之前的没有做笔记的部分,那就算了吧,有兴趣的可以去看书,是表达式之谜,字符之谜。

TEST20:类名转换1
public class Test20 {
    public static void main(String[] args) {
        System.out.println(
                Test20.class.getName().replaceAll(".", "/")+"class"
                );

    }
}

console://class

原因:String.replaceAll接受了一个正则表达式作为它的第一个参数。

​ 正则表达式”.”可以匹配任何一个字符,因此String中每一个字符都被替换成”/“

Test20.class.getName().replaceAll("\\.", "/")+".class"
TEST21:类名转换2
public class Test21 {
    public static void main(String[] args) {
        System.out.println(
                Test21.class.getName().
                replaceAll("\\.", File.separator)+".class"
                );

    }
}

consle:Exception in thread “main” java.lang.IllegalArgumentException: character to be escaped is missing

原因:在windows平台上 File.separator 为 “/” ,单独出现一个 “\” 是无效的。

解决办法:String.replace(CharSequence,CharSequence),她将两个参数都作为字符常量处理。

Test21.class.getName().
            replace(".", File.separator)+".class"
TEST22 :URL的愚弄
public class Test22 {
    public static void main(String[] args) {
        System.out.print("iexplore:");
        http://www.baidu.com;
        System.out.println(":maximize");
    }
}

consle:iexplore::maximize

原因:程序中出现的URL是一个语句标号(statement label)后面跟着尾注释。它是合法的,但是没有什么用处。

仔细的写注释,并让他跟上朝代。

TEST23:不劳而获
package com.test;
import java.io.File;
import java.util.Random;

public class Test23 {
    private static Random random =  new Random();
    public static void main(String[] args) {
        StringBuffer word = null;
        switch (random.nextInt(2)) {
        case 1: word =new StringBuffer('P');
        case 2: word =new StringBuffer('G');    
        default: word =new StringBuffer('M');
         }
        word.append('a');
        word.append('i');
        word.append('n');
        System.out.println(word);   
    }
}

consle:只能输出ain

原因:栅栏柱错误,Random.nextInt(2),只可能取到0,1两个随机数。

​ :case没有后续的break语句时,将会后续的case。

​ :new StringBuffer(‘M’),不能实现预期目标。StringBuffer有三个构造器:无参,接受一个String作为字符串缓冲区初始内容的构造器,一个接受一个int作为缓冲器初始容量的构造器。new StringBuffer(‘M’)将被编译器作为int构造器,通过扩宽原生类型把M转换为int数值77.

public class Test23 {
    private static Random random =  new Random();
    public static void main(String[] args) {
        StringBuffer word = null;
        switch (random.nextInt(3)) {
        case 1: word =new StringBuffer("P"); break;
        case 2: word =new StringBuffer("G"); break; 
        default: word =new StringBuffer("M"); break;
        }
        word.append('a');
        word.append('i');
        word.append('n');
        System.out.println(word);
    }
}

更优雅的版本:

public class Test23 {
    private static Random random =  new Random();
    public static void main(String[] args) {
        System.out.println("PGM".charAt(random.nextInt(3))+"ain");
    }
}

更通用的版本:

public class Test23 {
    private static Random random =  new Random();
    public static void main(String[] args) {
        String a[] = {"Pain","Gain","Main"};
        System.out.println(randomElement(a));
    }
    public static String randomElement(String[] a) {
        return a[random.nextInt(a.length)];
    }
}
循环之谜
TEST24:Byte
public class Test24 {
    public static void main(String[] args) {
        for(byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++){
            if (b == 0x90) {
                System.out.println("JOY");
            }
        }
    }
}

输出为空

原因:0x90超出了Byte的数值范围。Byte为8bit,但是是一个有符号数,其最高位是符号位取值范围为-128到+127。常量0x90(十六进制)是一个最高位被占位的8位int数值,其值为+144。

解决方法:避免混合类型比较

if (b == (byte)0x90) 

用一个屏蔽码来消除符号扩展的影响

if ((b & 0xff)== 0x90) 

​ :用声明的常量代替 0x90

private static final byte  Target = (byte)0x90;
TEST25:无情的增量操作
public class Test25{
    public static void main(String[] args) {
        int j = 0;
        for(int i = 0; i < 100; i++) {
            j = j++;
        }
        System.out.println(j);
    }
}

consle:0

原因:j = j++;没有达到预期的效果。j++的值等于j在执行增量操作之前的初始值。

解决方法:

for(int i = 0; i < 100; i++)
    j++;

不要在单个表达式中对相同的变量赋值超过一次。

TEST26:在循环中
public class TEST {
    public static final int END  = Integer.MAX_VALUE;
    public static final int START  = END - 100;

    public static void main (String[] args){
        int count  = 0;
        for (int i = START; i <= END; i++){
            count++;
        }
        System.out.print(count);
    }
}

输出count结果:不输出

原因:陷入无限循环

​ 当i达到Integer.MAX_VALUE,时,再次执行增量操作。它将绕回到Integer.MIN_VALUE.

解决办法:long i

TEST29:循环者的新娘

提供一个声明,将下面的循环转变为无限循环

while(i != i){}

解决办法:NaN(not a number):没有良好的数字定义的浮点数计算的值。

​ NaN不等于任何浮点数值,包括它自身在内

​ 任何浮点操作,只要它的一个或多个操作数为NaN,那么其结果为NaN

​ 一旦一个计算产生了NaN,它就被损坏了,且无法被修复。

​ double i = Double.NaN;

​ 或 double i = 0.0 / 0.0;

TEST30:循环者的爱子

提供一个声明,将下面的循环转变为无限循环。但不可使用浮点数

while(i != i + 0){}

解决办法:将i定义为String类型。

​ 唯一的“+”操作符有定义的非数值类型就是String。其执行字符串的连接。

TEST32:循环者的诅咒

提供对i,j的声明,使得循环变成无限

while(i <= j && j <= i && i != j){}

一波:

​ < ,<=,> ,>=,两侧的操作数类型必须可以转换成原始的数字类型(byte,char,short,int,和double)

那被包装的数值类型有(Byte,Character,Short,Integer,Long,Float,Double)

对于包装类,< ,<=,> ,>=,,操作将解包转换。而 = 是引用ID比较,即是判断否是同一个对象。

解决办法:

Integer i = new Integer(0);
Integer j = new Integer(0);

TEST33:循环者遇到狼人

提供一个对i的声明,将下面的循环转变为无限

while(i != 0 && i == -i)

1,i不可为NaN,因为 ”-i“中的”-“是一元符号,则i必须是数字类型数值,否则不合法。

2,有符号数的整数雷鑫使用二进制补码运算,取一个数的复值,要对其中每一位取反,然后加一,其中0有唯一的表示。

3,正和负数的个数不一样。至少有一个int数值,其负值不能正确的表示为int数值。

4,Interger.MIN_VALUE:-2的31次方。它的十六进制表示为0x80000000,为这个值取负,得到:0x7fffffff+1即0x80000000.满足条件。

5,同理,Long.MIN_VALUE.也可。

java使用2的补码的算术运算是不对称的,对于每一种有符号数,负数比正数要多出一个。

TEST34:被计数击倒

count的值为多少。

public class TEST {
    public static void main (String[] args){
        int count  = 0;
        final int START = 2000000000;
        for (float f = START; f < START + 50; f++){
            count++;
        }
        System.out.print((float)(START));
        System.out.print((float)(START+50));
        System.out.print(count);
    }
}

解:

count为0,不循环。

(float)(START)==(float)(START+50)==2.0E9。

原因:float只提供到24位精度。占满。

使用浮点数,最佳选择是double。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值