String的那些事
String的特点?
通过查看String类的源码我们得知:String类被final关键字修饰,这即是说明String类的特点就是:字符串对象一旦被初始化就不会被改变。注意:此处是字符串对象而不是字符串引用。也即是说:
String s = "abc"; // s引用变量指向了值为"abc"的对象
s = "cba"; // s引用变量又指向了值为"cba"的对象,但是上面值为"abc"的对象的值并未改变
我们需要注意所有对String的操作(包括增删改等)都是新建对象(参考String类的源码)。那么String类被final修饰有什么好处呢?第一个好处是安全,因为final保证不管怎样操作,它的值都是不变的;第二个好处就是高效,因为只有String类是不可变类时,我们才能实现字符串常量池。试想如果String类是可变类,当多个字符串引用变量指向同一个字符串对象时,字符串对象改变后就会引起多个字符串引用变量内容的改变,这显然不符合我们的预期。我们可以通过下面的代码来验证字符串常量池的存在:
class Demo {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
Demo d1 = new Demo();
Demo d2 = new Demo();
System.out.println(s1 == s2); // 1
System.out.println(d1 == d2);
}
}
我们知道:如果是两个引用变量使用"=="进行比较,那么比较的是两个对象的地址值,1处的代码输出结果为"true",说明s1引用变量和s2引用变量指向的是同一个对象,也就验证了字符串常量池的存在。字符串常量池其实就是字符串的一个缓冲区,而"缓存"可以提高系统性能,那么即是说字符串常量池的使用可以提高系统性能。常量池的特点就在于:如果池中没有则创建,如果池中有就直接使用池中的。
String内部实际存储结构为char数组。下面为jdk1.8版本的String源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
// 用于存储字符串的值
private final char value[];
// 用于缓存字符串的hashcode
private int hash; // Default to 0
// else code
// ... ...
}
我们需要注意编译器会对String做一些优化,比如下列代码:
class Demo {
public static void main(String[] args) {
String s1 ="Ja"+"va";
String s2 = "Java";
System.out.println(s1 == s2);
}
}
String的构造方法?
String是一个类,所以我们除了使用String s1 = "abc"方式创建字符串对象之外,还可以通过String类的构造方法进行创建。通过查看jdk文档我们发现String类
有下面这样的构造函数:

我们需要注意这两种创建方式的区别:
class Demo {
public static void main(String[] args) {
String s1 = newString("Java"); // 1
String s2 = s1.intern(); // 2
String s3 = "Java"; // 3
System.out.println(s1 == s2);
System.out.println(s2 == s3);
}
}
1处代码的含义是:在堆内存中使用new的方式创建了一个字符串对象并把地址值赋给了引用变量s1,并且该对象在创建的时候接收了一个字符串对象;而2处代码的含义是:在堆内存中创建一个变量s2,如果调用intern()才会把此字符串保存到字符串常量池中;3处代码的含义是:在字符串常量池中创建了一个值为"Java"的字符串对象,并把该对象的地址值赋给了引用变量s3;所以3处的代码最终只涉及到一个对象,而1处的代码有可能涉及一个(字符串常量池中有字符串对象"Java")也有可能涉及两个(字符串常量池中没有字符串对象"Java")。这三个引用变量在JVM中存储的位置如下:

注意:在JDK6.0及之前版本,字符串常量池是放在方法区中,而在JDK7.0版本,字符串常量池被移到了堆中。
我们可以看到引用变量s1和引用变量s2的内容其实是相等的,都是"Java",于是如果我们只想比较两者的内容时,就可以使用equals()。
class Demo {
public static void main(String[] args) {
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
}
}
这里需要注意,Object类中equals()的源码是下面这样的:
public boolean equals(Object obj) {
return (this == obj); // 比较的还是对象的地址值
}
而String类对该方法进行了覆盖,源码是这样的:
public boolean equals(Object anObject) {
// 对象引用相同直接返回 true
if (this == anObject) {
return true;
}
// 判断需要对比的值是否为String类型,如果不是则直接返回false
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
// 把两个字符串都转换为 char 数组对比
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
// 循环比对两个字符串的每一个字符
while (n-- != 0) {
// 如果其中有一个字符不相等就 true false,否则继续对比
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
String类有几个很常用的构造方法,如下:
// char[]为参数的构造方法
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
// byte[]为参数的构造方法
public String(byte bytes[]) {
this(bytes, 0, bytes.length);
}
// string为参数的构造方法
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
// StringBuffer为参数的构造方法
public String(StringBuffer buffer) {
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
// StringBuilder为参数的构造方法
public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}
String的常用方法?
通过查看jdk文档,我们可以看到String类有很多方法,将其中常用的方法分为下面几类:
- 用于获取:
1.1 获取字符串中字符的个数(长度):
int length();
1.2 根据位置获取字符:
char charAt(int index);
1.3 根据字符获取在字符串中的第一次出现的位置:
int indexOf(); // 注意此方法的有多种重载形式
- 用于转换
1.1 将字符串变成字符串数组(字符串的切割):
String[] split(String regex); // 注意此方法涉及到正则表达式
1.2 将字符串中的字母转成大小写:
String toUpperCase():大写
String toLowerCase():小写
1.3 将字符串中的内容进行替换:
String replace();
1.4 将字符串两端的空格去除:
String trim();
- 用于判断
1.1 判断字符串中是否包含指定字符串:
boolean contains(string str);
- 用于比较
1.1 比较两个字符串:
int compareTo(String anotherString)
// 下面为compareTo方法的源码
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
// 对比每一个字符
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
// 如果字符不相等就返回差值
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
可以看出compareTo()和equals()都是用于比较两个字符串的,并且当equals()返回true或者是compareTo()返回0时,则表示两个字符串完全相同。这两个方法的区别在于:compareTo()接收的是String类型的参数,而equals()可以接收一个Object类型的参数;compareTo()的返回值为int,而equals()返回值为Boolean。
String的那些事的更多相关文章
- C#与Java对比学习:类型判断、类与接口继承、代码规范与编码习惯、常量定义
类型判断符号: C#:object a; if(a is int) { } 用 is 符号判断 Java:object a; if(a instanceof Integer) { } 用 inst ...
- 记一次 .NET 某医院HIS系统 CPU爆高分析
一:背景 1. 讲故事 前几天有位朋友加 wx 抱怨他的程序在高峰期总是莫名其妙的cpu爆高,求助如何分析? 和这位朋友沟通下来,据说这问题困扰了他们几年,还请了微软的工程师过来解决,无疾而终,应该还 ...
- TypeScript学习文档-基础篇(完结)
目录 TypeScript学习第一章:TypeScript初识 1.1 TypeScript学习初见 1.2 TypeScript介绍 1.3 JS .TS 和 ES之间的关系 1.4 TS的竞争者有 ...
- string.Format之你不知道的事
1.格式化货币(跟系统的环境有关,中文系统默认格式化人民币,英文系统格式化美元) string.Format("{0:C}",0.2) 结果为:¥0.20 (英文操作系统结果:$0 ...
- java——String的那边破事
经典的先看下面一段代码,请问最终创建几个对象,分别在哪里? String s0 = new String("luoliang.me"); String s1 = "luo ...
- String不得不说的那些事
一.String.StringBuilder和StringBuffer的区别 1. String是字符串常量,StringBuilder和StringBuffer是字符串变量 String对象创建完成 ...
- 【C#】CLR内存那点事(string)
string是比特殊的类,说引用类型,但不存在堆里面,而且String str=new String("HelloWorld")这样的重装也说没有的. 我们先来看一个方法 clas ...
- string那些事之replace
/* 用法一: 用str替换指定字符串从起始位置pos开始 长度为为len的字符串 string &replace(size_t pos, size_t len, const string&a ...
- 谁还不知道Java String的那点事
String是我们平时接触最多的一种数据类型之一,不同语言有自己内部的实现,今日一起看下Java中String的内部实现. 常问问题 面试中常被提及的String问题 String为什么是Final的 ...
随机推荐
- deeplearning.ai 序列模型 Week 1 RNN(Recurrent Neural Network)
1. Notations 循环序列模型的输入和输出都是时间序列.$x^{(i)<t>}$表示第$i$个输入样本的第$t$个元素,$T_x^{(i)}$表示输入的第$i$个样本的元素个数:$ ...
- mysqli存储过程
<?php$link = mysqli_connect('localhost','root','','chinatupai'); $sql = "call getEmail('000 ...
- git 忽略规则
# 以'#'开始的行,被视为注释. # 忽略掉所有文件名是 foo.txt的文件. foo.txt # 忽略所有生成的 html文件, *.html # foo.html是手工维护的,所以例外. !f ...
- CF-1066B-Heaters
这题就是从1到n点进行遍历,对未加热的点找到最远的能加热到这个点的点,还是看代码讲吧 #include"bits/stdc++.h" using namespace std; co ...
- python 前端素材提供
小图标素材:http://fontawesome.dashgame.com/
- JXJJOI2018_T2_tank
题目描述 Lemon最近迷上了一款坦克对战游戏.在这款游戏中,Lemon需要驾驶一辆坦克与敌军对战. 坦克有很多不同的武器,每种武器有各自的特点,而Lemon所要做的就是合适地发射这些武器,对敌军造成 ...
- 维生素D补充过多会中毒
虽然我们的物质生活越来越丰富,各种食材几乎一年四季都能够吃到,然而却越来越多的人选择进行补充各种维生素,但是你知道吗?维生素不是我们想象中多吃无害的,补充过多也会要人命,特别是最近非常流行补充的一种维 ...
- AI能帮我们造出一个无肉的世界吗?
AI听起来很遥远,其实已经渗透到我们的日常工作和生活中.在不远的未来,互联网.大数据.硬件的发展和软件的优化,乃至全社会的参与,人工智能将真正从实验室走进生活,它将成为改变我们生活的一部分.我们吃的肉 ...
- 《自动化平台测试开发-Python测试开发实战》第2次印刷
书籍货源比较紧张.紧张啊,如此短的时间,已经第2次印刷.第2次印刷. 第2次印刷. 同时该书已确认与台湾出版社合作翻译成繁体版,甚至有可能与国外出版社合作翻译成英文版. 2018年7月 第1次印刷 2 ...
- ubuntu 代理设置
在学习工作中使用vagrant作为开发环境已经有很长一段时间了,使用ubuntu 作为开发系统 在使用中发现,即使修改了apt的source.list源文件,在面对一些开发中需要的软件工具的时候,不可 ...