String是个啥?

  字符串?不可变字符串?今天想起来这个又意思的东西,所以来记录一下。我们说String是不可变字符串,那他就真的不可变吗?

public class StringDemo {
public static void main(String[] args) {
String s = " a b ";
s.trim();
System.out.println("-" + s + "-");
}
} 输出:- a b -
空格没有被删除
public class StringDemo {
public static void main(String[] args) {
String s = " a b ";
s = s.trim();
System.out.println("-" + s + "-");
}
} 输出:-a b-
空格被删除
public class StringDemo {
public static void main(String[] args) {
String s = " a b ";
String ss = s.trim();
System.out.println("-" + ss + "-");
}
} 输出:-a b-
空格被删除
public class StringDemo {
public static void main(String[] args) {
String s = " a b ";
String ss = s.trim();
System.out.println("-" + s + "-");
}
} 输出:- a b -
空格没有被删除

  我蒙蔽了,来理一理,先看一看String的源码:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[]; private int hash; private static final long serialVersionUID=-6849794470754667710L;
......
public String trim() {
int len = value.length;
int st = 0;
char[] val = value; /* avoid getfield opcode */ while ((st < len) && (val[st] <= ' ')) {
st++;
}
while ((st < len) && (val[len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}

 String类为什么被称为不可变字符串呢?是因为类上面加了final还是value[]数组上面加了final呢?还是因为String类没有提供可变的方法呢?我们不妨利用反射拿到这个value数组试一试。

public class StringDemo {
public static void main(String[] args) throws Exception {
String s = " a b ";
Class clazz = s.getClass();
Field f = clazz.getDeclaredField("value");
f.setAccessible(true);
char[] cs = (char[])f.get(s);
cs[1] = 'A';
System.out.println(s);
}
}
输出: A b 

  这说明它是可变的啊,final只不过是约束了变量所指向的地址不能变,并不是说地址段的内容不能变,也就说,虽然value数组使用final修饰,但这只是定义了我value变量指向的地址不能变,但是地址段本身的内容(数组的内容)是可变的。

  String 是final类,也就是说,一旦定义了String类型的变量,那么变量本身所指向的地址就不能变了。但是String变量指向的地址的内容可变吗?这你就得注意点了,String类型变量和普通类型变量以及引用类型变量都有区别,虽然String类型变量是引用类型,但他还有另一个身份,String类型的变量还是个常量!既然是常量,那JVM就会把它区别对待,把它保存在方法区的常量池中。

  当s.trim()时,trim()方法入栈,在本方法的栈针中,定义了一个新的char类型数组val,并指向保存原字符串信息的char数组value,但由于数组是基本类型的,所以并没有传引用,而是直接把数组的内容复制给了新的数组val,经过循环操作完成方法后返回一个字符串,但是这个字符串是个常量,JVM如果发现这个常量在常量池中不存在,就会把他保存在常量池中,注意了:这个新的字符串常量和原字符串常量在不同的内存块。但是由于s是final修饰的,所以s并不能改变地址指向新的字符串常量,所以s的输出的值不变,与s不同的是,String ss = s.trim()刚好站了出来,说:我来指向它!于是,ss的输出的值就成了新的字符串常量。如果没有ss指向那个新的常量,那他就可能过会儿被GC了。

String是个啥?的更多相关文章

  1. 透过WinDBG的视角看String

    摘要 : 最近在博客园里面看到有人在讨论 C# String的一些特性. 大部分情况下是从CODING的角度来讨论String. 本人觉得非常好奇, 在运行时态, String是如何与这些特性联系上的 ...

  2. JavaScript String对象

    本编主要介绍String 字符串对象. 目录 1. 介绍:阐述 String 对象的说明以及定义方式. 2. 实例属性:介绍 String 对象的实例属性: length. 3. 实例方法:介绍 St ...

  3. ElasticSearch 5学习(9)——映射和分析(string类型废弃)

    在ElasticSearch中,存入文档的内容类似于传统数据每个字段一样,都会有一个指定的属性,为了能够把日期字段处理成日期,把数字字段处理成数字,把字符串字段处理成字符串值,Elasticsearc ...

  4. [C#] string 与 String,大 S 与小 S 之间没有什么不可言说的秘密

    string 与 String,大 S 与小 S 之间没有什么不可言说的秘密 目录 小写 string 与大写 String 声明与初始化 string string 的不可变性 正则 string ...

  5. js报错: Uncaught RangeError: Invalid string length

    在ajax请求后得到的json数据,遍历的时候chrome控制台报这个错误:Uncaught RangeError: Invalid string length,在stackoverflow查找答案时 ...

  6. c# 字符串连接使用“+”和string.format格式化两种方式

    参考文章:http://www.liangshunet.com/ca/201303/218815742.htm 字符串之间的连接常用的两种是:“+”连接.string.format格式化连接.Stri ...

  7. 【手记】注意BinaryWriter写string的小坑——会在string前加上长度前缀length-prefixed

    之前以为BinaryWriter写string会严格按构造时指定的编码(不指定则是无BOM的UTF8)写入string的二进制,如下面的代码: //将字符串"a"写入流,再拿到流的 ...

  8. JavaScript中String对象的方法介绍

    1.字符方法 1.1 charAt() 方法,返回字符串中指定位置的字符. var question = "Do you like JavaScript?"; alert(ques ...

  9. 在多线程编程中lock(string){...}隐藏的机关

    常见误用场景:在订单支付环节中,为了防止用户不小心多次点击支付按钮而导致的订单重复支付问题,我们用 lock(订单号) 来保证对该订单的操作同时只允许一个线程执行. 这样的想法很好,至少比 lock( ...

  10. BCL中String.Join的实现

    在开发中,有时候会遇到需要把一个List对象中的某个字段用一个分隔符拼成一个字符串的情况.比如在SQL语句的in条件中,我们通常需要把List<int>这样的对象转换为“1,2,3”这样的 ...

随机推荐

  1. Linux系统启动过程浅析

    经过老师的讲解以及查阅资料后,现对Linux系统启动做以浅析,仅是个人理解. 主要的步骤有以下几步: 第一步:Power On.用户按下电源开关的那一瞬间,叫Power On阶段 .在这个阶段,BIO ...

  2. Java版基于SpringBoot+Vue.js实现自动创表自动定时采集(各个微信公众号商城产品进行采集)-爬虫篇

  3. nodejs http服务器简单搭建

    var http = require('http') // 1. 创建 Server var server = http.createServer() // 2. 监听 request 请求事件,设置 ...

  4. docker安装es

    下载镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:6.8.1 创建容器并映射docker run -e ES_JAVA_OP ...

  5. 如何从mysql备份中提取单张表数据

    1.先提取备份数据中的前50行出来,查看一下备份数据格式    head -50 bakdb.sql > head50.txt        类似下面的数据是我们所需要提取的:        / ...

  6. 调整notepad++的行距的方法

    notepad++是一款免费开源的文本编辑器,在windows平台上表现非常好,可以自定义的地方多,还支持主题导入,导出和切换,对各种语言的语法高亮支持也是在各大文本编辑器中名列前茅,插件库的内容也非 ...

  7. [python 学习] argparse模块

    https://docs.python.org/3/library/argparse.html#module-argparse

  8. php io

    1.获取目录下文件,不包括子目录 //获取某目录下所有文件.目录名(不包括子目录下文件.目录名) $handler = opendir($dir); while (($filename = readd ...

  9. CSS中用 opacity、visibility、display 属性将 元素隐藏 的 对比分析

    说明 opacity 用来设置透明度 display 定义建立布局时元素生成的显示框类型 visibility 用来设置元素是否可见. opacity.visibility.display 这三个属性 ...

  10. python 日期封装

    import time import datetime import locale class TimeUtil: def __init__(self, curtime=None): self.cur ...