Java学习记录——DAY2

Q:char和String的区别。

A:

1、本质区别:

  • char 是基本数据类型,与byte,int,double,long,boolean,float,short相似。
  • String是一个

2、 深入了解具体区别

  • 把String当作是字符串和字符串类型都是不准确的。String其实相当与一个装char类型数据的容器类类型,实例化之后,它就是一个容器,用于盛放char类型的数据。
    String p = new String("123456");
    //该行代码的意思是实例了一个字符串容器p,里面装了“123456”
  • String类的一些补充知识:                                                                                                     1)String类是通过char数组来保存字符串的。                                                                       2)String类是final类,即String类不能被继承,其成员方法也都为final方法。                       3)String对象一旦被创建了就是固定不变的,无法被修改。任何change操作都会生成一个新的String对象。
  • ​​​​字符串常量池(Java中会使用常量池来存放数据以达到提高性能和减少内存开销的目的)字符串常量池顾名思义就是存放字符串的常量池。当我们创建字符串常量的时候,JVM会先检查字符串常量池里有没有相同的数据,有就返回常量池中该数据的实例引用;如果该常量不在字符串常量池里,JVM就会实例化该字符串并将其存放到常量池中。由于String的不可变性,字符串常量池里绝对不会出现两个完全相同的字符串。
  • 字面值方式赋值和使用new运算符赋值的区别
    //字面值方式赋值
    public void test1{
        String a = "123";
        String b = "123";
        System.out.println(a==b);
    }
    //运行结果为:true

    使用字面值方式赋值时,JVM会先去字符串常量池里查找是否有“123”这个对象,如果不存在就创建这个对象,如果存在就直接调用字符串常量池里的实例引用。应用到上面的例子就是:给a赋值的时候,字符串常量池里没有“123”这个对象,那么JVM就会在字符串常量池里创建“123”这个对象,然后将“123”这个对象的引用地址返回给字符串a,这样:变量a就会指向字符串常量池中的“123”。当给b赋值的时候,JVM发现字符串常量池中有“123”这个对象,因此把“123”的引用地址返回给变量b,这样:变量b就会指向字符串常量池中的“123”。由于变量a和变量b都指向同一个对象“123”,所以输出true。                                                                       

     

    //使用new运算符赋值
    public void test2{
        String c = new String('456');
        String d = new String('456');
        System.out.println(c==d);
    }
    //运行结果为false

    使用new运算符赋值时,JVM同样会先检查字符串常量池里是否有“456”这个对象,如果不存在就创建这个对象,如果存在就直接调用字符串常量池里的实例引用。但是由于new运算符是new出来一个新的对象,对象的不同会导致变量引用地址不同,即c==d的结果为false。应用到上面的例子就是:用new运算符给c赋值时,由于字符串常量池里没有“456”这个对象,那么JVM会先在字符串常量池里创建一个“456”对象,然后再在堆里创建一个“456”对象,将堆中的这个“456”对象返回给变量c引用,这样:变量c就指向了堆中创建的这个“456”对象。当用new运算符给d赋值时,由于字符串常量池中已经有“456”这个对象了,故只需要在堆中再创建一个“456”对象,并将这个对象返回给d引用,这样:变量d就指向了堆里的另一个“456”对象。由于变量c和变量d指向不同的对象,所以输出false。注意:使用String时不一定会创建一个新的对象,字符串常量池里不允许有两个相同的对象,当使用字面值赋值的方法时,如果字符串常量池中已经有该对象里但在堆里面,每new一次都会产生一个新的对象,与这个对象的内容是否相同无关,因此堆中可能会出现很多个内容相同的对象,但实际上它们都是不同的对象。

  • String的intern()方法:扩充常量池的一个方法。当一个String实例str调用intern()方法时,java查找常量池中是否有相同unicode的字符串常量,如果有,则返回其引用,如果没有,则在常量池中增加一个unicode等于str的字符串并返回它的引用。                                                       注意:只有 a.equals(b) 为 true 时,a.intern() == b.intern() 才为 true。

    public void test3(){
        String s0 = "kvill"; 
        String s1 = new String("jackson"); 
        String s2 = new String("jackson"); 
        System.out.println( s0 == s1 ); //false
        s1.intern(); //虽然执行了s1.intern(),但它的返回值没有赋给s1
        s2 = s2.intern(); //把常量池中"jackson"的引用赋给s2 
        System.out.println( s0 == s1); //flase
        System.out.println( s0 == s1.intern() ); //true//说明s1.intern()返回的是常量池中"jackson"的引用
        System.out.println( s0 == s2 ); //true
    }
  • equals()方法与“==”:                                                                                                                  (1)“==”用在数值类型的变量时,是比较两个变量的储存的值是否相同;用在引用类型的变量时,是比较两个变量的引用地址是否相同。                                                                            (2)equals()方法是用于比较两个变量的引用地址是否相同。(equals()方法不能用在数值类型变量的比较上)                                                                                                                       注意:Object类中equals()方法只能用于比较引用地址,但实际上在Object类的许多子类中都会对equals()方法进行重写String类中就对equals()方法进行重写,使其只用于比较字符串对象所存储的字符串是否相等,并不是比较其引用地址。同理,Double,Date,Integer等也对equals()方法进行重写,使其用于比较两个变量的内容是否相同。

    //“==”与equals()方法:
    public void test4(){
        String s1="hello";
        String s2="hello";
        String s3=new String("hello");
        System.out.println( s1 == s2); //true,表示s1和s2指向同一对象,它们都指向常量池中的"hello"对象
        System.out.println( s1 == s3);  //flase,表示s1和s3的地址不同,即它们分别指向的是不同的对象,s1指向常量池中的地址,s3指向堆中的地址
        System.out.println( s1.equals(s3)); //true,表示s1和s3所指向对象的内容相同
    }
  • String类中“+”运算符的具体实现:                                                                                              (1)Java编译时,会尽可能地把左起的字符串常量先连起来(直到遇到变量就停止),形成新的字符串常量参与后续连接。                                                                                                (2)接下来的字符串连接是从左向右依次进行,对于不同的字符串,首先以最左边的字符串为参数创建StringBuilder对象,然后依次对右边进行append操作,最后将StringBuilder对象通过toString()方法转换成String对象。

    //String类中“+”运算符的具体实现:
    public void test5(){
        String a = "aa";
        String b = "bb";
        String c = "xx" + "yy " + a + "zz" + "mm" + b;
        System.out.println(c);
    }

    实现方法:                                                                                                                          (1)先将“xx”和“yy”连接起来成为一个新的字符串常量,遇到变量a之后自动停止连接。        (2)接着,以“xxyy”为参数创建StringBuilder对象,然后依次对右边进行append操作,直到所有字符串都被连起来,最后使用toString()方法将StringBuilder对象转换为String对象。         注意:每做一次 + 就产生个StringBuilder对象,然后append后就扔掉。这样会导致连接字符串的过程中会有很多创建和销毁对象的操作,造成运行缓慢。如果我们直接采用 StringBuilder 对象进行 append 的话,我们可以节省 N - 1 次创建和销毁对象的时间。所以对于在循环中要进行字符串连接的应用,一般都是用StringBuffer或StringBulider对象来进行append操作。

  • String类中的final修饰词的理解:                                                                                              final只对引用的"值"(即内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。至于它所指向的对象的变化,final是不负责的。

    //String类中的final修饰词:
    final StringBuffer a = new StringBuffer("111");
    final StringBuffer b = new StringBuffer("222");
    a=b;//此句编译不通过 不能改变final变量的引用路径
    
    final StringBuffer a = new StringBuffer("111");
    a.append("222");//编译通过  可以改变final变量的具体内容
  • 补充:关于String str = new String("abc")创建了多少个对象?                                                   这段代码在执行的过程中,new只调用了一次,也就是说只创建了一个对象。而这道题目让人混淆的地方就是这里,这段代码在运行期间确实只创建了一个对象,即在上创建了"abc"对象。而为什么大家都在说是2个对象呢,这里面要澄清一个概念,该段代码执行过程类的加载过程是有区别的。在类加载的过程中,确实在运行时常量池中创建了一个"abc"对象,而在代码执行过程中确实只创建了一个String对象
    这个问题如果换成 String str = new String("abc")涉及到几个String对象?合理的解释是2个。而如果换成这段代码执行过程中创建了多少个对象?合理解释是1个。

本博客参考自:深入理解Java中的String_weixin_34117211的博客-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值