转载

Java 中常见的几个陷阱,你没有遇到几个?

概述

Java 中常见的几个陷阱,你没有遇到几个?

java 中有很多,新手经常遇到的陷阱,本文主要包含

  • 自动装箱与拆箱
  • 不可变的String
  • 内存泄漏
  • 自增类型使用
  • 使用 “==”进行对象比较
  • double 类型计算

不可变的String

Java String类是不可变的(不可修改)。这是因为String对象被缓存在String池中。字符串引用的对象可以更改,但字符串对象本身不能更改。

Java 中常见的几个陷阱,你没有遇到几个?

字符串是不可变的。一旦创建了字符串,以后将无法更改该字符串对象。

Java使用按值传递,而不是按引用传递。当您在方法中为分配新值时,它只会修改本地,而不是调用代码中的原始s

Java 中常见的几个陷阱,你没有遇到几个?

自动装箱与拆箱

装箱就是自动将基本数据类型转换为包装器类型;

拆箱就是自动将包装器类型转换为基本数据类型。

装箱拆箱的类型有哪些?

Java 中常见的几个陷阱,你没有遇到几个?

通过上图,可以看出,java 基本类型可以进行拆装箱。

那拆装箱会出现什么问题呢?

Java 中常见的几个陷阱,你没有遇到几个?
Java 中常见的几个陷阱,你没有遇到几个?

通过实例,上面两个程序,计算耗时相差近10倍,在大量存在装箱行为时,会导致程序性能低下。

当封装类型进行==、+、-、*、/计算时,会自动拆箱,对基础数据类型进行运算.所以在进行计算时,使用基本数据类型。

内存泄漏

Java的核心优势之一是 Java垃圾收集器,它可以管理堆上的对象内存。每当对象不可访问时,它将自动释放。

但是,对于新手和有经验的程序员而言,常见的错误是通过允许不再使用的对象可访问来防止释放内存。这可能对项目造成很大的不利影响,因为内存泄漏会阻塞资源并降低应用程序性能。它甚至可能导致java.lang.OutOfMemoryError。

常见的情况是:

  • 静态字段声明。静态字段,并在不再需要其数据后忘记将其设置为null
  • 未正常关闭流。 Java虚拟机为每个打开的连接分配内存。忘记关闭连接会消耗内存。这样的连接可以是:输入流,数据库连接,会话等。
  • finalize() 方法。当我们覆盖的finalize()方法,finalize()只会在对象内存回收前被调用一次,具有不确定行,只保证方法会调用,但不保证方法里的任务会被执行完。所以尽量避免使用。在Java 9 中,已经声明为过期函数,

自增类型使用

Java中运算符的计算顺序是在同等级下从左到右计算,看下自增情况

Java 中常见的几个陷阱,你没有遇到几个?

第一种情况的执行上下文如下:

1.存储操作数的先前值。

2.增加值。

3.返回上一个值

第二种情况的执行上下文如下:

1.增加值。

2.存储操作数的值(递增)

3.返回值

使用 “==”进行对象比较

许多新手程序员尝试使用“ ==”运算符比较对象,并且当代码的行为不符合预期时,就会感到困惑。需要注意的是,关系运算符“ ==”正在进行引用比较,它检查两个对象是否都指向内存中的相同位置。使用 .equals()方法将消除此问题,因为它会比较对象内部的值。

Java 中常见的几个陷阱,你没有遇到几个?

尽管有时“ ==”运算符会给出预期的答案:

Java 中常见的几个陷阱,你没有遇到几个?

这是什么原因呢?同样是字符串,创建的方式不同,差距咋这么大呢

Java语言规范的字符串文字中:同一包中不同类内的文字字符串表示对同一String 对象的引用

如果还不清楚那看下两种字符串创建过程

第一种new的方式

new一个字符串时,做了两件事。首先在堆中生成了该字符串对象,然后去看常量池中有没有该字符串,如果有就不管了,没有就往常量池中添加一个

Java 中常见的几个陷阱,你没有遇到几个?

第二种,直接赋值

这样创建字符串,首先会去常量池里找有没有这个字符串,有就直接指向常量池的该字符串,没有就先往常量池中添加一个,再指向它。

Java 中常见的几个陷阱,你没有遇到几个?

上面就是两种方式的对比情况了。

Java 中常见的几个陷阱,你没有遇到几个?

两个Integer 对比

Java 中常见的几个陷阱,你没有遇到几个?

那为什么100的时候就是相等200就不行了呢这是由于Integer 使用了缓存。

Java 中常见的几个陷阱,你没有遇到几个?

其static块中就一次性生成了-128到127直接的Integer类型变量存储在cache[]中,对于-128到127之间的int类型,返回的都是同一个Integer类型对象。

整个工作过程就是:Integer.class在装载(Java虚拟机启动)时,其内部类型IntegerCache的static块即开始执行,实例化并暂存数值在-128到127之间的Integer类型对象。

当自动装箱int型值在-128到127之间时,即直接返回IntegerCache中暂存的Integer类型对象。

为什么Java这么设计?应该是出于效率考虑,因为自动装箱经常遇到,尤其是小数值的自动装箱;而如果每次自动装箱都触发new,在堆中分配内存,就太耗时了;

其它几种基本类型包装类,也进行了缓存

Java 中常见的几个陷阱,你没有遇到几个?

Double 类型计算

Java 中常见的几个陷阱,你没有遇到几个?

Java中的double和float在内部表示为二进制分数,因此在表示十进制分数时可能不够精确(IEEE标准754)。十进制数计算需要精度,需要使用java.math.BigDecimal

总结

Java 中还有很多小陷阱,如果你有可以写出来吆。

原文  http://developer.51cto.com/art/201910/605162.htm
正文到此结束
Loading...