Java学习基础_1.4_String

定义:

  String类是一个字符串类型的类,使用"   "定义的内容都是字符串。 

实例化:

  (1)直接赋值实例化:String str ="Hello World!";

  (2)使用构造方法实例化:String str = new String("Hello World!");

字符串的比较:

  如果我们想知道两个int类型变量是否相等,可以使用 == 进行验证,那么String中使用 == 是否可以验证呢,来看一个栗子:

  

package javaEE;
/** 
 * @author 047493 
 * @version 2018年8月31日 
 * 类说明 
 */
public class Test12 {
    public static void main(String[] args) {
        
        String str1 = "Hello";
        String str2 = new String("Hello");
        String str3 = str2;
        
        System.out.println(str1 == str2);
        System.out.println(str2 == str3);
        System.out.println(str1 == str3);
        
    }
}

运行结果:

false
true
false

造成此原因的内存关系图如下:

通过上图分析可知,== 比较的不是字符串对象包含的内容,而是两个对象所在的内存对象的数值。即 == 属于数值比较,比较的是内存地址。

如果想比较字符串的内容,可以使用equals()。栗子如下:

package javaEE;
/** 
 * @author 047493 
 * @version 2018年8月31日 
 * 类说明 
 */
public class Test12 {
    public static void main(String[] args) {
        
        String str1 = "Hello";
        String str2 = new String("Hello");
        String str3 = str2;
        
        System.out.println(str1.equals(str2));
        System.out.println(str2.equals(str3));
        System.out.println(str1.equals(str3));
        
    }
}

运行结果如下:

true
true
true

字符串常量是匿名对象:
  举个栗子,验证如下:

package javaEE;
/** 
 * @author 047493 
 * @version 2018年8月31日 
 * 类说明 
 */
public class Test12 {
    public static void main(String[] args) {
        
        String str1 = "Hello";
        System.out.println("Hello".equals(str1));
    }
}

运行结果如下:

true

匿名对象可以调用类中的方法和属性,而以上字符串调用了String类的equals(),所以它一定是一个对象。

String类对象两种实例化方式的区别:

  (1)直接赋值的实例化方式:String str ="Hello";

内存关系图如下:

举个栗子:

package javaEE;
/** 
 * @author 047493 
 * @version 2018年8月31日 
 * 类说明 
 */
public class Test12 {
    public static void main(String[] args) {
        
        String str1 = "Hello";
        String str2 = "Hello";
        String str3 = "Hello";
        
        System.out.println(str1 == str2);
        System.out.println(str2 == str3);
        System.out.println(str3 == str1);

    }
}

运行结果如下:

true
true
true


我们发现以上所有直接赋值的String类对象的内存地址完全相同,内存分配图如下:

在设计String类的时候才用了一种共享设计模式的概念。在运行的JVM底层存在一个字符串的对象池(object pool),如果用户才用了直接赋值的方式,会将字符串的内容放入池保存,如果以后其他字符串对象继续使用直接赋值方式实例化,且设置了同样的内容,那么将不会分配新的堆内存空间,而是使用已有对象的引用进行分配继续使用。如果新声明的字符串内容不在对象池中,则会分配一个新的,然后继续放到池中以供下次使用。

  (2)构造方法实例化方式:String str = new String("Hello");

构造方法实例化一定用使用new关键字,而一旦使用new关键字就表示要分配新的内存空间。

内存分配图如下:

可以发现,分配了两块内存空间,其中一块是垃圾。这样除了内存的浪费外,使用构造方法定义的String对象,其内容不会保存在对象中(因为重新分配了一块堆内存)。

现在希望使用构造方法定义的String类对象,其内容要保存在对象中,改怎么办?我们可以使用intern(),手工入池。

举个栗子:

package javaEE;
/** 
 * @author 047493 
 * @version 2018年8月31日 
 * 类说明 
 */
public class Test12 {
    public static void main(String[] args) {
        
        String str1 = new String("Hello").intern();
        String str2 = "Hello";
        String str3 = "Hello";
        
        System.out.println(str1 == str2);
        System.out.println(str2 == str3);
        System.out.println(str3 == str1);
    }
}

运行结果如下:

true
true
true

两种实例化方式的区别:

  (1)直接赋值方式:只会分配一块堆内存空间,并且对象内容自动入池,以供重复使用;

  (2)构造方法方式:会分配两块堆内存空间,其中有一块是垃圾,并且不会自动入池,可以调用intern()自动入池。

字符串的内容一旦定义则不可改变:

  举个栗子:

package javaEE;
/** 
 * @author 047493 
 * @version 2018年8月31日 
 * 类说明 
 */
public class Test12 {
    public static void main(String[] args) {
        
        String str = "Hello ";
        str +="World ";
        str +="!!!";
        System.out.println(str);
    }
}

运行结果如下:

Hello World !!!

内存分析图如下:

通过内存分析图得知,字符串内容的改变,实际上改变的是字符串对象的引用过程,并且会伴随着大量的内存垃圾出现,在实际开发中应该避免。

那,如果我们要改变字符串的长度,应该怎么做呢?

可以使用可变字符串StringBuilder或StringBuffer。

StringBuilder和StringBuffer构建可变字符串对象都是通过new操作符调用构造方法,两者的区别在于StringBuilder应用于单线程环境,而StringBuffer应用于多线程环境。

StringBuilder的主要方法:

package javaEE;
/** 
 * @author 047493 
 * @version 2018年8月31日 
 * 类说明 
 */
public class Test12 {
    public static void main(String[] args) {
        
        StringBuilder sb = new StringBuilder();
        sb.append("String is changed");
        System.out.println(sb);
        sb.insert(0, 123);  //在字符串下标0处插入123
        System.out.println(sb);
        sb.delete(0, 3);  //删除前3位字符串
        //sb.delete(sb.length()-3, sb.length());  //删除sb字符串后面的3位字符
        System.out.println(sb);
        sb.replace(0, 3, "!!!");  //替换前3位字符串
        System.out.println(sb);
        sb.reverse();  //字符串翻转
        System.out.println(sb);
        sb.setCharAt(0, 'A');  //设置某个小标的字符内容
        System.out.println(sb);
    }
}

运行结果如下:

String is changed
123String is changed
String is changed
!!!ing is changed
degnahc si gni!!!
Aegnahc si gni!!!

即,凡是需要大量拼接字符串的地方都应该尽量使用可变字符串来完成,效率高且不占内存空间。

参考资料:

https://blog.csdn.net/wei_zhi/article/details/52761081

https://www.cnblogs.com/fwnboke/p/8529453.html

猜你喜欢

转载自www.cnblogs.com/Rain1203/p/9494665.html
今日推荐