Java常见疑难问题-应用16


51. 静态导入的优先权
import static .util.Arrays.toString;
import .util.Arrays;
public class T {
public static void main(String[] args) {
prt(1, 2, 3);
}
static void prt(Object… args) {
// 自身继承至Object类的toString的优先级高于静态导入的方法
//!! System.out.println(toString(args));//不能
System.out.println(Arrays.toString(args));
}
}

本身就属于某个范围的成员在该范围内与静态导入相比具有优先权。
52. PrintStream对输出结果的缓冲
public static void main(String[] args) {
String str = “Hello World”;
for (int i = 0; i System.out.write(str.charAt(i));
}
}
上面的程序没有输出结果。

这里的在于System.out是带有缓冲的。输出的结果被写入了System.out的缓冲区,但是
缓冲区从来都没有被刷新。大多数人认为,当有输出产生的时候System.out和System.err会
自动地进制刷新,但这并不完全正确,这两个流都属于PrintStream类型,请看API DOC描
述:一个PrintStream被创建为自动刷新,这意味着当一个字节数组(byte[])被写入、或者
某个println方法被调用、或者一个换行字符或字节('
‘)被写入之后,PrintStream类型的
flush方法就会被自动调用。

令人奇怪的是,如果这个程序用print(char)去替代write(int),它就会刷新System.out并输出
结果,这种行为与print(char)的文档是矛盾的,因为其文档叙述道:”打印一个字符,这个字
符将根据平台缺省的字符编码方式翻译成一个或多个字节,并且这些字节将完全按照
write(int)方法的方式输出。”,但这里没有换行符却也自动的刷新了。类似的,如果程序改用
print(String),它也会对流进行刷新。所以调用print方法也是会自动刷新的。

请加入到原博客中:PrintStream也可以对OutputStream进行包装并指定编码方式:
PrintStream(OutputStream out, boolean autoFlush, String encoding),但实质上也是调用
OutputStreamWriter来实现的。

System.err在eclipse中输出时是红色的字体。
53. 调用命令时被阻塞
public static void main(String[] args) throws IOException,
InterruptedException {
String command = “java ProcessTest exc”;
if (args.length != 0) {
for (int i = 0; i System.out.println(command);
System.err.println(command);
}
} else {
Process process = Runtime.getRuntime().exec(command);
int exitValue = process.waitFor();
System.out.println(“exit value = ” + exitValue);
}
}
执行java ProcessTest发现程序阻塞。

Process文档描述:由于某些本地平台只提供有限大小的缓冲,所以如果不能迅速地读取子
进程的输出流,就有可能会导致子进程的阻塞,甚至是死锁。这恰好就是这里所发生的事情:
没有足够的缓冲空间来保存这些输出结果。为了结子进程(Process线程),父进程(Main
线程)必须排空它的输出流(标准流与错误流都需要排空),即要去缓存中读取结果:
static void readResult(final InputStream is) {
new Thread(new Runnable() {
public void run() {
try {
// 排空缓存内容
while (is.read() >= 0);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
然后在process.waitFor()之前加上
readResult(process.getErrorStream());
readResult(process.getInputStream());
即可输出exit value = 0。

另外,只能根据process.waitFor返回的结果来判断命令执行是否成功(成功:0,
失败:1),我们不能根据错误流中是否有内容来判断是否执行成功。
54. 实现Serializable的单例
class Dog implements Serializable{
public static final Dog INSTANCE = new Dog();
private Dog(){}
}
上面能控制只生成一个单实例吗?

如果对实现了Serializable的对象进行序列化后,再反序列化,内中会不只一个实例了,因
为反序列化时会重新生成一个对象。

既然INSTANCE为静态域,那序列化时返回的对象如果也是INSTANCE就可以解决了,
而打开API我们发现Serializable接口确实有这样两个特殊的方法描述:
? 将对象写入流时需要指定要使用的替代对象的可序列化类,应使用准确的签名来实现此
特殊方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
此 writeReplace 方法将由序列化调用,前提是如果此方法存在,而且它可以通过被序列化
对象的类中定义的一个方法访问。因此,该方法可以拥有私有 (private)、受保护的 (protected)
和包私有 (package-private) 访问。子类对此方法的访问遵循 java 访问规则。
? 在从流中读取类的一个实例时需要指定替代的类应使用的准确签名来实现此特殊方法:
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
此 readResolve 方法遵循与 writeReplace 相同的调用规则和访问规则。

上述两个方法的只要出现,就会履盖以下两个方法(这两个方法本质的意义就是用来替换序
列与返序列的对象),虽然会执行它们,但最后得到的结果却是writeReplace、readResolve
两个方法写入或读出的对象:
? private void writeObject(java.io.ObjectOutputStream out) throws IOException
? private void readObject(java.io.ObjectInputStream in)throws IOException,
ClassNotFoundException;

另外,writeObject与readObject需成对实现,而writeReplace与readResolve则不需要成对
出现,一般单独使用。如果同时出现这四个方法,最后写入与读出的结果以writeReplace和
readResolve方法的结果为准。

所以下要解决真真单实例,我们如下修正:
class Dog implements Serializable {
public static final Dog INSTANCE = new Dog();
private Dog() {}
private Object readResolve() {
return INSTANCE;
}
}

public class SerialDog {
public static void main(String[] args) throws IOException,
ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
new ObjectOutputStream(bos).writeObject(Dog.INSTANCE);
ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray());
Dog dog = (Dog) new ObjectInputStream(bin).readObject();
System.out.println(dog == Dog.INSTANCE);//true
}
}

一个实现了Serializable的单例类,必须有一个readResolve方法,用以返回它的唯一实例。

声明: 除非转自他站(如有侵权,请联系处理)外,本文采用 BY-NC-SA 协议进行授权 | 智乐兔
转载请注明:转自《Java常见疑难问题-应用16
本文地址:https://www.zhiletu.com/archives-249.html
关注公众号:智乐兔

赞赏

wechat pay微信赞赏alipay pay支付宝赞赏

上一篇
下一篇

相关文章

在线留言

你必须 登录后 才能留言!

在线客服
在线客服 X

售前: 点击这里给我发消息
售后: 点击这里给我发消息

智乐兔官微