- 浏览: 7937134 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (2425)
- 软件工程 (75)
- JAVA相关 (662)
- ajax/web相关 (351)
- 数据库相关/oracle (218)
- PHP (147)
- UNIX/LINUX/FREEBSD/solaris (118)
- 音乐探讨 (1)
- 闲话 (11)
- 网络安全等 (21)
- .NET (153)
- ROR和GOG (10)
- [网站分类]4.其他技术区 (181)
- 算法等 (7)
- [随笔分类]SOA (8)
- 收藏区 (71)
- 金融证券 (4)
- [网站分类]5.企业信息化 (3)
- c&c++学习 (1)
- 读书区 (11)
- 其它 (10)
- 收藏夹 (1)
- 设计模式 (1)
- FLEX (14)
- Android (98)
- 软件工程心理学系列 (4)
- HTML5 (6)
- C/C++ (0)
- 数据结构 (0)
- 书评 (3)
- python (17)
- NOSQL (10)
- MYSQL (85)
- java之各类测试 (18)
- nodejs (1)
- JAVA (1)
- neo4j (3)
- VUE (4)
- docker相关 (1)
最新评论
-
xiaobadi:
jacky~~~~~~~~~
推荐两个不错的mybatis GUI生成工具 -
masuweng:
(转)JAVA获得机器码的实现 -
albert0707:
有些扩展名为null
java 7中可以判断文件的contenttype了 -
albert0707:
非常感谢!!!!!!!!!
java 7中可以判断文件的contenttype了 -
zhangle:
https://zhuban.me竹板共享 - 高效便捷的文档 ...
一个不错的网络白板工具
第一个问题
直接打印 null 的 String 对象,会得到什么结果?
String s = null;
System.out.print(s);
运行的结果是
null
果然如书上说的没有抛出异常,而是打印了null。显然问题的线索在于print函数的源码中。我们找到print的源码:
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
看到源码才发现原来就只是加了一句判断而已,简单粗暴,可能你对 JDK 的简单实现有点失望了。放心,第一个问题只是开胃菜而已,大餐还在后面。
第二个问题
打印一个 null 的非 String 对象,例如说 Integer:
Integer i = null;
System.out.print(i);
运行的结果不出意料:
null
我们再去看看print的源码:
public void print(Object obj) {
write(String.valueOf(obj));
}
有点不一样的了,看来秘密藏在valueOf里面。
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
看到这里,我们终于发现了打印 null 对象不会抛出异常的秘密。print方法对 String 对象和非 String 对象分开进行处理。
String 对象:直接判断是否为 null,如果为 null 给 null 对象赋值为"null"。
非 String 对象:通过调用String.valueOf方法,如果是 null 对象,就返回"null",否则调用对象的toString方法。
通过上面的处理,可以保证打印 null 对象不会出错。
到这里,本文就应该结束了。
什么?说好的大餐呢?上面还不够塞牙缝呢。
开玩笑啦。下面我们来探讨第三个问题。
第三个问题(隐藏的大餐)
null 对象与字符串拼接会得到什么结果?
String s = null;
s = s + "!";
System.out.print(s);
结果可能你也猜到了:
null!
为什么呢?跟踪代码运行可以发现,这回跟print没有什么关系。但是上面的代码就调用了print函数,不是它会是谁呢?+的嫌疑最大,但是+又不是函数,我们怎么看到它的源代码?这种情况,唯一的解释就是编译器动了手脚,天网恢恢,疏而不漏,找不到源代码,我们可以去看看编译器生成的字节码。
L0
LINENUMBER 27 L0
ACONST_NULL
ASTORE 1
L1
LINENUMBER 28 L1
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "!"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 1
L2
LINENUMBER 29 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/String;)V
看了上面的字节码是不是一头雾水?这里我们就要扯开话题,来侃侃+字符串拼接的原理了。
编译器对字符串相加会进行优化,首先实例化一个StringBuilder,然后把相加的字符串按顺序append,最后调用toString返回一个String对象。不信你们看看上面的字节码是不是出现了StringBuilder。详细的解释参考这篇文章 Java细节:字符串的拼接。
String s = "a" + "b";
//等价于
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
String s = sb.toString();
再回到我们的问题,现在我们知道秘密在StringBuilder.append函数的源码中。
//针对 String 对象
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
//针对非 String 对象
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
现在我们恍然大悟,append函数如果判断对象为 null,就会调用appendNull,填充"null"。
直接打印 null 的 String 对象,会得到什么结果?
String s = null;
System.out.print(s);
运行的结果是
null
果然如书上说的没有抛出异常,而是打印了null。显然问题的线索在于print函数的源码中。我们找到print的源码:
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
看到源码才发现原来就只是加了一句判断而已,简单粗暴,可能你对 JDK 的简单实现有点失望了。放心,第一个问题只是开胃菜而已,大餐还在后面。
第二个问题
打印一个 null 的非 String 对象,例如说 Integer:
Integer i = null;
System.out.print(i);
运行的结果不出意料:
null
我们再去看看print的源码:
public void print(Object obj) {
write(String.valueOf(obj));
}
有点不一样的了,看来秘密藏在valueOf里面。
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
看到这里,我们终于发现了打印 null 对象不会抛出异常的秘密。print方法对 String 对象和非 String 对象分开进行处理。
String 对象:直接判断是否为 null,如果为 null 给 null 对象赋值为"null"。
非 String 对象:通过调用String.valueOf方法,如果是 null 对象,就返回"null",否则调用对象的toString方法。
通过上面的处理,可以保证打印 null 对象不会出错。
到这里,本文就应该结束了。
什么?说好的大餐呢?上面还不够塞牙缝呢。
开玩笑啦。下面我们来探讨第三个问题。
第三个问题(隐藏的大餐)
null 对象与字符串拼接会得到什么结果?
String s = null;
s = s + "!";
System.out.print(s);
结果可能你也猜到了:
null!
为什么呢?跟踪代码运行可以发现,这回跟print没有什么关系。但是上面的代码就调用了print函数,不是它会是谁呢?+的嫌疑最大,但是+又不是函数,我们怎么看到它的源代码?这种情况,唯一的解释就是编译器动了手脚,天网恢恢,疏而不漏,找不到源代码,我们可以去看看编译器生成的字节码。
L0
LINENUMBER 27 L0
ACONST_NULL
ASTORE 1
L1
LINENUMBER 28 L1
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "!"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 1
L2
LINENUMBER 29 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/String;)V
看了上面的字节码是不是一头雾水?这里我们就要扯开话题,来侃侃+字符串拼接的原理了。
编译器对字符串相加会进行优化,首先实例化一个StringBuilder,然后把相加的字符串按顺序append,最后调用toString返回一个String对象。不信你们看看上面的字节码是不是出现了StringBuilder。详细的解释参考这篇文章 Java细节:字符串的拼接。
String s = "a" + "b";
//等价于
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
String s = sb.toString();
再回到我们的问题,现在我们知道秘密在StringBuilder.append函数的源码中。
//针对 String 对象
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
//针对非 String 对象
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
现在我们恍然大悟,append函数如果判断对象为 null,就会调用appendNull,填充"null"。
发表评论
-
复习:强迫线程顺序执行方式
2019-01-03 23:42 1569方法1: 三个线程,t1,t2,t3,如果一定要按顺序执行, ... -
(转)不错的前后端处理异常的方法
2019-01-02 23:16 2018前言 在 Web 开发中, 我们经常会需要处理各种异常, 这是 ... -
info q的极客时间大咖说等资料下载
2018-08-15 08:40 3465info q的极客时间大咖说等资料下载,还有不少思维导图 链 ... -
CXF 客户端超时时间设置(非Spring配置方式)
2018-07-03 22:38 2232import org.apache.cxf.endpoint. ... -
(转)synchronized关键字画像:正确打开方式
2018-06-14 09:25 490https://mp.weixin.qq.com/s/b3Sx ... -
CountDownLatch的例子
2018-06-13 14:10 684public class StatsDemo { ... -
两道面试题,带你解析Java类加载机制
2018-06-12 16:29 607https://mp.weixin.qq.com/s/YTa0 ... -
Spring中获取request的几种方法,及其线程安全性分析
2018-06-11 09:03 669https://mp.weixin.qq.com/s/KeFJ ... -
内部类小结
2018-06-06 10:25 434https://mp.weixin.qq.com/s/hErv ... -
JVM虚拟机小结1
2018-06-04 20:43 5391 jps -l //列出详细的类名和进程ID 2)jps ... -
windows下自带命令行工具查看CPU资源情况等
2018-06-04 12:53 3097微软提供了不少命令行 ... -
(收藏)深入分析Java的序列化与反序列化
2018-05-30 15:21 614https://mp.weixin.qq.com/s/T2Bn ... -
apache common包中的序列化工具
2018-05-30 09:10 1843什么是序列化 我们的 ... -
JAVA8 JVM的变化: 元空间(Metaspace)
2018-05-24 22:30 963本文将会分享至今为至我收集的关于永久代(Permanent G ... -
(转)服务器性能指标(一)——负载(Load)分析及问题排查
2018-05-21 21:03 1360原创: Hollis Hollis 负载 ... -
(转)对象复用
2018-05-20 15:27 857public class Student { priv ... -
mapreduce中入门中要注意的几点
2018-05-06 08:59 670在 mapreduce中,比如有如下的词: I love b ... -
HDFS的基本操作
2018-05-02 21:47 937-mkdir 在HDFS创建目录 ... -
一个不错的开源工具类,专门用来解析日志头部的,好用
2018-05-02 20:00 768一个不错的开源工具类,专门用来解析日志头部的,好用。 http ... -
介绍个不错的RESTFUL MOCK的工具wiremock
2018-04-27 21:02 1904介绍个不错的RESTFUL MOCK的工具wiremock,地 ...
相关推荐
`Object.toString()`适合获取对象的自定义表示,类型转换适用于已知可转换类型的对象,而`String.valueOf(Object)`则在处理可能为`null`的对象时提供了一定的容错性。同时,`Integer.parseInt()`和`Integer.valueOf...
此外,Java 还提供了异常处理机制,通过 `try-catch` 块来捕获和处理异常,从而提高代码的容错能力。 总的来说,Java 语言提供了丰富的特性和工具,如访问修饰符、匿名内部类、内部类、逻辑运算符、集合框架、断言...
Node.js是一款基于Chrome V8引擎的JavaScript运行环境,常用于构建服务器端和网络应用,而Gson则是Google提供的一个Java库,主要用于在Java对象和JSON数据之间进行映射,特别适用于Android开发中的JSON格式处理。...
Java 生成二维码是一种常见的数据编码需求,ZXing(Zebra Crossing)是一个开源的、多格式的一维/二维条码图像处理库,它支持多种条码和二维码的生成与解码。在Java中利用ZXing库生成二维码,可以方便地将文本、链接...
总之,RabbitMQ作为消息中间件,能有效地解耦应用程序,提高系统的可扩展性和容错性。Java开发者可以通过`amqp-client`库轻松地与RabbitMQ集成,实现高效的数据交换。在这个简单的demo中,我们学习了如何创建连接、...
在实际应用中,我们还需要考虑错误处理、二维码格式转换、容错级别调整等因素,以满足不同场景的需求。在进行这些操作时,确保遵循最佳实践,比如合理设置容错级别以提高二维码的抗损能力,以及在生成带Logo的二维码...
Java 二维码生成与解析是Java开发中常见的功能需求,尤其在移动互联网时代,二维码被广泛应用于数据交换、链接跳转、支付凭证等场景。本文将详细介绍如何使用Google的ZXing库来实现Java环境下的二维码生成与解析。 ...
Java连接FastDFS上传图片是一项常见的任务,特别是在分布式存储系统中。FastDFS是一个开源的高性能、轻量级的分布式文件系统,适用于互联网行业的大型网站或应用,用于存储和共享大量小文件,如图片、文档等。Java...
在Java编程环境中,访问Hadoop集群是一项常见的任务,特别是在大数据处理和分析的场景下。Hadoop是一个开源框架,主要用于存储和处理大规模数据集。本文将深入探讨如何利用Java API来与Hadoop集群进行交互,包括读取...
不可变对象是创建后其状态不能改变的对象,例如Java中的String。 13. **如何编写排序程序?** 可以使用Java内置的`Arrays.sort()`或Collections的`sort()`方法对数组或集合进行排序,也可以自定义排序算法,如...
在学习和使用这个Java后台生成二维码工具类时,可以尝试不同的输入参数,观察生成的二维码效果,并了解不同错误纠正级别对二维码容错能力的影响。通过实践,你将更好地掌握Java生成二维码的技术。
在实际应用中,我们还需要考虑错误处理和容错机制,因为二维码在被拍摄或打印后可能会出现部分损坏。通过选择不同的错误校正级别(例如,这里使用了ErrorCorrectionLevel.H),我们可以提高二维码在损坏情况下的...
以上就是关于RabbitMQ HelloWorld Java代码的详细解析,希望对你理解RabbitMQ的基础使用有所帮助。在实际开发中,你可以根据项目需求调整这些基础示例,例如使用不同的交换机类型、路由键,或者实现更复杂的消费逻辑...
Spouts负责生成数据流,而Bolts则对这些流进行处理,如过滤、聚合等操作。 在Java中,我们首先需要导入Storm相关的库,例如`storm-core`。然后,我们可以创建一个名为`stormtest`的项目,并定义拓扑类。这个类通常...
本教程将通过Java API来探讨如何与HDFS进行交互,从而实现对文件系统的操作。HDFS Java API是开发人员与HDFS进行通信的主要接口,它提供了丰富的类和方法,使得在Java程序中读写HDFS文件变得简单易行。 首先,我们...
在IT行业中,消息队列(Message Queue)是一种重要的中间件技术,用于解耦应用程序的不同组件,提高系统的可扩展性和容错性。RabbitMQ作为一款广泛使用的开源消息代理,它支持多种消息协议,包括AMQP(Advanced ...
本教程将对RabbitMQ在Java环境下的使用进行深入解读。 首先,我们需要了解RabbitMQ的基本概念。消息队列是应用程序之间通信的一种方式,它可以缓存消息并保证它们在系统间的可靠传输。在RabbitMQ中,有以下几个核心...
在Hadoop生态系统中,Java API是开发者常用的一种与HDFS(Hadoop Distributed File System)进行...通过这些操作,开发者可以在Java程序中实现对HDFS的读写、管理和操作,从而利用Hadoop的强大功能处理大规模的数据。
要生成一个基本的二维码,我们需要创建一个`BitMatrix`对象,然后使用`QRCodeWriter`将其编码为二维码格式。以下是一个简单的示例: ```java import com.google.zxing.BarcodeFormat; import ...