Java中特殊的类——String类

Java中特殊的类——String

1.String类的实例化方式

(1)直接赋值: 

     String 字符串名 = "要赋值内容";

 

public class TestString4_12 {

public static void main(String[] args) {

String str1 = "我是直接赋值进行实例化";

System.out.println("str1"+ str1);

}

}

(2)传统方式(new)

    因为String为一个类,所以一定存在自己的构造方法,因此可以通过构造方法实例化对其赋值。

     String类中的构造方法:

                   

利用关键字new进行对象的实例化:

public class TestString4_12 {

public static void main(String[] args) {

String str2 = new String("我是利用构造方式进行实例化");

System.out.println("str2"+str2);

}

}

(3)两种实例化方式的区别

public class TestString4_12 {

public static void main(String[] args) {

//直接赋值方式实例化

       String str1 = "我是直接赋值进行实例化";

String str3 = "我是直接赋值进行实例化";

String str4 = "我是直接赋值进行实例化";

System.out.println("str1"+ str1);

System.out.println(str1==str3);

System.out.println(str1==str4);

System.out.println(str3==str4);

       //传统方式(new)实例化

String str2 = new String("我是利用构造方式进行实例化");

String str5 = new String("我是利用构造方式进行实例化");

String str6 = new String("我是利用构造方式进行实例化");

System.out.println("str2"+str2);

System.out.println(str2==str5);

System.out.println(str2==str6);

System.out.println(str5==str6);

}

}

运行结果:

 

那么为什么会产生如下的结果呢?那么我们做以下分析:

String类使用了共享设计模式。

JVM底层实际自动维护了一个对象池(字符串对象池),如果采用直接赋值进行String类的实例化,则该实例化对象(字符串的内容)将自动保存到这个对象池中,若下次继续使用直接赋值方式声明String类型,那么在此时则先看对象池中是否由指定内容,若有则直接引用;若没有,则开辟新的字符串对象并将其保存至对象池中供下次使用。

                              

直接赋值实例化内存分析图

 

    如果使用String 构造方式实例化对象就会产生两块堆内存空间,并且其中的一块为垃圾空间。

                               

传统方式实例化内存分析图

 

那么String两种对象实例化的区别:

     1.直接赋值:只会开辟一块内存空间,并且该字符串对象会自动保存在对象池中供下次使用。

     2.构造方式:会开辟两块堆内存空间,其中一块成为垃圾空间,并且不会保存在对象池中。(但可以使用intern()方法手工入池

 

(4)字符串共享问题

     针对用构造方法实例化对象并不能将字符串自动入池的问题,String类提供了intern()方法进行手工入池。如下例:

 

public class TestString4_12 {

public static void main(String[] args) {

       //进行此操作该字符串常量并没有保存在对象池中

String str7 = new String("hello");

String str8 = "hello";

System.out.println(str7==str8);  

       //进行字符串的实例化并利用inter()方法进行手工入池操作

String str9 = new String("hello").intern();

String str10 = "hello";

System.out.println(str9==str10);

}

}

 

运行结果:

 

 

                                     

手工入池内存分析

2.字符串相等比较

我们熟知用==”可以判断两个基本数据类型是否相等,上面的例子所示,我们使用了“==”来比较两个String对象的大小,那么究竟是如何作比较呢,我们可根据如下程序得出结论:==运算符本身是进行数值比较的,如果用来比较两个对象,则比较的应该是两个对象所保存的地址值,并不是比较对象中的内容;要想比较对象中保存的内容是否相等则应使用String提供的equals方法

public class TestString4_12_1 {

public static void main(String[] args) {

String str1 = "hello lemon";

String str2 = new String("hello lemon");

System.out.println(str1==str2);

System.out.println(str1.equals(str2));

}

}

运行结果:  


==”判断两字符串相等内存分析图

请解释String类中“==”和“equals”的区别

==”:进行的是数值比较,比较的是两个字符串对象的内存地址数值。

equals”:进行的是字符串内容的比较。

3.字符串常量是String的匿名对象

在任何语言的底层都不会提供直接的字符串类型。现在所谓的字符串只是高级语言提供给用户方便开发的支持而已。在java本身也没有直接提供字符串常量的概念,所有使用“”定义的内容从本质上来讲都是String的匿名对象。

public class TestString4_12_1 {

public static void main(String[] args) {

String str1 = "hello lemon";

String str2 = new String("hello lemon");

System.out.println(str1==str2);

System.out.println(str1.equals(str2));

System.out.println("hello lemon".equals(str2));

}

}

 

由此我们可以看出,之前使用的 String str1 = hello lemon”本质上就是将一个匿名的String类对象设置有名字,而且匿名对象要保存在堆空间中。

提示:若要判断用户输入的字符串是否与特定字符串相等时,一定要将特定字符串写在前面。

public class TestString4_12_1 {

public static void main(String[] args) {

String  str3 = null;//假定该字符串由用户输入

System.out.println("hello".equals(str3));

System.out.println(str3.equals("hello"));

}

}

 

运行结果:

 

 

     若使用将“用户输入”字符串放前面作比较的话,如果用户没有输入,则会出现NullPointerException异常;但若使用将特定字符串放前面则不会出现此异常(任何的字符串常量都为String的匿名对象,所以该对象永远不会为null.

3.字符串常量不可变更

字符串定义如下:

 

    由此看可以看出:String类是一个final类,即字符串已一旦定义就不可改变。

所有的语言对于字符串的底层实现都是字符数组,数组的最大缺陷就是长度不可改变。在定义字符串常量时,它的内容不可改变

那么该如何理解内容不可改变呢,我们由下例给出分析:

public class TestString4_12_1 {

public static void main(String[] args) {

String str1 = "hello";

str1 = str1 + " lemon";

str1 = str1 + "!";

System.out.println(str1);

}

}

 


字符串常量不可变更内存分析图

通过上面的分析可以发现字符串上没有发生改变,但是字符串对象的引用一直在发生改变,从而可以导致大量的垃圾空间。

所以在开发中不应该出现如下代码:

 

public class TestString4_12_1 {

public static void main(String[] args) {

String str = "lalala";

for(int i = 0;i <= 1000;i++){

str += i;

}

System.out.println(str);

}

}

这样的代码若很多用户使用同样的从操作,则会产生垃圾空间的数量相当可观。

 5.String类中一些常用方法

1)字符与字符串的互操作

字符串就是一个字符数组,所以在Sring类中提供有字符串与字符互相转换的方法。

字符数组->字符串public String(char value[])

部分字符数组->字符串:public String(char value[], int offset,         int count)

字符串->字符数组public char[] toCharArray()

取得指定位置的字符:public char charAt(int index)

public class TestString4_12_1 {

public static void main(String[] args) {

//字符数组转化为字符串

char[] myData = new char[]{'h','e','l','l','o',' ',

                   'w','o','r','l','d',',',

                   'h','e','l','l','o',' ',

                   '','',''};

//将字符数组中所有内容转化成字符串

System.out.println(new String(myData));

//将字符数组中指定位置开始的内容转化成字符串

System.out.println(new String(myData,6,6));

String str = "hello world ,hello 陕科大";

char[] temp = str.toCharArray();

for(int i = 0;i < temp.length;i++){

System.out.print(" "+temp[i]);

}

System.out.println();

//取得指定位置的字符

System.out.println("str的第10个字符为:"+str.charAt(10));

}

}

 

 

 

例子:现有一个字符串判断其是否由数字组成:

      解决思路:因为不知道字符串的长度和内容,所以最好是将字符串转化成字符数组然后判断每一个字符是否是0”—“9”之间的内容,若是则为数字,反之亦然。

public class TestString4_12_1 {

public static void main(String[] args) {

String str2 = "1243234adsfs";

String str3 = "902093";

System.out.println(isNumConsist(str2));

System.out.println(isNumConsist(str3));

}

//判断字符串是否全部由数字组成

public static boolean isNumConsist(String string){

char[] data = string.toCharArray();

for(int i = 0;i < data.length;i++){

if(data[i]<'0'||data[i]>'9'){

return false;

}

}

return true;

}

}

 

运行结果:

 

 

(2)字节与字符串的互操作

(3)字符串比较

在之前提过字符串比较的equals()方法,该方法只可以用来比较区分大小写的相等判断,除此看还有以下比较方法:

区分大小写的比较: public boolean equals(Object anObject)

不区分大小写的比较:public boolean equalsIgnoreCase(String anotherString)

比较两个字符串大小关系(可以区分大小关系): public int compareTo(String anotherString)

public class TestString4_12_1 {

public static void main(String[] args) {

String str1 = "HELLO ";

String str2 = "hello";

//不区分大小写的比较两个字符串是否相等

System.out.println(str1.equals(str2));

//区分大小写比较两个字符串是否相等

System.out.println(str1.equalsIgnoreCase(str2));

//比较两个字符串的大小关系,若两个字符串都为英文字母

//其返回结果为两个字符串不相同的第一个字母所相差的ASCII码值

System.out.println(str1.compareTo(str2));

}

}

 

 

(4)字符串查找

a.判断一个子串是否存在 public boolean contains(CharSequence s)

b.从头开始查找指定字符串的位置:public int indexOf(String str)

c.从指定位置开始查找子字符串的位置:public int indexOf(String str, int fromIndex)

d.从后向前查找子字符串的位置:public int lastIndexOf(String str)

e.从指定位置开始从后往前查找子字符串的位置:public int lastIndexOf(String str, int fromIndex)

f.判断是否已指定字符串开头public boolean startsWith(String prefix)

g.从指定位置开始查找是否以指定字符串开头: public boolean startsWith(String prefix, int toffset)

h.判断是否以指定字符串结尾public boolean endsWith(String suffix)

 

public class TestString4_12_1 {

public static void main(String[] args) {

String str1 = "Hello world,Hello 陕科大";

String str2 = "Hello world,hello 陕科大";

String str3 = "Hello world,hello 陕科大,hello lemon";

//判定子串是否存在,若存在返回true,若不存在返回false

System.out.println(str1.contains("hello"));

System.out.println(str1.contains("Hello"));

//从开头查找指定字符串是否存在,若存在返回开始位置的索引值,若不存在返回-1

//若内容重复在,只返回第一次出现时的索引值

System.out.println(str2.indexOf("hello"));

//从指定查找指定字符串是否存在,若存在返回开始位置的索引值,若不存在返回-1

//若内容重复在,只返回第一次出现时的索引值

System.out.println(str3.indexOf("hello",13));

//从后向前查找子字符串的位置

System.out.println(str2.lastIndexOf("hello"));

//从指定位置向前查找子字符串的位置,若查找str3则返回的是最后一次出现时的索引值

System.out.println(str3.lastIndexOf("hello",27 ));

//判断是否以指定字符串开头

System.out.println(str1.startsWith("hello"));

System.out.println(str1.startsWith("Hello"));

//从指定位置开始判断是否以指定字符串开头

System.out.println(str2.startsWith(str2,10));

//判断是否以指定字符串结尾

System.out.println(str1.endsWith("陕科大"));

System.out.println(str3.endsWith("陕科大"));

}

}

 

运行结果:

 

 

(5)字符串替换

替换所有指定的内容:public String replaceAll(String regex, String replacement)

替换首次出现的指定内容:public String replaceFirst(String regex, String replacement)

public class TestString4_12_1 {

public static void main(String[] args) {

String str1 = "Hello world,Hello 陕科大";

String str2 = "Hello world,hello 陕科大";

String str3 = "Hello world,hello 陕科大,hello lemon";

//用指定字符串 替换原字符串中的所有指定要被替换的内容

System.out.println(str3.replaceAll("hello", "hi"));

//用指定字符串 替换原字符串中的所有指定要被替换的内容

System.out.println(str3.replaceFirst("hello", "hi"));

}

}

 

 

(6)字符串拆分

     可以将一个完整的字符串按照指定的分隔符拆分成多个字符串。

将字符串全部拆分: public String[] split(String regex)

将字符串部分拆分:public String[] split(String regex, int limit)

public class TestString4_12_1 {

public static void main(String[] args) {

String str1 = "Hello world,Hello 陕科大";

String str2 = "Hello world,hello 陕科大";

String str3 = "Hello world,hello 陕科大,hello lemon";

//将字符串按照指定分隔符全部拆分,拆分后结果为字符数组

String[] result = str3.split(" ");

for(int i = 0;i < result.length;i++){

System.out.println(result[i]);

}

System.out.println();

//将字符串按照指定分隔符按照指定数组的长度部分拆分

String[] result1 = str3.split(" ", 2);

for(int i = 0;i < result1.length;i++){

System.out.println(result1[i]);

}

System.out.println();

//拆分IP地址(若出现有些字符无法拆分时,则用转义字符"\\"进行转义)

String str4 = "192.168.237.188";

String[] result2 = str4.split("\\.");

for(int i = 0;i <result2.length;i++){

System.out.print(result2[i]+"  ");

}

System.out.println();

 }

}

 

 

 

(7)字符串截取

     从一个字符串中截取出部分内容

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

截取部分内容(指定开始索引指定结束索引):public String substring(int beginIndex, int endIndex)

public class TestString4_12_1 {

public static void main(String[] args) {

String str1 = "Hello world,Hello 陕科大";

//从指定位置截取字符串

System.out.println(str1.substring(6));

//从指定位置开始到指定位置结束截取字符串

System.out.println(str1.substring(6, 12));

 }

}

 

 

 

(8)其他方法

去掉字符串的左右空格保留中间空格:public String trim()

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

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

字符串连接(等同于+,入池):public String concat(String str)

public class TestString4_12_1 {

public static void main(String[] args) {

String str1 = " Hello world,Hello 陕科大 ";

String str2 = ",Hello lemon";

System.out.println(""+str1+"");

//去掉字符串左右空格保留中间空格

System.out.println(""+str1.trim()+"");

//字符串长度

System.out.println(str1.length());

//是否为空字符串

System.out.println(str1.isEmpty());

//字符串转大写

System.out.println(str1.toUpperCase());

//字符串转小写

System.out.println(str1.toLowerCase());

//字符串连接

System.out.println(str1.concat(str2));

 }

}

 

 

 

范例:实现首字母大写

public class TestString4_12_1 {

public static void main(String[] args) {

//实现首字母大写

System.out.println(RealizeFirstUpper("hello"));

System.out.println(RealizeFirstUpper(""));

System.out.println(RealizeFirstUpper("l"));

 }

public static String RealizeFirstUpper(String str){

if("".equals(str)||str == null){

return str;

}

if(str.length()>1){

//字符串长度对于1时,将第一个字符大写,然后拼接从第二个字符开始截取的字符串

return str.substring(0,1).toUpperCase()+str.substring(1);

}

//字符串只有一个字符的情况

return str.toUpperCase();

}

}

 

 

 6.StringBufffer

String类的特点:

      任何的字符串常量都是String类的匿名对象,且String一旦声明就不可改变(内容不可变,若要改变内容,改变的是索引)。

      为了方便字符串的修改我们来介绍StringBuffer类:String类中用“+”即可实现字符串的连接,但在StringBuffer类中要使用append()方法

public synchronized StringBuffer append(Object obj)

public class TestString4_12_1 {

public static void main(String[] args) {

StringBuffer strBuf = new StringBuffer();

//StringBuffer中字符串的拼接

strBuf.append("hello").append(" world");

fun(strBuf);

System.out.println(strBuf);

}

//实现换行并拼接资格字符串

public static void fun(StringBuffer temp){

temp.append("\n").append("hhahh");

}

}

 

 

1.String和StringBuffer类的最大区别:

       String类的内容不可修改,而StringBuffer类的内容可以修改。(若需要频繁修改字符串的内容则应该使用StringBuffer类)

 

2.String类和StringBuffer类不能直接转换,要想转换可使用以下原则:

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

StringBuffer-> String:调用toString()方法

 

3.StringBuffer类的一些方法:

  (1)字符串反转:public synchronized StringBuffer reverse()

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

  (3)插入数据: public StringBuffer insert(int offset, 各种数据类型)

public class TestString4_12_1 {

public static void main(String[] args) {

StringBuffer strBuf = new StringBuffer("hello world");

StringBuffer strBuf1 = new StringBuffer("hello world");

StringBuffer strBuf2 = new StringBuffer("hello world");

//字符串反转

System.out.println(strBuf.reverse());

//删除指定位置的元素

System.out.println(strBuf1.delete(2,8));

//插入数据

System.out.println(strBuf2.insert(5, "你好"));

}

}

 

 

总结:

字符串一般的使用原则:

字符串使用直接赋值。

字符串比较使用equals实现。

字符串不能改变太多。

StringStringBufferStringBuinder类的区别:

     1String的内容不可改变,StringBufferStringBuilder的内容可以改变。

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


猜你喜欢

转载自blog.csdn.net/qq_40409115/article/details/79920429