java 关于String的一些问题

最近一直在忙毕业的东西,偷懒没有更新博客。趁着最近闲下来了,动手试验一下之前看到的关于String的一些问题。

 

一、String类能被继承吗,为什么?

很遗憾这是不行的。String类被final修饰,被final修饰的类无法被继承。

1

顺带一提,final可以修饰变量、方法和类,意味着“最终结果”,不希望别人搞事,不需要做出改变。

二、为什么对于安全敏感的信息使用Char[]会比String对象更好?

网上普遍流传着这样一个回答:

“字符串是不变的,这也就意味着字符串一旦被创建,它们将一直保持在那,直到被垃圾回收器清理为止。而对于一个数组,你可以明确的修改它的元素。这样一来,安全性敏感信息(比如密码)将不会出现在系统的任何其它地方。”

不知道是我理解能力太差还是怎么回事,我完全没有搞明白这句话是什么意思。直到找到了这样一篇文章,才如醍醐灌顶:

http://blog.csdn.net/reliveIT/article/details/47450531

我大致总结一下这篇文章的解释:

在执行完密码的代码逻辑后,密码就失去了作用。为了防止密码继续停留在内存中,需要对密码进行清理操作,将其立刻置为空:

这两者有什么区别呢?

password[i] = 0x00的时候,操作的是同一片内存,可以这么粗略的理解,如果原来的password[i] = 0x01,那么归零后password[i] = 0x00,相当于password的字符数组中的数据被抹除了,dump内存下来只能看到归零后的值。

但是,对于String password = “xx”或者String password = new String(“xx”);而言,password = null并不会清除内存中的password,原始的密码还留在内存中。

这是为什么呢?

String类在字节码中有一个私有化的字节码常量池String pool,是存储String对象的定长HashTable。String password = “xx”,这句代码在编译的时候会创建一个String对象并存放在字符串常量池中;String password = new String(“xx”),这句代码则会先在常量池中查找,看是否能找到”xx”.equals(池对象),如果找到则传入String类的构造方法,如果找不到则会创建一个String对象然后再进入String构造方法。

这也就意味着,无论是哪一种方式,都会在常量池中存在一个String对象”xx”,因此无论最终password = null或任何其他值,对于”xx”对象而言,依旧还在内存中的,因此对于password这种安全敏感的数据来说,dump内存是可以看到的。

这就是为什么对于安全敏感的信息使用Char[]会比String对象更好。

三、如何比较两个字符串?用“=”还是“equals”?

其实要看你的目的是什么。如果你要比较两个字符串的引用是不是都指向内存中的同一个对象,那么就用“=”。如果只是单纯的比较两个字符串的值是否相等,那么就用equals。

这里有个小例子:

我的个人理解:前三条输出都是true,说明如果声明的是同样的字符串,那么句柄会优先指向常量池中的同一对象。第四条输出为false,说明如果强行使用new关键字新建一个String对象,那么这个String对象肯定处于常量池中不同的位置,“==”肯定会返回false。

四、如何根据空格去分隔字符串?

可以使用split方法,通过正则的方式去分隔。

结果为:

五、String和StringBuilder和StringBuffer

这个问题是在知乎上看到的,以后另外开一篇文章来分析一下。

六、如何快速重复构造一段字符串

一般人都是这样想的:

也可以使用apache.commons.lang包中StringUtils类的repeat方法。

七、如何计算一个字符在某个字符串中出现的次数

一般人是这样想的:

也可以使用apache.commons.lang包中StringUtils类的countMatches方法。

八、如何“填满”一个String

要区分是“向左填满”还是“向右填满”。

可以使用apache.commons.lang包中StringUtils类的leftPad方法

大概意思是构造一个11位的String,前面不足的位置使用“X”来填满。

九、总结

基本上是一些编码时的技巧。要理解第二点和学会使用apache.commons.lang包。

发表评论

电子邮件地址不会被公开。 必填项已用*标注