final java string_java.lang.String 为什么是final 的?

java.lang.String 为什么是final 的?

之前只是模模糊糊的知道原因,今天在看另外一篇文章的时候,作者简单的说了下String类为什么是final的,但是他的理由说服不了我,这里我简单总结下为什么java.lang.String类是final的。

使用final生成不变类

String在Java中是和基本数据类型差不多的存在,类似所有的基本数据类型的包装类一样,他们都是final的,而基本数据类型作为不可变类是因为,int 3的包装类value就一定是3而不会是其他。

不变类在多线程中可以变量共享,不会存在多线程的线程安全的问题

很多情况下HashMap的key都是String,而key仅仅存的是引用,如果String是可变的,可能会导致key丢失。

String的intern的特性,也是String为final的重要一点,因为String需要缓存到常量池中,而如果String是可变的,这样会导致一个地方的引用调用改变了String对象,其他所有引用所指向的对象也跟着改变,这简直就是灾难。

将String声明为final,还有一个说法就是语义的问题,String类是final类,这意味着不允许任何人定义String的子类。换言之,如果有一个String的引用,它引用的一定是一个String对象,而不可能是其他类的对象。

说简单一点,就是为了性能和安全。

下面来简单的解释下可变类为什么最好不要做HashMap,HashSet的key

使用HashMap的时候我们应该都听过一句话:重载hashCode()方法的时候也要重载equals()

这是因为HashMap的key可能存在Hash碰撞,也就不同的key,hashcode可能相同,因此HashMap在获取某个key对应的value的时候,会先索引hashcode,然后再使用equals()验证是否是相等的对象。

if (first.hash == hash && // always check first node

((k = first.key) == key || (key != null && key.equals(k))))

return first;

JDK 1.8 hashMap#getNode()部分源码

假如我们定义了一个普通的pojo:Student

@Getter

@Setter

@EqualsAndHashCode

@AllArgsConstructor

@ToString

public class Student {

private String name;

private String sex;

}

然后通过业务系统将其放入了一个全局的HashMap

Student stuDcc=new Student("dcc","男");

map.put(stuDcc);

而在后来,因为其他的一些业务逻辑,我们修改了stuDcc的name

stuDcc.setName("dcc2");

就这样,这stuDcc所对应的value永远都获取不到了,除非stuDcc对象再将name修改为dcc.

map.get(new Student("dcc","男")); //null

map.get(stuDcc); //null

为什么呢?

因为现在的HashMap中StuDcc对象的hashCode是通过name=dcc ,sex=男来计算获得的,而equals需要是name=dcc2,sex=男。

因为HashMap判断一个对象需要同时HashCode和Equals,但是hashCode的获取是在存入对象的时候就固定了,而equals是判断的对象目前的值,因此stuDcc对象在修改了name以后,其他任何一个对象都无法同时拥有stuDcc存入map的时候的hashCode以及stuDcc修改值的相同的值。

也就是下面的代码:

map.get(new Student("dcc","男")); //null hashCode() 匹配成功但是equals失败

map.get(stuDcc); //null equals()成功 但是hashCode匹配不到

因此,最好使用不可变类做Key

参考链接:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值