1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-07-24 07:21:46 +08:00
Java-Interview-Guide/docs/java/basis/Java基础知识疑难点.md
2021-09-06 22:56:57 +08:00

138 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 正确使用 equals 方法
Object的equals方法容易抛空指针异常应使用常量或确定有值的对象来调用 equals。
举个例子:
```java
// 不能使用一个值为null的引用类型变量来调用非静态方法否则会抛出异常
String str = null;
if (str.equals("SnailClimb")) {
...
} else {
..
}
```
运行上面的程序会抛出空指针异常但是我们把第二行的条件判断语句改为下面这样的话就不会抛出空指针异常else 语句块得到执行。:
```java
"SnailClimb".equals(str);// false
```
不过更推荐使用 `java.util.Objects#equals`(JDK7 引入的工具类)。
```java
Objects.equals(null,"SnailClimb");// false
```
我们看一下`java.util.Objects#equals`的源码就知道原因了。
```java
public static boolean equals(Object a, Object b) {
// 可以避免空指针异常。如果a=null的话此时a.equals(b)就不会得到执行,避免出现空指针异常。
return (a == b) || (a != null && a.equals(b));
}
```
**注意:**
Reference:[Java中equals方法造成空指针异常的原因及解决方案](https://blog.csdn.net/tick_tock97/article/details/72824894)
- 每种原始类型都有默认值一样如int默认值为 0boolean 的默认值为 falsenull 是任何引用类型的默认值,不严格的说是所有 Object 类型的默认值。
- 可以使用 == 或者 != 操作来比较null值但是不能使用其他算法或者逻辑操作。在Java中`null == null`将返回true。
- 不能使用一个值为null的引用类型变量来调用非静态方法否则会抛出异常
## 整型包装类值的比较
所有整型包装类对象值的比较必须使用equals方法。
先看下面这个例子:
```java
Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);//false
```
`Integer i1=40` 这一行代码会发生装箱,也就是说这行代码等价于 `Integer i1=Integer.valueOf(40)` 。因此,`i1` 直接使用的是常量池中的对象。而`Integer i1 = new Integer(40)` 会直接创建新的对象。因此,输出 false 。
记住:**所有整型包装类对象之间值的比较,全部使用 `equals()` 方法比较**。
![](https://img-blog.csdnimg.cn/20210313164740893.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MzM3Mjcy,size_16,color_FFFFFF,t_70)
**注意:** 如果你的IDE(IDEA/Eclipse)上安装了阿里巴巴的p3c插件这个插件如果检测到你用 ==的话会报错提示,推荐安装一个这个插件,很不错。
## BigDecimal
### BigDecimal 的用处
《阿里巴巴Java开发手册》中提到**浮点数之间的等值判断,基本数据类型不能用==来比较,包装数据类型不能用 equals 来判断。** 具体原理和浮点数的编码方式有关,这里就不多提了,我们下面直接上实例:
```java
float a = 1.0f - 0.9f;
float b = 0.9f - 0.8f;
System.out.println(a);// 0.100000024
System.out.println(b);// 0.099999964
System.out.println(a == b);// false
```
具有基本数学知识的我们很清楚的知道输出并不是我们想要的结果(**精度丢失**),我们如何解决这个问题呢?一种很常用的方法是:**使用 BigDecimal 来定义浮点数的值,再进行浮点数的运算操作。**
```java
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");
BigDecimal x = a.subtract(b);
BigDecimal y = b.subtract(c);
System.out.println(x); /* 0.1 */
System.out.println(y); /* 0.1 */
System.out.println(Objects.equals(x, y)); /* true */
```
### BigDecimal 的大小比较
`a.compareTo(b)` : 返回 -1 表示 `a` 小于 `b`0 表示 `a` 等于 `b` 1表示 `a` 大于 `b`
```java
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
System.out.println(a.compareTo(b));// 1
```
### BigDecimal 保留几位小数
通过 `setScale`方法设置保留几位小数以及保留规则。保留规则有挺多种不需要记IDEA会提示。
```java
BigDecimal m = new BigDecimal("1.255433");
BigDecimal n = m.setScale(3,BigDecimal.ROUND_HALF_DOWN);
System.out.println(n);// 1.255
```
### BigDecimal 的使用注意事项
注意我们在使用BigDecimal时为了防止精度丢失推荐使用它的 **BigDecimal(String)** 构造方法来创建对象。《阿里巴巴Java开发手册》对这部分内容也有提到如下图所示。
![《阿里巴巴Java开发手册》对这部分BigDecimal的描述](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019/7/BigDecimal.png)
### 总结
BigDecimal 主要用来操作浮点数BigInteger 主要用来操作大整数(超过 long 类型)。
BigDecimal 的实现利用到了 BigInteger, 所不同的是 BigDecimal 加入了小数位的概念
## 基本数据类型与包装数据类型的使用标准
Reference:《阿里巴巴Java开发手册》
- 【强制】所有的 POJO 类属性必须使用包装数据类型。
- 【强制】RPC 方法的返回值和参数必须使用包装数据类型。
- 【推荐】所有的局部变量使用基本数据类型。
比如我们如果自定义了一个Student类,其中有一个属性是成绩score,如果用Integer而不用int定义,一次考试,学生可能没考,值是null,也可能考了,但考了0分,值是0,这两个表达的状态明显不一样.
**说明** :POJO 类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何 NPE 问题,或者入库检查,都由使用者来保证。
**正例** : 数据库的查询结果可能是 null因为自动拆箱用基本数据类型接收有 NPE 风险。
**反例** : 比如显示成交总额涨跌情况,即正负 x%x 为基本数据类型,调用的 RPC 服务,调用不成功时,返回的是默认值,页面显示为 0%,这是不合理的,应该显示成中划线。所以包装数据类型的 null 值,能够表示额外的信息,如:远程调用失败,异常退出。