[JavaSE]String类

目录

1引用

2String类

2.1String类的两种实例化方式:(直接赋值/构造方法//常量池)

2.2字符串相等比较("=="比较字符串/equals()比较字符串)

2.3字符串常量不可变更

2.4char-------String(补充!String类和基本类型的转换)

2.5Byte-------String    

2.6何时使用 byte[], 何时使用 char[] 呢?-文本数据 vs 二进制数据

2.7其他方法

3StringBuffer类

3.1String与StringBuffer的互相转换

3.2StringBuffer的方法


官网上String类

1引用:

在栈上开辟了一小块内存空间保存一个地址

可以把引用想象成一个标签, "贴" 到一个对象上. 一个对象可以贴一个标签, 也可以贴多个. 如果一个对象上面一个标签都没有, 那么这个对象就会被 JVM 当做垃圾对象回收

修改str2=str1,内存变化:

String str="code";
String str2=str1;

如果改变str1="Student"会不会改变str2呢?

验证一下!

package se.SE.practice;
public class Test {
    public static void main(String[] args) {
        String str1="code";
        String str2=str1;
        str1="Student";
        System.out.println(str2);
    }
}

我们可以发现,即使改变了str1,但是str2不会改变的,对str1的改变只是让 str1 这个引用指向了一个新的 String 对象 

看看他们的内存变化吧!

2String类

2.1String类的两种实例化方式:

java中有很多池(常量池,线程池,内存池,数据库连接池),池的引入是为了帮助程序猿萌提高编程效率

举个栗子~~小明同学是个十足的宅男,最喜欢的就是躺在床上,吃零食。所以他在床边的篮子里放了很多种零食,正在吃的零食是A,其他备用的零食是B,为什么要放这么多备用的零食呢?一旦吃完了正在吃的零食,可以迅速的从床边拿备用零食,提高效率~~那么这些备用的零食组成的集合就可以看作是备用池

常量池

JVM内部会维护一个字符串常量池(对象数组)

a.如果采用直接赋值的方式进行String类的实例化操作,那么该对象会自动保存到对象池中。

b.如果下一次继续使用直接赋值实例化String类对象时,先在对象池中寻找是否有指定内容对象

                               1如果有,那么直接引用。

                               2否则创建新空间,将新对象入池以供下次使用。

2.1.1直接赋值:

String str="Hello";//直接赋值,在堆上分配空间

class Test{
    public static void main(String[] args) {
        String str1="Hello";
        String str2="Hello";
        System.out.println(str1==str2);
    }
}//true

2.1.2构造方法:

String str=new String("Hello");

内存变化:

 

1如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间

(字符串常量 "hello" 也是一个匿名对象, 用了一次之后就不再使用了, 就成为垃圾空间, 会被 JVM 自动回收掉).
2. 字符串共享问题. 同一个字符串可能会被存储多次, 比较浪费空间. 

实例后的对象不会保存在对象池之中,可以使用intern()方法来手工入池


class Test{
    public static void main(String[] args) {
        String str1="Hello";
        String str2=new String("Hello");
        System.out.println(str1==str2);
    }
}//false


class Test{
    public static void main(String[] args) {
        String str1="Hello";
        String str2=new String("Hello").intern();//调用intern()方法手工入池
        System.out.println(str1==str2);
    }
}//true

2.2字符串相等比较

2.2.1"=="比较字符串

两个对象所保存的内存地址数值比较,也就是两个引用是否是指向同一个对象.

比较下面两段代码:

代码1:

class Test{
    public static void main(String[] args) {
    int i1=1;
    int i2=1;
        System.out.println(i1==i2);
    }
}
//输出结果:true

代码1内存变化: 

代码2:创建的 String 对象相当于再堆上另外开辟了空间来存储"Hello" 的内容, 也就是内存中存在两份 "Hello".


class Test{
    public static void main(String[] args) {
        String str1="Hello";
        String str2=new String("Hello")
        System.out.println(i1==i2);
    }
}
输出结果:false

代码2内存变化:

这里你可能会产生一些疑问啦,为什么都是字符串"Hello"的比较,两段代码的输出结果会有所差别呢?

第二段代码new了一个新的内存空间,即str1和str2的地址不同,因此输出为false

2.2.2equals()比较字符串

进行字符串内容的比较

public boolean String(String anothor String)//方法声明

str1.equals(str2);//调用方法equals()

下面我们用equals()来比较str1 和str2的大小


class Test{
    public static void main(String[] args) {
        String str1="Hello";
        String str2=new String("Hello");
        System.out.println(str1.equals(str2));
    }
}
//输出结果:true

怎样更好的比较两个字符串的内容呢?equals()方法的最优比较

String str = new String("Hello");
// 方式一
System.out.println(str.equals("Hello"));
// 方式二
System.out.println("Hello".equals(str));

这里更推荐方式二!原因:方式一如果str为null会抛出异常,方式二不会 

2.3字符串常量不可变更

堆中常量的值无法修改,栈中的指向可以修改。


class Test{
    public static void main(String[] args) {
     String str="Happy ";
     str+="birthday";
     str+="!";
        System.out.println(str);
    }
}//输出结果:Happy birthday!

上述代码运行过程中,内存变化情况: 

中文

一些小建议:

 字符串不要改变太多次,慎用"+"

2.4char-------String

  • char[]->String

public String(char[] value):将字符数组全部转为字符串

public String(char[] value,int offset,int len):将字符数组部分转为字符串

  • String->char

public char charAt(int index):取得字符串指定索引字符,从0开始

  • String->char[]

public char[] toCharArray():将字符串转为字符数组


class Test{
    public static void main(String[] args) {
     String str="happy ";
//将字符串转换为字符数组

     char[] data=str.toCharArray();
     for(int i=0;i<data.length;i++){
         data[i]-=32;
     }
//将字符数组转换为字符串
        System.out.println(new String(data));//全部转换
        System.out.println(new String(data,0,4));//部分转换

    }
}
/*输出结果
HAPPY

HAPP

*/


应用toCharArray()方法来判断一个字符串是否全部由数字组成


class Test{
    public static void main(String[] args) {
    //判断一个字符串是否全部由数字组成
        String str1="1234";
        String str2="123a4";
        System.out.println(isNumber(str1));
        System.out.println(isNumber(str2));
}
public static boolean isNumber(String str) {
    char[] data = str.toCharArray();
    for (int i = 0; i < data.length; i++) {//遍历字符数组
        char c = data[i];
        if (c < '0' || c > '9') {
            return false;
        }

    }
    return true;
}
}//输出
true
false

补充!!

String类和基本类型的转换

String->基本类型

1valueOf方法

2intValue()---new一个字符串对象再转换

       //String->int
        String str1="100";
        //方法一:调用Integer的静态方法valueOf
        int num1=Integer.valueOf(str1);
        //方法二:new了一个字符串对象,再转换成number
        int num2=new Integer(str).intValue();

当字符串中包含非数字,在运行时会抛出NumberFormatException

基本类型->String

1."+"

       //int->String
        int num=10;
        //字符串和number相加就可
        String str=num+" ";
        

2.通过String类的构造方法

推荐:使用String.valueOf(所有基本类型)

2.5Byte-------String    


字节用在二进制流和网络传输中

  • byte[ ]->String

public String(byte[] value):将字符数组全部转为字符串

public String(byte[] value,int offset,int len):将字符数组部分转为字符串

  • String->byte[ ]

public byte[] getByte():将字符串转为字节数组[ ]

public byte[] getByte(String charSet):将字符串按照指定的编码格式转化为字节数组。

Linux默认编码为UTF-8 windows默认编码为GBK

class Test{
    public static void main(String[] args) {
        String str1="happybirthday";
//字符串转为字节数组
        byte[] data=str1.getBytes();
        for(int i=0;i<data.length;i++){
            data[i]-=32;
        }
//字节数组转为字符串
        System.out.println(new String(data));
    }
}

编码:将字符串按照怎样的算法转为字节

2.6何时使用 byte[], 何时使用 char[] 呢?

a.byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合
针对二进制数据来操..
b.char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候

文本数据 vs 二进制数据


一个简单粗暴的区分方式就是用记事本打开能不能看懂里面的内容.
如果看的懂, 就是文本数据(例如 .java 文件), 如果看不懂, 就是二进制数据(例如 .class 文件).

2.7其他方法

字符串的比较方法

  • 比较相等:

equals(Object anObject)--区分大小写的比较

equalsIngoreCase(String anotherString)--不区分大小写的比较

  • 比较大小:

public int compareTo(String anotherString):比较两个字符串的大小关系

负数:小于

0:相等

正数:大于

class Test{
    public static void main(String[] args) {
    String str1="abc";
    String str2="Abc";
    String str3="abc";
        System.out.println(str1.compareTo(str2));
        System.out.println(str2.compareTo(str3));
    }
}输出结果:
32 
-32

按照ASCII码比较,只要发现不相等的内容算出差值直接返回,不会继续向下。

字符串的查找

public boolean contains(CharSequence)   判断一个字符串是否存在

public boolean startswith(String prefix)    判断是否以指定字符串开头

public boolean endswith(String prefix,int toffset)   判断是否以指定的字符串结尾

特别的:这里有一个比较特别的方法 indexOf() --------返回int 。JDK1.5之前查找字符串,此方法查找字符串时如果内容重复,它只能返回查找的第一个位置。

class Test{
    public static void main(String[] args) {
        String str="happybirthday!";
        System.out.println(str.contains("happy"));
        System.out.println(str.startsWith("happy"));
        System.out.println(str.endsWith("!"));

    }
}
输出结果:
true
true

字符串的替换

由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串.

public String replaceAll(String regax,String relacement):将字符串中所有指定内容替换成新内容。

public String replaceFirst(String regax,String replacement):替换首个内容

class Test{
    public static void main(String[] args) {
        String str="happybirthday!";
        System.out.println(str.replaceAll("pp","00"));
        System.out.println(str.replaceFirst("a","0"));

    }
}
输出结果:
ha00ybirthday
h0ppybirthday

字符串的拆分(重点!)

public String[] split(String regax):按照指定格式将字符串全部拆分

public String[] split(String regax,int limit):将字符串部分拆分,数组长度为限定limit长度

//全部拆分

class Test{
    public static void main(String[] args) {
        String str="happy-birthday-!!!";
      String[] result=str.split("-",3);//按照--拆分
      for(String s:result){
          System.out.println(s);
      }
    }
}
输出结果:
happy
birthday
!!!

注:当limit的值大于等于(regex+1)时,所拆分段数不变。通俗点解释,在本例中happy-birthday-!!!按“-”拆分,当limit的值大于等于三时,最多可分成3段

//部分拆分

class Test{
    public static void main(String[] args) {
        String str="happy-birthday-!!!";
      String[] result=str.split("-",2);
      for(String s:result){
          System.out.println(s);
      }
    }
}

敲重点啦!!一些比较复杂的拆分形式

1. 字符"|","*","+"都得加上转义字符,前面加上"\".
2. 而如果是"",那么就得写成"\\".
3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符. 

//拆分IP地址

class Test{
    public static void main(String[] args) {
        String str="192.156.1.2";
      String[] result=str.split("\\.");
      for(String s:result){
          System.out.println(s);
      }
    }
}
输出结果:
192
156
1
2

//多次拆分

class Test{
    public static void main(String[] args) {
      String str="a:12|b:34";
      String[] result=str.split("\\|");
      for(int i=0;i<result.length;i++){
      String[] temp=result[i].split(":");
      System.out.println(temp[0]+"="+temp[1]);
      }
    }
}
输出结果:
a=12
b=34
class Test{
    public static void main(String[] args) {
    String str = "name=zhangsan&age=18" ;
    String[] result = str.split("&") ;
    for (int i = 0; i < result.length; i++) {
    String[] temp = result[i].split("=") ;
    System.out.println(temp[0]+" = "+temp[1]);
        }
    }
}

字符串的截取

public String substring(int beginIndex):从指定索引开始截取到字符串结尾

public String substring(int beginIndex,int endIndex):从指定索引开始到指定结束位置。

class Test{
    public static void main(String[] args) {
        String str="happybirthday!";
      String[] result=str.split("\\|");
        System.out.println(str.substring(5));//从第五个截取到末尾(不包括第五)
        System.out.println(str.substring(0,5));//从第一个截取到第五个  
    }
}
输出结果:
birthday!
happy

其他方法:

public String trim():去掉字符串左右两边的空格,换行,制表符,中间保留。

String str = " hello world " ;
System.out.println("["+str+"]");
System.out.println("["+str.trim()+"]");

public String toUpperCase():字符串转大写

public String toLowerCase():字符串转小写

public int length():取得字符串的长度数组长度使用数组名称.length属性,而String中使用的是length()方法

public boolean isEmpty():判断是否为空字符串--------判断标准:长度为0 不是null

String类的首字母大写需要自己实现

public static void main(String[] args) {
System.out.println(fistUpper("yuisama"));
System.out.println(fistUpper(""));
System.out.println(fistUpper("a"));
}
public static String fistUpper(String str) {
if ("".equals(str)||str==null) {
return str ;
}
if (str.length()>1) {
return str.substring(0, 1).toUpperCase()+str.substring(1) ;
}
return str.toUpperCase() ;
}

String类的总结:

1.任何字符串常量都是String对象,并且String的常量一旦声明不可改变,如果改变,只是改变对象引用的指向

2.String类用“+”拼接 不可更改

3StringBuffer类

----------目的:为了方便字符串的修改

  • public synchronized StringBuffer append(各种数据类型 b)
class Test{
    public static void main(String[] args) {
 StringBuffer sb=new StringBuffer();
 sb.append("Hello").append("world");
fun(sb);
        System.out.println(sb);
    }
    public static void fun(StringBuffer temp){
        temp.append("\n").append("www.github.com");
    }
}
输出结果:
Helloworld
www.github.com

3.1String与StringBuffer的互相转换:

源码:

String类

public final class String implements
java.io.Serializable, Comparable<String>,
CharSequence

 StringBuffer类

public final class StringBuffer extends
AbstractStringBuilder implements java.io.Serializable,
CharSequence

两个类都是"CharSequence"接口的子类。这个接口描述的是一系列的字符集。所以字符串是字符集的子
类,如果以后看见CharSequence,最简单的联想就是字符串。

String-->StringBuffer:     利用StringBuffer的构造方法或者append()方法

package se.SE.practice;
public class Test1{
    public static void main(String[] args) {
        String str="hehe";
        StringBuffer stringBuffer=new StringBuffer(str);
        for(int i=0;i<6;i++){
            stringBuffer.append(" b");//实现字符串的拼接,stringBuffer.append("要拼接的字符")
        }
        str=stringBuffer.toString();
        System.out.println(str);
    }
}
//输出:
//hehe b b b b b b

StringByffer-->String:     调用toString方法

3.2StringBuffer的方法

线程安全,同步操作(但凡和同步相关联,这个操作就和高性能无关)也就是说,线程安全付出的代价就是性能下降

字符串反转:reverse()

public synchronized StringBuffer reverse()

class Test{
    public static void main(String[] args) {
        StringBuffer sb=new StringBuffer("happybirthday");
        System.out.println(sb.reverse());
    }
}
输出结果:
yadhtribyppah

删除指定范围的数据:delete(int start ,int end)

public synchronized StringBuffer  delete(int start ,int end)

class Test{
    public static void main(String[] args) {
        StringBuffer sb=new StringBuffer("happybirthday");
        System.out.println(sb.delete(0,3));
    }
}
输出结果:
pybirthday

插入数据:insert()

public synchronized StringBuffer  insert(int offset,数据类型 b)

class Test{
    public static void main(String[] args) {
        StringBuffer sb=new StringBuffer("hhappybirthday");
        System.out.println(sb.delete(0,1).insert(0,"boom~~~ "));
    }
}
输出结果:boom~~~ happybirthday

总结:

从线程安全性比较String/StringBuffer和StringBuilder:

String常量内容不可修改而StringBuffer和StringBulider内容可以修改

StringBuffer采用同步处理,属于线程安全操作。

StringBuilder采用异步处理,属于线程不安全操作。

一般情况使用StringBuilder性能较高

当String对象用“+”进行字符串的拼接时,javac编译器会将String对象变为StringBuilder然后调用append()来修改字符串的内容,减少无用空间的开辟。

String是immutable的,其内容一旦创建好之后,就不可以发生改变。
StringBuffer 是可以变长的,内容也可以发生改变
改变的原理是StringBuffer内部采用了字符数组存放数据,在需要增加长度的时候,创建新的数组,并且把原来的数据复制到新的数组这样的办法来实现。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值