String


String是最常操作的引用类型了,但也是我最怕的地方(因为不熟悉),最怕还是String和Array同时出现,所以现在先写下一篇博客熟悉熟悉字符串

0. 字符串非空

if( str == null || str.length() == 0){
    System.out.println("11");
}

1.字符串的不可变性

我们常说String是不可变的,但的对应的变量为什么还是能"改"为不同的字符串呢?

来看一下String的部分源码

  • 在114行可以看出,String内部使用数组来存储,使用了private与final修饰,且内部没有修改value数组的方法,所以一旦定义就不能修改,即String的不可变性

不可变性的好处

  • 不可变才有字符串常量池,优化空间
  • 存储hashCode的,因为经常使用
  • 线程安全,因为不可变

2. 但为什么我们的变量还是能改为不同的字符串呢?

String a = new String("String不可变性");
a = new String("String确定不可变吗?");
System.out.println(a);

//输出
//String确定不可变吗?
  • 其实字符串都没有变,变的是a的引用地址,这样看起来貌似字符串改变了罢了

3. String Pool

创建字符串会放到字符串常量池中,下次创建相同的字符串会从常量池中拿取引用,所以相同字符串引用相同

String a = "String不可变性";    //字面量
String b = "String不可变性";
System.out.println(a == b);

//输出
//true

//但new关键字是在堆中复制一个副本,引用地址给了变量,所以指向的对象的地址不同
String a1 = new String("String不可变性");   //对象
String b1 = new String("String不可变性");
System.out.println(a1 == b1);

//输出
//false

对JVM不熟悉的同学可以看我另一篇 学不会的JVM

4. 连接符 “+”

//字符串常量,JVM会优化,在字符串常量池直接存放“123”
String a = "1" + "2" + "3";

//字符串变量,会在底层创建StringBuilder,然后append,最后toString返回
String a = new String("1") + new String("2");

5. 构造方法及常用方法

构造函数

解释

String(byte[] bytes, String charsetName)

构造一个新的String用指定的字节数组和解码

String(String original)

初始化新创建的String对象,新创建的字符串是参数字符串的副本

String(StringBuffer buffer)

其中包含当前包含在字符串缓冲区参数中的字符序列

String(StringBuilder builder)

其中包含当前包含在字符串构建器参数中的字符序列

返回值

方法名

解释

char

charAt(int index)

返回指定索引处的字符

int

compareTo(String anotherString)

按字典顺序比较两个字符串

int

compareToIgnoreCase(String str)

按字典顺序比较两个字符串,忽略大小写

String

concat(String str)

将指定的字符串连接到该字符串的末尾

boolean

contains(Strin str)

判断字符串中是否有指定的子字符串

boolean

equals(Object anObject)

判断值是否相同

byte[]

getBytes(String charsetName)

使用命名的字符集将此String编码为字节序列

int

length()

返回此字符串的长度

int

indexOf(int ch,int fromIndex)

返回指定字符第一次出现的字符串内的索引,从指定索引开始

int

lastIndexOf(int ch)

返回指定字符最后一次出现的字符串内的索引

String []

split(String regex)

将此字符串分割为给定的字符串

String

substring(int beginIndex,int endIndex)

返回一个字符串,该字符串是此字符串的子字符串。

char[]

toCharArray()

将此字符串转换为新的字符数组

String

trim()

返回一个字符串,删除任何前导和尾随空格

String

replace(old char/String, new char/String)

返回一个新字符串

boolean

matches(String regex)

是否匹配正则

计算字串出现的次数

public int StrTimes(String a,String b){
    
    int count = 0
    int fromIndex = 0;
    
    while( (fromIndex = a.indexOf(b,fromIndex)) != -1 ){
        fromIndex += b.length();
        count++;
    }
    
    return count;
}

6. StringBuilder和StringBuffer

  • StringBuilder线程不安全,速度稍快
  • StringBuffer 线程安全,速度稍慢

他俩的实现方式是创建一个可变的底层数组,且提供各种改变数组序列的方法

这里来看StringBuffer ,StringBuilder类似,就不讲了

  • 二者都继承AbstractStringBuilder
  • 66行super()默认构造函数使用父类的,默认大小为16,底层也是字符数组
  • 会自动扩容,扩为原数组的2倍加2,这时是创建一个新的数组,并将原数组复制到新数组(与集合扩容类似)
  • 线程安全来源于synchronized

常见方法

构造函数

构造函数

解释

StringBuffer()

构造一个没有字符的字符串缓冲区,初始容量为16个字符

StringBuffer(String str)

构造一个初始化为指定字符串内容的字符串缓冲区,大小为str.length()+16

StringBuffer(int capacity)

构造一个没有字符的字符串缓冲区和指定的初始容量

常用方法

返回值

方法名

解释

StringBuffer

append(String str)

将指定的字符串附加到此字符序列

int

capacity()

返回当前容量

StringBuffer

delete(int start, int end)

删除此序列的子字符串中的字符

StringBuffer

insert(int offset, String str)

将字符串插入到此字符序列中

int

length()

返回长度(字符数)

StringBuffer

replace(int start, int end, String str)

用指定的String中的字符替换此序列的子字符串

StringBuffer

reverse()

导致该字符序列被序列的相反代替

String

toString()

返回表示此顺序中的数据的字符串

并且有String的方法

简单操作

可以链式操作,因为返回的是this本对象

StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("123")
    .append("abc")
    .append("-----")
    .delete(0, 3)
    .replace(3, 5, "dddd")
    .insert(7, "e");

System.out.println(stringBuffer.length());
System.out.println(stringBuffer.capacity());
System.out.println(stringBuffer.toString());
System.out.println(stringBuffer.reverse());
11
16
abcdddde---
---eddddcba

7. 总结

String适合操作少量数据

StringBuffer适合线程安全操作大量数据

StringBuilder适合单线程操作大量数据


没有地方写,补充一下日期的格式化

Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
System.out.println(sdf.format(date));

//2019-44-29 21:44:28

8 补充

java是按值传递,不是引用传递,下面举例

public class Pass {
    
    public static void test(int a, String b, User user){
        
        a = 2;
        b = "bb";
        user.name = "Change";
        
        System.out.println(a);
        System.out.println(b);
        System.out.println(user.name);
        
    }

    public static void main(String[] args) {
        
        int a = 1;
        String b = "b";
        User user = new User("Howl");
        
        test(a, b, user);
        System.out.println("--------------上面是传递改变,下面是未传递前----------------");
        
        System.out.println(a);
        System.out.println(b);
        System.out.println(user.name);
        
    }
}
2
bb
Change
--------------上面是传递改变,下面是未传递前----------------
1
b
Change

这里有个冲突分歧怪异点:为什么String和user对象只有user才能被改变?难道只有自定义对象才是按值传递?

非也,基本类型是按值传递这里大家没有意见把,主要在于引用类型是按值传递还是引用传递?其实这里应该在上面的test方法里加多一个语句才好理解

public static void test(int a, String b, User user){
        
        a = 2;
        b = "bb";
        user = new User("Change");  // 加的语句在这里
        // user.name = "Change";
        
        System.out.println(a);
        System.out.println(b);
        System.out.println(user.name);
}
2
bb
Change?
--------------上面是传递改变,下面是未传递前----------------
1
b
Howl

改变语句后,引用传递的效果就失去了,下面来分析一下:

public static void test(int a, String b, User user){
        
        a = 2;      // 参数a传递过来的是副本,即按值传递
        b = "bb";   // 这里String类型有点特殊,b = “bb” 相当于 b = new String(“bb”),新建了一个对象
        user = new User("Change");  // 把user的指向改为new User("XXX"),这里就明示出不是引用传递
        // user.name = "Change";    // test方法里和main方法里的user都指向堆内存同一个对象,当然可以改变
        
        System.out.println(a);
        System.out.println(b);
        System.out.println(user.name);
}

总结一下:基本类型按值传递,引用类型的传参传的是地址的副本,在给参数中的引用类型赋值时,改变的是参数的地址,即不属于引用传递,下面画图更好理解

没加入语句前

加入语句前

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • RabbitMQ入门

    笔者经常能看到MQ这个词,知道其作为消息队列,但始终没有接触过,现在刚好有个机会(不知道在抢答系统中能不能用上),首先当然要知道MQ有什么作用:

    晚上没宵夜
  • 邮箱验证激活账号

    晚上没宵夜
  • 重写equals和hashCode方法

    Object类中定义了equal和hashCode方法,又因为Object是基类,所以继承了Object的类都有这两个方法

    晚上没宵夜
  • String类常用方法(重要)

    int length():返回字符串的长度: return value.length

    乐心湖
  • Java常用类(二)String类详解

    前言   在我们开发中经常会用到很多的常用的工具类,这里做一个总结。他们有很多的方法都是我们经常要用到的。所以我们一定要把它好好的掌握起来! 一、String简...

    用户1195962
  • Java-String那些事

    贾博岩
  • Top 10 Methods for Java Arrays1 声明一个array2 打印一个array3 从array创建一个list4 检查array中是否存在某个元素5 连接两个array6 D

    desperate633
  • Spark Tips3: 在Spark Streaming job中读取Kafka messages及其offsetRange

    在Spark Streaming job中读取Kafka topic(s)中的messages时,有时我们会需要同步记录下每次读取的messages的offse...

    叶锦鲤
  • 基础面试,为什么面试官总喜欢问String?

    关于 Java String,这是面试的基础,但是还有很多童鞋不能说清楚,所以本文将简单而又透彻的说明一下那个让你迷惑的 String

    黄泽杰
  • 基础面试,为什么面试官总喜欢问String?

    关于 Java String,这是面试的基础,但是还有很多童鞋不能说清楚,所以本文将简单而又透彻的说明一下那个让你迷惑的 String

    码农小胖哥

扫码关注云+社区

领取腾讯云代金券