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. express 获取post 请求参数

    在 Express 中没有内置获取表单 POST 请求体的 API , 我们需要添加第三方插件库 安装: npm install --save body-parser 配置: var bodyPars ...

  2. 初学Java 二维数组找出最近的两个点

    import java.util.Scanner; public class FindNearestPoints { public static void main(String[] args) { ...

  3. leetcode x进制数 python3

    不少题目都是实现吧10进制数转换成x进制数,实际上都是一个套路,下面是7进制的,想换成什么进制,把7替换成相应数字即可,输出的是字符串 16,32进制这种有特殊要求的转不了,其他的应该通用 class ...

  4. gbase整合mybatis出现: Cause: java.sql.SQLException: Can't convert to: binary stream

    参考地址:http://mybatis-user.963551.n3.nabble.com/Map-SQL-Type-LVARCHAR-x-to-JDBC-Type-VARCHAR-globally- ...

  5. git 日常 常用命令

    初始化git git init 第一次拉代码: 方式1:git clone git clone https://git.oschina.net/*****.git (https远程仓库地址) 方式2: ...

  6. [php代码审计] php四种标记

    php手册中的介绍: 可以在 PHP 中使用四对不同的开始和结束标记.其中两种,<?php ?> 和 <script language="php"> < ...

  7. django之创建子应用

    一:子应用 Django的视图编写是放在子应用中的.类似于flask中的视图. 二:创建子应用 例如:在刚才的dj_study项目中,创建一个名字为user的子应用(目录):注意是第一级的dj_stu ...

  8. JIRA之两大统计图讲解

    一.创建与解决的问题-状态统计图 配置方式 理解该统计图 横坐标 x:时间 纵坐标 y:issue数量 统计图示解读: A.随着时间的推移,创建的问题数(红线)减少,修复问题数(绿线)增加,标志着版本 ...

  9. go mac 交叉编译 linux

    CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w' -o server ./server.go

  10. 2A3T我的PMP备考及考试心得20181208

    2018年的下半年由于工作不是很忙,所以生活中有更好的精力去做些自己的事情.出于工作需要,我决定考个证书充实下自己,在各大网站搜索解惑后决定考PMP,并报了个培训班 一.PMP考试简介 共200道选择 ...