前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java 使用 char[] Array 还是 String 存储字符串

Java 使用 char[] Array 还是 String 存储字符串

原创
作者头像
HoneyMoose
发布2022-06-20 23:09:47
9680
发布2022-06-20 23:09:47
举报
文章被收录于专栏:CWIKIUSCWIKIUS

概述

在本文章中,我们主要用来说明为什么应该使用 char[] 数组来存储密码,而不是使用 String 来存储密码。

需要注意的是,为了密码的安全,我们通常都会将用户输入的密码 MD5 加密哈希后进行存储。

我们通常是不会在后台中存储明文的用户密码的,这篇文章主要目的就是为了说明字符串在 Java 中的存储方式和在存储中的实现,就算你应该使用 char[] 数组来存储,你也不应该在程序中使用明文。

同时,本文章还假设你没有办法对 String 字符串进行控制。例如你获得密码是从某些第三方工具上面获得的,或者第三方 API 传递过来的,通常你是没有办法对上面的字符串进行控制的。

因此,你还不得不使用 java.lang.String 对象来对密码进行实现,经过 Java 的官方小组还是推荐使用 char[] 数组来实现。

你可以通过单击 JPasswordField 这个链接来查看 JPasswordField API 的使用,这个 API 是存在 javax.swing 包中的。

我们可以知道 getText() 这个返回 String 的方法从 Java 2 开始就被丢弃了,你应该使用 getPassword() 来返回密码,这个方法实际上是返回的 char[] 字符串。

java-password-01
java-password-01

下面来让我们看看为什么应该使用 char[] 数组来存储密码了。

Strings 是不可变的(Immutable)

String 在 Java 中是不可变的。这个不可变的意思是,String 是不能被更高一级的 API 进行操作的。

任何对 String 对象的修改都会创建一个新的 String 对象,同时将老的 String 对象保存在内存中。

上面这句话的意思就是:如果密码(Password)使用 String 来进行存储的话,如果你对密码进行操作后,老的密码还是在内存中存在的,知道 Java 的垃圾回收程序来清理掉。

这个垃圾回收的过程,我们是没有办法进行控制的,我们也不知道 JVM 什么时候执行垃圾清理。这个清理的过程与其他对象的清理对比来说,可能需要等待比较长的时间。这是因为 String 在 JVM 中是存储在 String Pool 中的,这个主要是为了便于对 String 的再次利用。

因为有这个缓存的存在,所以 String 在内存中保留的时间会比较长。

在这个过程中,任何人如果对 JVM 进行 Dump 内存操作的话,任何人都可以从内存中获得密码的明文。

如果我们使用 char[] 数组来存储密码的话,我们可以在对密码的计算完成后来使用程序对数组进行清理。因此,我们可以保证我们使用过的密码从内存中完全清楚,而不是等候 JVM 垃圾清理程序来进行清理。

下面我们来看代码来对上面的用例进行说明:

String 测试

代码语言:javascript
复制
    @Test
    public void immutableForString() {
        String stringPassword = "password";
        System.out.print("Original String password value: ");
        System.out.println(stringPassword);
        System.out.println("Original String password hashCode: " + Integer.toHexString(stringPassword.hashCode()));

        String newString = "********";
        stringPassword.replace(stringPassword, newString);

        System.out.print("String password value after trying to replace it: ");
        System.out.println(stringPassword);
        System.out.println("hashCode after trying to replace the original String: " + Integer.toHexString(stringPassword.hashCode()));
    }

上面程序将会有如下输出:

代码语言:javascript
复制
Original String password value: password
Original String password hashCode: 4889ba9b
String password value after trying to replace it: password
hashCode after trying to replace the original String: 4889ba9b

char 数组测试

代码语言:javascript
复制
    @Test
    public void immutableForCharArray() {
        char[] charPassword = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};

        System.out.print("Original char password value: ");
        System.out.println(charPassword);
        System.out.println("Original char password hashCode: " + Integer.toHexString(charPassword.hashCode()));

        Arrays.fill(charPassword, '*');

        System.out.print("Changed char password value: ");
        System.out.println(charPassword);
        System.out.println("Changed char password hashCode: " + Integer.toHexString(charPassword.hashCode()));
    }

针对数组的测试输出如下:

代码语言:javascript
复制
Original char password value: password
Original char password hashCode: 10d59286
Changed char password value: ********
Changed char password hashCode: 10d59286
java_string_array
java_string_array

正如我们所看到的那样,当我们对 String 进行了操作后,操作后的结果是不会改变原始输入 String 的结果的。

我们可以看到上面的代码,hashCode() 方法返回的结果是一样的,并没有给我们有不同的结果,同时 String 中的值也保持一致。

使用 char[] 数组的时候,我们注意到,hashCode() 的值是一样的,但是内容却不一样了。这是因为我们对 char[] 进行了操作所导致的,我们可以对相同的对象中的数据进行修改。

需要注意 stringPassword.replace(stringPassword, newString); 方法,如果你需要获得这个方法替换后的值得话,你需要将方法执行后的值重新赋值才可以。

避免意外打印密码

使用 char[] 数组来存储密码的好处就是能够避免意外的将内存中存储的密码数据输出到控制台,显示器或者其他并不安全的地方。

让我们来考察下面的代码:

代码语言:javascript
复制
    @Test
    public void accidentallyPassword_print() {
        String passwordString = "password";
        char[] passwordArray = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
        System.out.println("Printing String password -> " + passwordString);
        System.out.println("Printing char[] password -> " + passwordArray);
    }

上面的代码将会输出为:

代码语言:javascript
复制
Printing String password -> password
Printing char[] password -> [C@2698dc7

我们可以从上面的输出了解到,String 的输出是完整的内容输出,char[] 的输出不是将 char[] 中的内容输出,这样的方式让输出更不容易泄密。

这是因为在 Char 数组打印的时候调用的是一个 toString 的方法,这个方法输出的是类的值和类的哈希代码(hashCode)转换成 16 进制。

这就是你看到这一串奇怪字符串的原因。

结论

在这篇文章中,我们对为什么应该使用 char 数组而不是使用 String 来存储密码或者敏感字符串的原因进行了说明。

同时通过举例来说明了一些相关问题和结构。

https://www.ossez.com/t/java-char-array-string/14015

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • Strings 是不可变的(Immutable)
    • String 测试
      • char 数组测试
      • 避免意外打印密码
      • 结论
      相关产品与服务
      对象存储
      对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档