java—String

3 篇文章 0 订阅
String对象的创建有两种方式
  String s1 = "hello";
  String s2 = new String("hello");

这两种方式有什么区别呢?

推荐:https://www.zhihu.com/question/22739143   

String中,native方法Intern()是关键

对于String的Intern()的分析:https://www.cnblogs.com/wxgblogs/p/5635099.html

                                                    https://www.cnblogs.com/guozhenqiang/p/5633269.html

     可以发现java7后,Interned String从PermGen挪到Heap堆。

    关于JVM内存的分区情况推荐大家查阅《深入理解Java虚拟机[JVM高级特性与最佳实践](周志明)》的第2.2章节。

    相信大家已经基本清楚区别啦,现在知道

String s2 = new String("hello");

       会创建几个对象了吗?如果常量池中没有“hello”,会创建两个,是字符串常量池中的“hello 和 JAVA Heap中的 s2引用指向的对象

如何使s3与s1、s2是同一个"hello"的引用?

public class Main {

    public static void main(String[] args) throws InterruptedException {

        String s3 = new String("hel") + "lo" ;
        s3.intern();
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
    }
}

执行结果:

true

true

public class Main {

    public static void main(String[] args) throws InterruptedException {

        String s1 = "hello";
        String s3 = new String("hello") ;
        s3.intern();
        System.out.println(s1 == s3);
        s3 = s3.intern();
        
        String s2 = "hello";
        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
    }
}

运行结果:

false
true
true

总结一下Stirng的对象创建:

1.String s1 = "hello"这种赋值,会在常量池去寻找引用

        需要知道:因为String类为final的,“hello”的引用会在类被加载的时候被放到字符串常量池中,“hello”被放在了堆中的Eden区,在执行前,s1还未“连接”上“hello”。当要运行创建s1时,先查看字符串常量池里面有没有对象“hello”的引用,加载的时候被放进来了,找到后,把这个引用赋值给s1完成创建

2.String s3 = new String("hello") 会在java堆上会创建一个对象,其次如果常量池中没有“hello“,会在常量池中创建"hello"的引用, 在堆上放上“hello”字符串

 如果把常量池中的引用的String对象用作了同步对象,一定要小心

class B extends Thread{

    public void run(){
        synchronized ("hello"){
            System.out.println("进入B,持有字符串hello锁");
            while(true);
        }
    }
}

class C extends Thread{
    public void run(){
        System.out.println("C试图去获得字符串hello锁");
        //与B中获取的是常量池中的同一个hello,B未释放,一直不能获取到阻塞
        synchronized ("hello"){
            System.out.println("进入C,持有字符串hello锁");
        }
    }
}

public class Main {

    public static void main(String[] args) throws InterruptedException {
        B b = new B();
        C c = new C();
        b.start();
        Thread.sleep(1000);
        c.start();
    }
}

运行结果:

进入B,持有字符串hello锁

C试图去获得字符串hello锁

 B和C中的“hello”字符串都是常量池中的同一个

      String类因为是final修饰的,所以不能被继承。String对象被创建后是不可变的,String类中每一个看起来会修改String值的方法,实际上都是创建了一个全新的String对象,最初的String对象丝毫不动

public class Main {

    public static void main(String[] args) throws InterruptedException {
        String s = "hello";
        String s2 = s;
        System.out.println(s == s2);

        s2 = "world";
        System.out.println(s == s2);
    }
}

运行结果:

true
false

     String的连接可以通过“+”“+=”实现,而编译器自动为这项工作引用了StringBuilder类。StringBuilder可以通过append方法连接,最后通过toString()方法最终结果,所以如果有循环去连接一个长字符串,应该这样写:

    public String add(String[] fields){
        StringBuilder result = new StringBuilder();
        for(int i = 0; i < fields.length; i++){
            result.append(fields[i]);
        }
        return result.toString();
    }

而不应该这样写:

    public String add(String[] fields){
        String result = "";
        for(int i = 0; i < fields.length; i++){
            //因为使用了‘+=’去连接,每一次循环编译器都会创建新的StringBuilder对象
            result += fields[i];
        }
        return result;
    }
避免无意识的递归

   所有类都继承于Object类,现在我们想打印对象的地址,如下:

class D{
    public String toString(){
        return "address" + this ;
    }
}

public class Main {

    public static void main(String[] args) throws InterruptedException {
        D d = new D();
        System.out.println(d);
    }
}

        运行后,会出现java.lang.StackOverflowError的异常,这是无限递归造成的。在D类中,重写了toString方法,想要通过this来返回对象的地址,但当"address"去连接this时,this发现是字符串,所以要将自己装换成Stirng,所以又调用了自己的toString,造成了无限递归。应该这样来做:

class D{
    public String toString(){
        return "address" + super.toString() ; ;
    }
}

public class Main {

    public static void main(String[] args) throws InterruptedException {
        D d = new D();
        System.out.println(d);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值