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. Intel MKL函数之 cblas_sgemm、cblas_sgemm_batch

    cblas_sgemm int m = 40; int k = 20; int n = 40; std::vector<float> a(m*k, 1.0); std::vector< ...

  2. C++中的const_cast

    开发环境 Qt Creator 4.8.2 编译器版本 MinGw 32-bit const_cast 用法: const_cast<type_id> (expression) 说明: 该 ...

  3. django之类视图

    一:类视图 1. 为什么使用类视图? # 以注册请求逻辑为例 def register(request): if request.method == "GET": render(r ...

  4. Tomcat的作用思考及NIO在Tomcat中的应用模型

    Tomcat的作用 平时写完web程序都是直接点击启动,就可以在本机浏览器访问了.但是仔细想想,我们似乎都没有写过浏览器与servlet通信的代码,也没有写过创建request.reponse的代码. ...

  5. js reduce用法

    let books = [ 0, {bookName:"python",price:10,count:1}, {bookName:"Ruby",count:2, ...

  6. 关于scikit-learn

    机器学习scikit-learn scikit-learn官网学习资料非常丰富,完全可以自学: http://scikit-learn.org/ 目前就以scikit-learn为主要工具学习mach ...

  7. 对排序(Sort)的研究

    这一篇主要是介绍一些数据排序的基本算法和高级算法并利用JavaScript来逐一实现, 算法的说明: 稳定:如果a原本在b前面,当a=b时,排序之后a仍然在b的前面 不稳定:如果a原本在b的前面,当a ...

  8. 阿里云推出SRT+杜比全景声直播方案,低成本打造高质量直播观感体验

    超过200个国家和地区共5144万人观看:浙江卫视.东方卫视55城总收视达2.39,稳居同时段市场第一:优酷直播间63%观看晚会的用户参与了互动:微博68.2亿的主话题阅读量:2019天猫双11狂欢夜 ...

  9. php array_key_exists()函数 语法

    php array_key_exists()函数 语法 作用:检查某个数组中是否存在指定的键名.大理石平板价格 语法:array_key_exists(key,array) 参数: 参数 描述 key ...

  10. JS自定义随机数字键盘

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...