1-14 字符串、相等性规则、值传递与引用传递

1 相等性规则

== 比较运算符

  1. ==比较基本数据类型,判断的是值是否相等(基本数据类型只能用“==”比较)
  2. ==比较引用类型,判断的是内存地址是否相等

equals()方法

  1. Object类的equals()方法,比较的内存地址是否想等;
  2. String类的equals()方法,比较的是值是否相等;
  3. 按照自己的相等性规则进行比较,需要自定义equals方法;

2 String类型

String类型是一个引用类型,即栈中存放对象名和对象的引用,堆中存放String对象;

String类型的对象,底层实际是一个final修饰的char类型的数组。

2.1 创建String类型的对象

String a = "abc";

/*

这种创建方式,会把值存放到字符串常量池中

字符串常量池,可以理解为一个String的数据集,它是在堆内存中开辟的一块特殊内存

*/

String b = new String("abc");

/*

这种创建方式,就是创建一个String类型的对象,是在内存中新申请一块内存

*/

boolean tar = (a == b);//tar的值为false,因为==比较的是内存地址

2.2 常用方法

方法

返回值

作用

示例

equals()

boolean

比较字符串是否值相等

String a = “hi”;

String b = ”hello”;

boolean tar = a.equals(b);

length()

int

返回字符串的长度

int len = a.length();

trim()

String

去除字符串两端的空格

String b = a.trim();

replace()

String

替换字符串中的指定字符(串)

a.replace(s1,s2);

s1-被替换的字符串

s2-替换字符串

concat()

String

拼接字符串

a.concat(“123”);

toLowerCase()

String

字符串转小写

a.toLowerCase();

toUpperCase()

String

字符串转大写

a.toUpperCase();

split(",")

String[]

根据指定字符把字符串切分成数组,返回String[]

String a = “a,b,c”;

char[] arr = a.split(“,”);

contains()

boolean

判断字符串中是否包含指定字符

a.contains(“a”);

substring(1)

String

根据下标截取字符串,从指定下标到字符串末尾

substring(int startIndex);

String b = a.substring(1);

substring(1,2)

String

截取下标范围内的字符串,从开始下标到结束下标

substring(int s, int e);

s-开始下标

e-结束下标

indexOf()

int

获取指定字符在字符串中的下标

int index = a.indexOf(“a”);

charAt()

char

获取字符串中指定下标的字符

char c = a.charAt(1);

isEmpty()

boolean

判断字符串是否为空

boolean tar = a.isEmpty();

toCharArray()

char[]

将字符串转成字符数组

char[] d = a.toCharArray();

String.valueOf()

String

将变量转为String类型

int a = 1;

String b = null;

b = String.valueOf(a);

//14 String类的静态方法 format() 能用来创建可复用的格式化字符串

float f1 = 1.1f;

int i2 = 10;

String s3 = "hello";

String str = String.format("浮点型%f 整型%d 字符串%s", f1, i2, s3);

System.out.println(str); //打印:浮点型1.100000 整型10 字符串hello

3 字符串常量池

3.1 字符串常量池的设计思想

字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能

3.2 常量池工作原理

JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化

为字符串开辟一个字符串常量池,类似于缓存区

创建字符串常量时,首先检查字符串常量池是否存在该字符串

存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中

3.3 实现的基础

实现该优化的基础是因为字符串是不可变的(final),可以不用担心数据冲突进行共享

运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收

1-14 字符串、相等性规则、值传递与引用传递

 

4 StringBuffer与StringBuilder

String和StringBuffer、StringBuilder他们都可以存储和操作字符串,即包含多个字符的字符串数据。

String类是字符串常量,是不可更改的常量。而StringBuffer/StringBuilder是字符串变量,它的对象是可以扩充和修改的。

StringBuffer和StringBuilder的默认大小为16。

 1) StringBuffer和StringBuilder的默认容量长度为16。

 * 2) 如果在声明StringBuffer对象的同时,通过构造方法进行value[]初始化(即给变量赋值),

 * 则容量长度是是(value[]的长度+16)

 * 3) 如果调用append方法拼接字符串,字符串的长度超出了容量长度,则对容量长度进行扩容,扩容大小为(原长度<<1+2)

 *

特点:

  1. 修改String对象的值,内存地址会发生改变;
  2. StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的对象,即内存地址不变;
  3. StringBuffer是线程安全的,StringBuilder是线程不安全的;
  4. StringBuilder的执行速度比StringBuffer快;

常用方法:

方法

返回值

作用

示例

append()

StringBuffer

拼接字符串到末尾

StringBuffer a;

a.append("abc");

reverse()

StringBuffer

将字符串中的字符顺序反转

delete()

StringBuffer

删除字符串中指定下标范围的字符

a.delete(1,3);

insert()

在字符串指定下标位置插入字符

a.insert(1, "efd");

replace()

替换指定索引区间内的字符串

a.replace(1,3,"hul");

length()

int

字符串长度

a.length();

capacity()

int

容量长度

//初始化容量长度 x

StringBuffer s1 = new StringBuffer(3); s1.append("abc");

int y = s1.length();

int z = s1.capacity();

// x<y<2*x+2  z = 2*x+2

// y<x        z = x

// y>2*x+2    z = y

2 String, StringBuffer, StringBuilder的区别是什么?String为什么是不可变的?

1、String是字符串常量,StringBuffer和StringBuilder都是字符串变量。后两者的字符内容可变,而前者创建后内容不可变。
2、String不可变是因为String类被声明为一个final类。
3、StringBuffer是线程安全的,而StringBuilder是非线程安全的。

4、线程安全会带来额外的系统开销,所以StringBuilder的执行效率比StringBuffer高。

5 值传递与引用传递

5.1 值传递pass by value

  1. 基本数据数据类型遵循值传递;
  2. 将原来的值,复制一份,传给方法

5.2 引用传递pass by reference

  1. 引用类型遵循引用传递;
  2. 将原来的引用,复制一份,传给方法

注意:

String是一个final类,它的值不能被改变;

一旦给String对象,在方法中重新赋值,等于在内存中重新开辟一块内存,引用会发生改变;

String遵循引用传递,会将引用复制一份,传给方法,但是在方法中重新赋值,等于给复制的引用重新赋值一个新的内存地址;

所以将一个String变量传给方法,原来的值不会发生改变;

示例:

public class Test {

String name;

int age;

public void write() {

System.out.println("name:"+name+",age="+age);

}

public Test() {

name = "张三";

age = 20;

}

public static void update(int a, String b, Test c) {

a = 18;

b = "cba";

c.name = "李四";

}

public static void main(String[] args)  {

int a = 1;

String b = "abc";

Test c = new Test();

update(a, b, c);

System.out.println(a);//1

System.out.println(b);//abc

c.write();//name:李四,age=20

}

}

上一篇:BeanCreationException


下一篇:14 高可用的数据,那些进了大厂的程序员面试前都做了哪些准备