• JAVA基础学习之路(八)[1]String类的基本特点


    String类的两种定义方式:

    1. 直接赋值

    2. 通过构造方法赋值 

    //直接赋值
    public class test2 {
        public static void main(String args[]) {
            String str = "hello"; 
            System.out.println(str);
        }    
    }
    
    
    //通过构造方法
    public class test2 {
        public static void main(String args[]) {
            String str = new String("hello");
            System.out.println(str);
        }    
    }

    但是,两种方法却有着极大的区别

    主要体现在内存

    一个简单的例子:

    public class test1 {
        public static void main(String args[]) {
            int a = 10;
            int b = 10;
            String str_1 = "hello";
            String str_2 = "hello";
            String str_3 = new String("hello");
            System.out.println(a==b);
            System.out.println(str_1==str_2);
            System.out.println(str_1==str_3);
            System.out.println(str_2==str_3);    
        }
    }   //输出为true true  false false

    按道理来说,应该是四个true,因为他们的值都是相等的啊.......但是.....

    上图解释了两个通过直接赋相同值产生的字符串使用“”==“”为什么返回true。

    为什么会全部指向一块堆内存而不是分别指向自己的堆内存呢???

    共享设计模式:

    在JVM底层有一个对象池,里面有包括String在内的许多对象,当代码之中使用了直接赋值的方式定义了一个String类对象时,会将此字符串使用的匿名对象加入对象池。之后若有采用直接赋值的方式定义字符串,并且赋了相同的值,那么不会开辟新的堆内存空间,而是使用已有的对象(堆内存)进行继续使用。

    上图解释了为什么直接赋值和构造方法赋相同的值,然而返回值却为false。因为使用构造方法定义字符串,使用了new关键字,意味着产生一块新的堆内存。那么两种方法各自开辟了一块堆内存,“==”符号对于字符串来说,比较的是地址值。两块堆内存的地址不同,所以返回值为false。

    若要比较字符串的内容,而不是地址,应该使用str_a.equals(str_b)

    字符串常量就是String类的匿名对象,所谓的直接赋值实际上就是为匿名对象加了一个名字。但是String类的匿名对象是由系统自动生成的,不用用户自己创建

    public class test1 {
        public static void main(String args[]) {
            String str = "hello";
            System.out.println("hello".equals(str));    
        }
    }
    //返回值为true

    tips:

    防止空指向异常(使用了未实例化的对象):将字符串写在输入的前面

    public class test1 {
        public static void main(String args[]) {
            String input = null;
            System.out.println(input.equals("hello"));    
        }
    }
    //Exception in thread "main" java.lang.NullPointerException
        at test.test1.main(test1.java:6)  空指向异常
    
    
    public class test1 {
        public static void main(String args[]) {
            String input = null;
            System.out.println("hello".equals(input));    
        }
    }
    //false

    两种定义方法的优劣:

    直接赋值节约空间

    然而构造方法却会产生大量垃圾,如下图:

    代码从右向左看,产生的第一块堆内存会成为垃圾

    构造方法实例化的方法除了浪费内存外,其定义的对象不会保存在对象池之中,若要保存,需要手动入池(使用inner()方法)

    public class test1 {
        public static void main(String args[]) {
            String str_1 = new String("hello").intern();
            String str_2 = "hello";
            System.out.println(str_1==str_2);    
        }
    }
    //true

    返回值为true,证明入池成功。

  • 相关阅读:
    大牛总结的Linux提权Exp合集
    CTF中图片隐藏文件分离方法总结
    解压报错gzip: stdin: not in gzip format tar: Child returned status 1 tar: Error is not recoverable: exiting now的解决方法
    CTF中常见Web源码泄露总结
    解决“当前扩展缓存策略没有进行注册”的错误
    【红色警报】XXE 高危漏洞将大面积影响微信支付安全,可能导致系统沦陷,请升级你的系统!
    Senparc.Weixin SDK v5.0 升级公告
    使用 VSTS 进行 CI 的过程中,无法识别 .NET Core 2.x 的情况处理
    .net core DI 注册 Lazy<> 类型
    【备忘】ASP.NET MVC 5 升级到 ASP.NET Core MVC 的部分变化
  • 原文地址:https://www.cnblogs.com/xhnxhnu/p/9129101.html
Copyright © 2020-2023  润新知