java解惑之字符之谜(谜题16)

谜题16:行打印程序

行分隔符是为分割文本行的字符或字符串而起的名字,并且在不同平台上它是存在差异的。在windows平台上,它由CR字符(回车)和紧随其后的LR(换行)字符组成。在UNIX平台上,通常引用单独的LF字符作为换行字符。那么,这次的谜题也就由行分隔符引出,来看看下面这个将LF字符传递给println方法的程序会打印什么,它的行为是否依赖于平台?

public class LinePrinter{
public static void main(String[] args){
//Note:\u000A is Unicode representation of linefeed(LF)
char c = 0x000A;
System.out.println(c);
}
}

其实这个程序的行为是平台无关的:它在任何平台上都不能通过编译。如果你尝试着去编译它,就会得到类似下面的出错信息:

LinePrinter.java:3:';' expected
//Note:\u000A is Unicode representation of lintfeed(LF)
1 error

看到这个或许大家都会感到熟悉,没错,这正是和谜题15犯了一样的错,在第三行注释中,\u000A是一个Unicode转义字符,谜题15中已经介绍了Unicode转义字符,不清楚的可以去看看谜题15,那么在编译器丢弃注释之前,这个Unicode转义字符就会适时的被转义为一个行分隔符,也就是说,转义后将要编译的代码是这样:

public class LinePrinter{
public static void main(String[] args){
//Note:
is Unicode representation of linefeed(LF)
char c = 0x000A;
System.out.println(c);
}
}

很显然这样的代码是不能通过编译的,修正程序最简单的方法就是在注释中移除Unicode转义字符,但这样做或许会让程序阅读者对代码要表达的内容感到迷惑,所以更好的方法是将行分隔符直接用一个转义字符序列而不是用一个十六进制整型字面常量来初始化,这样就能清楚的表达程序的内容了,从而也就不需要多余的注释了。

public class LinePrinter{
public static void main(String[] args){
char c = '\n';
System.out.println(c);
}
}

只要这么做了,程序就能确保编译通过并运行,但是这仍是一个有问题的程序,之前未修正的程序的行为(即出现编译错误)是与平台无关的,那么修正后的程序出现的行为是与平台有关的,原因也正是本谜题所要提醒的。在某些平台上,例如UNIX,它将打印两个完整的行分隔符;但是在其它平台上,例如Windows,它就不会产生这样的行为。尽管这些输出用肉眼看是一样的,但是如果它们被存储到文件中,或是输出到后续的其他处理程序中,就容易引发问题了。如果是想要打印两行空行,就应该老老实实的调用两次println方法。如果恰好使用的是JDK
5.0,那么你还可以使用格式化字符串"%n%n"的printf来代替println。%n的每一次出现都讲导致printf打印一个恰当的、与平台相关的行分隔符。

通过谜题14、谜题15以及本谜题,我们都能清楚的认识到Unicode转义字符绝对会产生混乱。所以,我们除非在确实是必需的情况下,否则就不要使用Unicode转义字符。

时间: 2024-12-09 06:59:00

java解惑之字符之谜(谜题16)的相关文章

java解惑之字符之谜(谜题20)

谜题20:我的类是什么 来看一个打印其类文件名称的程序: package com.javapuzzlers; public class Me{ public static void main(String[] args){ System.out.println(Me.class.getName().replaceAll(".","/") + ".class"); } } 这个程序是先获得它的类名("com.javapuzzlers.Me

java解惑之字符之谜(谜题21)

谜题21:我的类是什么?镜头2 下面的程序所要做的事情正是前一个谜题所做的事情,但是它没有假设斜杠符号就是分隔文件名组成部分的符号.相反,该程序使用的是java.io.File.separetor,它被指定为一个公共的String域,包含了平台相关的文件名分隔符.这个程序会打印正确的.平台相关的类文件名吗?该程序是从这个类文件中被加载的. package com.javapuzzlers; import java.io.File; public class MeToo{ public stati

java解惑之字符之谜(谜题18)

谜题18:字符串奶酪 下面这个程序从一个字节序列创建一个字符串,然后迭代遍历字符串中的字符,并将它们作为数字打印.请描述程序打印的数字序列: public class StringCheese{ public static void mian(String[] args){ byte bytes[] new byte[256]; for(int i = 0; i < 256; i++){ bytes[i] = (byte)i; } String str = new String(bytes);

java解惑之字符之谜(谜题22)

谜题22:URL的愚弄 本谜题利用了一个java编程语言中一个鲜为人知的特性.请考虑下面的程序将会做什么? public class BrowerTest{ public static void main(String[] args){ System.out.ptintln("iexplore"); http://www.google.com; System.out.println(":maximize"); } } 这是个有点诡异的问题.当我们初次看到这个程序时,

Java解惑三:循环之谜

谜题24 byte是有符号的,范围是-128 - 127.而0x90是int类型.比较的时候,不相等. 如果想让其相等,需要进行类型转换:(byte & 0xff) 或者 (byte)0x99. 谜题25 自增运算符对循环的影响.j = j++,先赋值. 谜题26 Integer.MAX_VALUE加一之后会变成Integer.MIN_VALUE,这对循环会有影响. 可以考虑使用long来表示i变量,或者使用效率更高的i != Integer.MAX_VALUE. 谜题27 (-1 <<

Java解惑七:更多类之谜

谜题66 继承的问题. 对于实例方法:命名相同时,子类会覆写父类的方法,且访问权限至少和父类一样大. 对于域:命名相同时,子类会隐藏父类的域,且访问权限任意. 谜题67 不要重用库中的类名. 谜题68 命名的问题. 类名应该以大写字母开头,形式为:MixedCase. 变量以小写字母开头,形式为:mixedCase. 常量以大写字母开头,形式为:MIXED_CASE. 单个大写字母,只能用于类型参数,形式为:Map<K, V>. 包名应该都是小写,形式为:lower.case. 当一个变量和一

Java解惑五:类之谜

本文是依据JAVA解惑这本书,做的笔记.电子书见:http://download.csdn.net/detail/u010378705/7527721 谜题46 函数重载的问题. JAVA重载解析过程:1. 选取全部可用的方法或者构造器:2. 从过程1中选取的方法或构造器中选择最精确的. 一般而言:能够强制要求编译器选择一个精确的重载版本号,将实參转型为形參所声明的类型. 谜题47 继承中静态域的问题. 静态域由声明它的类及其全部子类共享. 假设须要让每个子类都具有某个域的单独拷贝,必须在每个子

Java解惑八:更多库之谜

本文是根据JAVA解惑这本书,做的笔记. 电子书见:http://download.csdn.net/detail/u010378705/7527721 谜题76 将线程的启动方法start(),写成了run(); PS:管程(monitor)锁有待进一步理解. 谜题77 线程中锁的问题. 理解不深刻. 谜题78 反射会造成访问其他包中的非公共类型的成员,引起运行期异常. 谜题79 遮蔽:Thread.sleep()方法遮蔽了自定的方法. 谜题80 反射:如何实例化非静态内部类以及静态内部类.

Java解惑六:库之谜

本文是根据JAVA解惑这本书,做的笔记. 电子书见:http://download.csdn.net/detail/u010378705/7527721 谜题56 BigInteger.BigDecimal以及包装类型的实例是不可改变. BigInteger five = new BigInteger("5"); BigInteger total = BigInteger.ZERO; total.add(five); //这并不会改变total的值,调用该方法的返回值,才是加法得到的结