Java中的String类的学习

一、String类对象的实例化方式

1.直接使用"" 定义字符串赋值给String类的对象

2.使用String类中的构造方法:public String(String str);

public class StringDemo{
    public static void main(String args[]){
        String str="Hello world!";  //直接赋值实例化String类的对象
        String str=new String("Hello world!"); //通过String类的构造方法实例化String类的对象
        System.out.println(str);
    }    
}

二、String类对象的比较问题

1、==操作符——比较两个对象的内存地址,并未比较两个字符串的数值

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

2、equals方法——比较两个字符串的内容(public boolean equals(String other))

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

严格来说,equals比较的是堆内存中的内容

面试题:请解释String的两种比较方式?

  • "=="比较的是两个字符串的内存地址的数值,属于数值比较
  • equals()比较的是两个字符串的内容

注意:一个字符串常量是String的匿名对象

java中String并不是一个基本数据类型,所以Java会自动把一个字符串常量当成一个String类的匿名对象来处理

public class StringDemo{
    public static void main(String args[]){
        String str="Hello";
        
        System.out.println("Hello".equals(str); //true
    }    
}

小技巧:开发中使用以下方式可以避免NullPointException

例如:

public class StringDemo{
    public static void main(String args[]){
        String str="null";        
        System.out.println(str.equals("Hello"); 
    }    
}

会产生空指针异常NullPointException

改进: 通过字符串常量调用equals()方法,该常量永远不会是null,所以可以避免空指针异常

public class StringDemo{
    public static void main(String args[]){
        String str="null";        
        System.out.println("Hello".equals(str)); 
    }    
}

3、两种实例化方法的比较

1)java的共享设计模式

共享设计是在JVM中为用户提供一个对象池,当用户创建了一个 新的且池中没有的对象时,处理将这个对象分配内存之外,还会在对象池中进行保留,以后如果有其他对象社么了与之一样的内容时候,不会重复申明,而是从对象池中取出内容继续使用,String类正是使用该机制。

当用户采用直接赋值实例化String对象的时候,如果是第一次定义,则会自动将对象内容保留在字符串对象池中,以后如果其他的字符串对象依然采用直接赋值的话,可以直接通过对象池取出已经保存的内容继续使用,而不会重新开辟新的空间,如以下程序:

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

其内存关系为

2)通过String类的构造方法

但通过该法创建的String对象的内容不能自动入池,

但用户可以使用String类中的intern()方法手工入池。例如:

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

但是:

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

面试题:String对象的两种实例化方式的区别?

  • 直接赋值:只开辟一个堆内存空间,而且采用共享设计模式,可以自动入池,以备下次对象继续使用
  • 构造方法:开辟两个内存空间,其中一块将成为垃圾,且不会自动入池,但可以采用intern()方法继续手工入池

4、字符串的内容一旦声明则不可改变

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

其内存空间变化如下

 可以看出实际上对于String中的字符串内容并没有发生任何的变化,而最后内容的改变实际上改变的是String对象的内存地址的指向,所以字符串内容依然没有任何变化,但这样会产生大量的垃圾,所以在开发中对以下代码必须要进行回避:

public class StringDemo{
    public static void main(String args[]){
        String str="";
        for(int x=0; x<1000;x++){
            str += x;
        }
        System.out.println(str); 
    }    
}

相当于“断开-连接”1000次,且产生大量的垃圾空间;在实际开发中,可以用StringBuffer来实现上述代码功能,而不产生大量垃圾。

原文地址:https://www.cnblogs.com/JoannaQ/p/2651789.html