java中String

String

1 相等性规则

==比较运算符

1)== 比较基本数据类型,判断的是是否相等(基本数据类型只能用" == "比较

2)== 比较引用类型,判断的是 内存地址 是否相等

equals()方法 Object类中继承下来的

1)默认的equals方法与==一样,比较的是内存地址

2)按照自己的相等性规则进行比较,需要自定义equals方法(String类的equals方法比较的是值

String类型

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

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

String类也可以加final关键字修饰

2.1 创建String类型的对象

// 第一种  String类构造方法创建
/*
	这种创建方式,就是创建一个String类型的对象,是在内存中新申请一块内存
*/
String a = new String("abc");

// 第二种  字面值的方式创建
/*
	这种创建方式,会把值存放到字符串常量池中
	字符串常量池,可以理解为一个String的数据集,它是在堆内存中开辟的一块特殊内存
*/
String b = "abc";
String c = "abc";

boolean tar1 = (a == b);  // tar1的值为false,因为==比较的是内存地址
boolean tar2 = (b == c);  // tar2的值为true,因为第二种创建方式将值放入字符串常量池中,创建时会先去常量池中查看是否
                          // 已经存在,如果已经存在就会直接使用已存在的字符串值

2.2 常用方法

方法返回值作用示例
equals()boolean比较字符串是否值相等String a = “hi”;
String b = “hello”;
boolean tar = a.equals(b);
length()int返回字符串的长度int length = 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”;
String[] 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()
lastIndexOf()
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;
Sring b = null;
b = String.valueOf(a);

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 + private),可以不用担心数据冲突进行共享

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

4 StringBuffer与StringBuilder

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

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

特点:

1)修改String对象的值,内存地址会发生改变;

2)StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的对象,即内存地址不改变

3)StringBuffer 是线程安全的,StringBuilder 是线程不安全的;

4)StringBuilder 的执行速度比 StringBuffer 快;

5)常用方法:

方法返回值作用示例
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();
toString()转成String字符串a.toString();

5 关于字符串的补充

  1. +号拼接

    String s1 = "ab";
    String s2 = "cd";
    String s3 = s1 + s2;
    
    String s4 = s1 + "cd";
    
    String s5 = new String("ab") + new String("cd");
    String s6 = new String("ab") + "cd";
    
    // 拼接字符串时  程序是如何运行的?
    // 首先创建StringBuilder对象,然后调用append
    
    // 需要注意
    String s7 = "ab" + "cd";
    // s7创建的字符串对象在编译时就变成了"abcd"
    // 所以字符串常量池中只创建"abcd"的对象 不会分别创建"ab"和"cd"
    
  2. intern()方法
    因为不是所有的字符串创建方式都会在常量池中生成对应的字符串,而intern方法用于根据所给的字符串在常量池中创建对应的字符串。jdk1.7以后,调用intern方法时,如果该字符串已经存在于常量池中,则将常量池中的引用直接返回;如果不存在,则在常量池中生成一个对原字符串的引用

    String s1 = "abcd";
    String s2 = s1.intern();
    
    System.out.println(s1 == s2);
    // 结果为true 两者都指向常量池中的 abcd
    
    String s3 = new String("abcd");
    String s4 = s3.intern();
    System.out.println(s3 == s4);
    // 结果为false  s3指向堆  s4指向常量池中的
    
    String a1 = new String("abc");
    String a2 = a1 + "d";
    // a2.intern();
    String a3 = "abcd";
    System.out.println(a2 == a3); // false
    
    // 如果打开intern()方法的代码  就为true
    // 此时常量池中的"abcd"是个引用,指向a2的对象
    
    String str1 = new StringBuilder("计算机").append("软件").toString();
    String str2 = str1.intern();
    System.out.println(str1 == str2);  // true
    
    String str3 = new StringBuilder("ja").append("va").toString();
    String str4 = str1.intern();
    System.out.println(str3 == str4);  // false
    
    /*
    	注意:java是jvm一启动就默认放入常量池中的字符串
    */
    

​ 在jdk1.6中

​ intern方法会把首次遇到的字符串复制到方法区中,返回的也是方法区这个字符串的引用。

​ 而由StringBuilder创建的字符串实例在Java堆上,所以必然不是一个引用,所以返回false
在这里插入图片描述

​ str1指向堆,str2指向方法区,所以返回结果返回false。同理,str3和str4的返回结果也为false

​ jdk1.7+的intern方法不会再复制实例,只是在常量池中记录首次出现的实例引用。
在这里插入图片描述

​ 因此str2指向的引用其实就是str1指向Java堆中StringBuilder创建的字符串实例。所以返回结果为true

​ 但是java这个字符串常量在编译期就已经在方法区的常量池中了,不符合首次出现,所以str4指向的是常量池中的java字面量,所以 返回结果为false。

​ jdk9 String底层由char数组换成了 private final byte[] value;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值