java三大特殊类之String 类(上)

一、实例化方式

1、直接赋值:

 String str = "Hello World"; //str是一个对象,那么"Hello World"应该保存在堆内存中
 System.out.println(str);

这种赋值方法最为常用,但是String本身毕竟是一个类,既然是类,那么类中一定存在构造方法。

    public String (String str);

2、使用构造方法实例化:

String str = new String("Hello World");
System.out.println(str);

二、字符串比较

1、如果要比较两个int型变量是否相等,只需要用"=="验证

例子:

        int x = 10;
        int y = 10;
        System.out.println(x == y);

结果:

true

在String中也可以用"=="比较,看以例子:

/**
 * @Author WFG
 * @Date 2019/5/16 17:49
 */
public class TestDemo1 {
    public static void main(String[]args){
       String str1 = "Hello World";
       String str2 = new String("Hello World");
       String str3 = str2;       //引用传递

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

    }

}

结果:

false
false
true

通过以上例子可以发现,字符串内容相同,但用"=="判断的结果不一样,究其原因,还得从内存来看:

通过以上分析可知,"=="比较的不是字符串对象包含的内容,而是两个对象保存的内存地址数值比较,也就是"=="属于数值比较,比较的是内存地址。

如果想要比较对象的内容,则必须使用String类提供的equals方法

范例:

/**
 * @Author WFG
 * @Date 2019/5/16 17:49
 */
public class TestDemo1 {
    public static void main(String[]args){
       String str1 = "Hello World";
       String str2 = new String("Hello World");
       String str3 = str2;       //引用传递

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

    }

}

结果:

true
true
true

小结:

(1)“==”比较的是两个字符串内存地址的数值是否相等,属于数值比较。

(2)“equals()”比较的是两个字符串的内容,属于内容比较。

三、String的匿名对象

在任何语言的底层,都没有提供字符串的数据类型定义,现在所谓的字符串只是高级语言提供给用户方便开发的支持而已。很多语言都是使用字符数组来描述字符串的概念。在java中也没有提供字符串的概念,依然不属于基本数据类型。字符串作为String类的匿名对象存在的。(所有使用""定义的内容本质上来讲都是String类的匿名对象)。

观察字符串常量:

public class TestDemo2 {
    public static void main(String[]args){
        String str1 = "Hello";
        String str2 = new String("Hello");

        System.out.println(str1.equals(str2));
        System.out.println("Hello".equals(str2));
    }
}

结果:

true
true

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

PS:任何字符串常量都是Stringn的匿名对象,所以该对象用永远不会为null。如果要判断用户输入的字符串是否等同于特定字符串,一定要将特定字符串写在前面,以防出现NullPointerException问题。

四、String类两种实例化的区别

回顾上面讲到的两种实例化操作,在实际开发中,如何选择呢?

1、采用直接赋值:

        String str = "Hello";

此时只分配了一块栈内存和堆内存空间:

再来看代码:

public class TestDemo2 {
    public static void main(String[]args){
        String str1 = "hello" ;
        String str2 = "hello" ;
        String str3 = "hello" ;
        System.out.println(str1 == str2);
        System.out.println(str1 == str3);
        System.out.println(str2 == str3);
     
    }
}

结果:
 

true
true
true

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

为什么没有开辟新的内存空间呢?

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

在JVM底层实际上会自动维护一个对象池(字符串对象池),如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池中。如果下次继续使用直接赋值的模式声明String类对象,此时对象池中年如若有指定内容,将直接进行引用;如果没有,则开辟新的字符串对象然后将其保存在对象池中以供下次使用。(所谓对象池就是一个对象数组,目的是为了减少开销)

2、采用构造方法

类对象使用构造方法实例化是标准做法,使用构造方法一定要new,而一旦使用new就表示分配新的内存空间:

String str = new String("Hello") ;

内存分配如下:

通过分析可知,如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间,除了这一缺点外,也会对字符串共享产生问题。
 

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

    }
}

结果:

false

使用构造方法定义的String类对象,其内容不会保存在对象中(因为重新分配了一块新的内存)。

现在如果使用构造方法定义String类的对象,其内容要保存在对象中该怎么办?我们可以使用String类定义的一个手动入池的办法:

public String intern();

范例:

public class TestDemo2 {
    public static void main(String[]args){
        String str1 = new String("Hello").intern();
        String str2 = "Hello";

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

结果:
 

true

小结:

String类两种实例化的区别:

(1)直接赋值实例化(string str = "xxx"):只会分配一块堆内存空间,并且对象自动入池,以供重复使用;

(2)构造方法实例化(string str = new string("xxx")):会分配两块内存空间,其中一块是垃圾,并且不会自动入池,用户可以使用intern()方法手动入池。

五、字符串不可变更

字符串一旦定义不可变更。

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

范例:

public class TestDemo1 {
    public static void main(String[]args){
       String str = "Hello";
       str += "World";
       str = str + "!!!";
        System.out.println(str);
    }
}

结果:
 

HelloWorld!!!

通过内存图分析一下:

通过以上分析可知,字符串内容的更改,其实是改变的字符串对象的引用,并且伴随着大量的垃圾在实际开发中应该避免。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值