String类

本文详细探讨了Java中String类的常量表示及其匿名对象特性,解释了通过直接赋值和构造方法两种不同方式实例化String对象的区别。直接赋值方式仅创建一个对象并能自动保存到字符串池,而构造方法则会导致两个对象,但可以通过intern()方法手动入池。同时,介绍了Java的静态常量池和运行时常量池的概念,以及它们在程序加载和字符串比较中的作用。
摘要由CSDN通过智能技术生成


String类常量

字符串常量是String类的匿名类对象。

在程序的开发中,任何一个整数都是int类型,任何一个小数都是double类型,但是对于字符串而言,程序之中不会提供有字符串这样的基本数据类型,那么可以提供的只是String类,所以任何使用“"”定义的常用类实际上都是描述的一个String类的匿名对象

public class JavaDemo {
    public static void main(String[] args) {
        String s1 = "123";
        System.out.println("123".equals(s1));
    }
}

字符串常量“123”可以调用equals方法,说明“123”常量是一个String的匿名对象。

equals()方法里面提供有一个回避null的判断,所以如果将字符串常量写在前面,那么调用equals()方法的时候永远都不可能出现“NullPointerException”,字符串常量一定是一个匿名对象,一定具有堆内存地址。

String类两种实例化方式区别

String类对象有两种实例化方式,分析这两种实例化方式的区别:

1. 分析直接复制的对象实例化方式;

public class JavaDemo {
    public static void main(String[] args) {
        String s1 = "123";
    }
}

这种情况下,只会开辟一块堆内存空间。

利用直接复制实例化String的形式还可以实现同一个字符串对象数据的共享。

public class JavaDemo {
    public static void main(String[] args) {
        String s1 = "123";
        String s2 = "123";
        System.out.println(s1 == s2); //地址比较
    }
}

此时程序返回“true”,我们可以得出结论,这两个对象所指向同一块堆内存。

这时我们可以提出一个疑问:s1和s2是两个不同的匿名对象,为什么他们的堆内存地址会相同呢?

在这里我们引入一个String类池的概念。

当一个String类的匿名对象被实例化的时候,在堆地址中不会直接存一个字符串,而是存在有一个String类池(类似数组),当String类池中没有数据时,会将数据保存在String类池中,而String类池中有数据的时候,该String类的栈地址会直接指向String类池的那一部分。

先看一段代码:

public class JavaDemo {
    public static void main(String[] args) {
        String strA = "mldn";
        String strB = "mldnjava";
        String strC = "mldn";
        System.out.println(strA == strC); //地址比较
    }
}
true

底层运行的具体步骤是:

  1. strA的匿名对象被实例化,此时String类池没有“mldn”的数据,所以将“mldn”的数据存入String类池;
  2. strB的匿名对象被实例化,此时String类池中没有“mldnjava”的数据,所以将“mldnjava”的数据存入String类池;
  3. strC的匿名对象被实例化,此时String类池中已存在“mldn”的数据,所以strC 的栈内存直接指向String类池中“mldn”部分的堆内存。

图例分析:

在采用直接复制的处理过程中,对于字符串而言可以实现池数据的自动保存,当有相同数据定义时可以减少对象的产生,以提升我们的操作性能。

对于equals来说只要字符串相等其返回值都为true

2. 分析构造方法实例化

public class JavaDemo {
    public static void main(String[] args) {
        String str = new String("mldn");
    }
}

此时会开辟两块内存空间,而后只会使用一块,而另外一块由字符串常量所定义的匿名对象将称为我们的垃圾空间。

public class JavaDemo {
    public static void main(String[] args) {
        String strA = "mldn";
        String strB = new String("mldn");
        System.out.println(strA == strB);
    }
}
false

在这里插入图片描述
在使用构造方法实例化String对象时不会自动出现保存到字符串池的的处理。

根据上代码可知strB的开辟的内存不再String类池中。

手工入池

public class JavaDemo {
    public static void main(String[] args) {
        String strA = "mldn";
        String strB = new String("mldn").intern();
        System.out.println(strA == strB);
    }
}
true

在使用构造方法定义对象之后由于使用了intern()方法,所以即使时构造出来的String类对象的内容也可以实现对象池的管理。

面试题:请解释String类对象实例化方式的区别?

  • 直接赋值:只会产生一个实例化对象,并且可以自动保存到对象池之中,以实现该字符串实例的重用。
  • 构造方法:会产生两个实例化对象,并且不会自动入池,无法实现对象重用,但是可以利用intern()方法手工入池处理。

String对象(常量)池

对象池的主要目的时实现数据的共享处理。以String对象池为例,里面的内容主要就是为了重用,而重用实际上就属于共享设计,但是在Java之中对象(常量)池实际上可以分为两种:

  • 静态常量池:指的是程序(*.class)在加载的时候会自动将此程序之中保存的字符串、普通的常量、类和方法的信息等等,全部进行分配;
  • 运行时常量池:当一个程序(*.class)加载之后,里面可能有一些变量,这个时候提供的常量池。

范例:观察一个程序(静态常量池)

public class JavaDemo {
    public static void main(String[] args) {
        String strA = "www.mldn.cn";
        String strB = "www." + "mldn." + "cn";
        System.out.println(strA == strB);
    }
}
true

本程序中所给出的内容全部都是常量数据(字符串的常量都是匿名对象),所以最终在程序加载的时候会自动帮助开发者处理好相应的连接。

案例:观察另外一种情况

public class JavaDemo {
    public static void main(String[] args) {
        String info="mldn";
        String strA = "www.mldn.cn";
        String strB = "www." + info + "cn";
        System.out.println(strA == strB);
    }
}
false

这时候之所以是一个false,是因为程序在加载的时候并不确定info是什么内容,因为在进行字符串的连接的时候info采用的是一个变量,变量的内容是可以修改的,所以它不认为最终的strB的结果就是一个所需的最终的结果。

所以在比较两个字符串的内容时,使用equals()方法进行修改;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值