包装类和String类型的相互转换

包装类

JDK5以前需要我们手动装箱和拆箱
装箱就是基本数据类型转换成包装类型
拆箱就是包装类型转换成基本数据类型

自动装箱底层使用的是Integer.valueOf()方法

自动拆箱底层使用的是intValue()方法

package com.example.wrapper_;



/**
 * @Author 郜庆辉
 * @Time 2022/5/10 16:30
 * @Version 1.0
 */
public class Integer01 {
    public static void main(String[] args) {

        // JDK5以前需要我们手动装箱和拆箱
        // 装箱就是基本数据类型转换成包装类型
        // 拆箱就是包装类型转换成基本数据类型

        //手动装箱
        //int -> Integer
        int n1 = 100;
        Integer integer = new Integer(n1);
        Integer integer1 = Integer.valueOf(n1);

        //手动拆箱
        //Integer -> int
        int i = integer.intValue();


        //JDK5之后是自动装箱和拆箱
        //自动装箱底层使用的是Integer.valueOf()方法
        //自动装箱
        int m = 10;
        Integer integer2 = m;      //底层使用的是Integer.valueOf(m)

        //自动拆箱底层使用的是intValue()方法
        int m1 = integer2;  //底层使用的是intValue()方法
    }
}

包装类型和String类型的相互转换

package com.example.wrapper_;


import java.awt.geom.Arc2D;

/**
 * @Author 郜庆辉
 * @Time 2022/5/10 21:35
 * @Version 1.0
 */
public class WrapperVSString {
    public static void main(String[] args) {

        //包装类(Integer) -> String

        Integer i = 100;    //自动装箱
        //方式1
        String str1 = i + "";
        //方式2
        String str2 = i.toString();
        //方式3
        String str3 = String.valueOf(i);

        // String ->  包装类(Integer)
        String str4  = "1234";

        Integer i1 = Integer.parseInt(str4);    //使用到自动装箱
        Integer i2 = new Integer(str4); //构造器

        System.out.println("ok");

        //包装类(Double) -> String
        Double k = 100.0;
        String str5 = k + "";
        String str6 = k.toString();
        String str7 = String.valueOf(k);

        // String ->  包装类(Double)
        Double d1 = Double.parseDouble(str4);
        Double d2 = new Double(str4);
        System.out.println(d1 + " " + d2);
    }
}

Integer面试题

package com.example.wrapper_;


/**
 * @Author 郜庆辉
 * @Time 2022/5/10 22:23
 * @Version 1.0
 */
public class WrapperExercise01 {
    public static void main(String[] args) {


        Integer i = new Integer(1);     //这里是创建了两个不同的对象,返回F
        Integer j = new Integer(1);
        System.out.println(i == j);

        /*
          //我们来看一下valueOf的源码
          1.如果 i 在 IntegerCache.low(-128)~IntegerCache.high(127),就直接从数组返回
          2.如果不在 -128~127,就直接 new Integer(i)

            public static Integer valueOf(int i) {
                if (i >= IntegerCache.low && i <= IntegerCache.high)
                    return IntegerCache.cache[i + (-IntegerCache.low)];
                return new Integer(i);
            }
         */

        //主要看范围,如果范围是-128-127就直接返回,如果不再这个范围内就创建新的对象就 new Integer(xx);
        //m和n是1,所以直接返回不需要创建对象,结果为T
        Integer m = 1;     //底层是Integer.valueOf(1)
        Integer n = 1;     //底层是Integer.valueOf(1)
        System.out.println(m == n);

        Integer x = 128;            //超过上面所说的范围,新创建两个对象,两个对象肯定为F
        Integer y = 128;
        System.out.println(x == y);

    }
}
package com.example.wrapper_;

/**
 *	Integer面试题
 * @Author 郜庆辉
 * @Time 2022/5/11 0:21
 * @Version 1.0
 */
public class WrapperExercise02 {
    public static void main(String[] args) {
        //示例一:只要是创建两个对象的,都不相等
        Integer i1 = new Integer(127);
        Integer i2 = new Integer(127);
        System.out.println(i1 == i2);//F
        
		//示例二
        Integer i3 = new Integer(128);
        Integer i4 = new Integer(128);
        System.out.println(i3 == i4);//F
        
		//示例三:没创建对象的就看范围是否超出,超出也是自动创建对象,不超出就值比较
        Integer i5 = 127;//底层 Integer.valueOf(127)
        Integer i6 = 127;//-128~127
        System.out.println(i5 == i6); //T
        
		//示例四
        Integer i7 = 128;
        Integer i8 = 128;
        System.out.println(i7 == i8);//F
        
		//示例五
        Integer i9 = 127; //Integer.valueOf(127)
        Integer i10 = new Integer(127);
        System.out.println(i9 == i10);//F
        
		//示例六
        Integer i11=127;
        int i12=127;
        
        //只要有基本数据类型,判断的是值是否相同
        System.out.println(i11==i12); //T
		//示例七
        Integer i13=128;
        int i14=128;
        System.out.println(i13==i14);//T
    }
}

String类

1.String对象用汉语保存字符串,也就是一组字符序列

2."tom"是字符串常量,双引号括起来的字符序列

3.字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节

4.String类有很多构造器
常用的有:
String s1 = new String();
String s2 = new String(String original);
String s3 = new String(char[] a);
String s4 = new String(char[] a,int startIndex,int count);
String s5 = new String(byte b);

5.String类实现了接口Serializable 【String 可以串行化:可以在网络传输】
String类实现了接口Comparable 【String对象可以比较大小】

6.String是final类,不能被继承

7.String有属性private final char value[];用于存放字符串内容,可以说String本质就是char数组

8.一定要注意:value是一个final类型,不可以被修改,
这里不可以被修改是value不可以指向新的地址,字符串里面的单个字符是可以修改的

两种创建String对象的区别:

  1. ​ 直接赋值String s = hsp";
  2. 调用构造器String s2 = new String("hsp");

1.方式一:先从常量池查看是否有“hsp”数据空间,如果有就直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池中的空间地址

2.方式二:先在堆中创建空间,里面维护了value属性,指向常量池中的hsp空间。如果常量池没有“hsp”,重新创建,如果有,直接通过value指向。s2最后指向的是堆中的空间地址

下面是String比较的练习题:

package com.example.string_;

/**
 * @Author 郜庆辉
 * @Time 2022/5/11 17:17
 * @Version 1.0
 */
public class StringExercise01 {
    public static void main(String[] args) {
        //a直接指向常量池的"gqh"地址
        String a = "gqh";

        //b指向堆中的对象地址,而堆中的对象value指向常量池的"gqh"
        String b = new String("gqh");
        
        //String类将equals方法重写,比较的是字符串中的字符是否相等,结果为T
        System.out.println(a.equals(b));
        
        //a指向的是常量池的地址,b指向的是堆中的地址,结果为F
        System.out.println(a == b);
        
        //a指向是常量池的地址,b.intern()方法最终返回的时常量池的地址(对象),结果为T
        System.out.println(a == b.intern());
        
        //b是堆的地址,b.intern()方法最终返回的时常量池的地址(对象),结果为F
        System.out.println(b == b.intern());
        /*
        知识点:
        当调用intern方法时,如果常量池已经包含一个等于此String对象的字符串(用equals(Object)方法确定),
        则返回常量池中的字符串。否则,将此String对象添加到常量池中,并返回此String对象的引用。
        解读:b.intern()方法最终返回的时常量池的地址(对象)
         */
    }
}

下面是String比较的练习题2:

package com.example.string_;

/**
 * @Author 郜庆辉
 * @Time 2022/5/11 17:44
 * @Version 1.0
 */
public class StringExercese02 {
    public static void main(String[] args) {
        //创建一个由p1指向的Person对象
        Person p1 = new Person();

        //p1.name = "gaoqinghui" 表示在常量池中创建了一个gaoqinghui的数据空间,由p1的对象中的value属性指向这个数据空间
        p1.name = "gaoqinghui";

        //创建一个由p2指向的Person对象
        Person p2 = new Person();

        //p2.name = "gaoqinghui" 表示由p2的对象中的value属性指向刚才p1创建的gaoqinghui的数据空间,现在p1和p2的value都指向这个数据空间
        p2.name = "gaoqinghui";

        //比较的是字符串是否相等,结果为true
        System.out.println(p1.name.equals(p2.name));

        //现在p1.name和p2.name都指向的是常量池中的同一个存放gaoqinghui的数据空间
        System.out.println(p1.name == p2.name);

        //p1.name指向的是存放gaoqinghui的地址空间,而后面比较的gaoqinghui字符串是一个常数,不是new出来的,所以他本身就在常量池中,结果为true
        System.out.println(p1.name == "gaoqinghui");

        //不是同一个对象,比较结果为false
        String s1 = new String("bcde");
        String s2 = new String("bcde");
        System.out.println(s1 == s2);
    }
}
class Person {
    public String name;
}

面试题1:

下面语句是什么意思:创建了几个对象

String s1 = "hello";
s1 = "haha";

解读:创建了两个对象

  1. String是一个final类,代表不可变的字符序列
  2. 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。

String s1 = "hello";先在常量池中创建了一个”hello”的地址空间,

然后又执行s1 = “haha”,底层会在常量池中寻找是否有haha这个地址空间,如果有的话就让s1指向它,如果没有的话就创建一个haha地址空间让s1指向。s1指向新的haha这个地址空间,s1就不指向“hello”;

面试题2:

下面语句创建了几个对象

String a = "hello" + "abc";

答:创建了一个对象;

编译器会自动帮我们优化

String a = "hello" + "abc"; 等价于String a = "helloabc";

面试题3:

package com.example.string_;

import javax.print.DocFlavor;

/**
 * @Author 郜庆辉
 * @Time 2022/5/11 18:23
 * @Version 1.0
 */
public class StringExercise03 {
    public static void main(String[] args) {
        //解读:
        //1.先创建一个StringBuilder sb = StringBuilder()
        //2.执行sb.append("hello");
        //3.sb.append("abc");
        //4.String c = sb.toSting()
        //最后其实是c指向堆中的对象(String) value[] -> 池中 "helloabc"
        String a = "hello";
        String b = "abc";
        String c = a + b;
        //一共有3个对象
        //底层是StringBuilder sb = new StringBuilder(); sb.append(a);
        //sb.append(b); sb是在堆中,并且append是在原来字符串的基础上追加的
        // 重要规则:
        // Sting c1 = "ab" + "cd";是常量相加,看的是池
        //String c1 = a + b;变量相加,是在堆中

    }
}

分析下面代码的流程:面试题

package com.example.string_;

/**
 * @Author 郜庆辉
 * @Time 2022/5/12 15:16
 * @Version 1.0
 */
public class StringExercise04 {
    public static void main(String[] args) {
        //对下面的代码进行分析
        /*
        主方法main在堆中创建了一个用test1引用的对象,Test1对象中有一个str成员属性指向堆中的另一个String对象,String中有个value属性指向的是常量
        池中的"gqh"常量。test1中还有一个char类型的数组,ch指向这个数组,这个数组的存储位置在堆中的另一个空间。
        这时主方法调用了change方法,我们已经知道main方法在栈中,只要我们调用方法时就会在栈中创建一个空间存放方法。
        这时change方法中的str指向的就是String对象中的value属性。
        ch指向的也是刚才我们创建的ch数组
        str = "java"; 当执行这句话时,str就直接指向的时常量池中的“java”常量对象空间,如果没有"java"常量对象空间则创建,
        这时我们原来str指向的哪个String对象的value属性断开。
        ch[0] = 'h';我们知道这个数组是final的,地址不可修改,但是我们这个直接修改的就是堆中的字符串数组的单个元素。
        当我们在主函数中输出时,test1.str输出的main方法栈中的str,main方法的str指向的还是哪个String对象,输出的还是原来的”gqh“
        而输出test1.ch时,由于ch和test1.ch指向的都是同一个字符串数组,输出的是已经改的的”hava“

        总结:main栈中的str指向的是String对象的value属性。 change栈指向的直接就是常量池的"java";两者指向的并不一样,输出的也不一样
            而main栈和change栈指向的都是同一个数组。前者是指向的是String对象的ch对象指向的数组,后者直接指向的就是数组,两者一样

         */
        Test1 test1 = new Test1();
        test1.change(test1.str, test1.ch);
        System.out.print(test1.str + " and " );
        System.out.println(test1.ch);
    }
    
}

class Test1 {
    String str = new String("gqh");
    final char[] ch = {'j','a','v','a'};

    public void change(String str,char ch[]){
        str = "java";
        ch[0] = 'h';
        
    }
}

StringBuffer类

java.lang.StringBuffer代表可变的字符序列,可以堆字符串内容进行增删
很多方法与String相同,但StringBuffer是可变长度的

StringBuffer是一个容器

1.StringBuffer的直接父类是AbstractStringBuilder

2.StringBuffer实现了Serializable,即StringBuffer的对象可以串行化

3.在父类中,AbstractStringBuilder有属性char[] value,不是final该value数组存放字符串内润,因此存放在堆中

4.StringBuffer是一个final类,不能被继承

5.因为StringBuffer字符内容是存在 char[] value,所有在变化(增加/删除)的时候不需要每次都更换地址(即不是每次创建新的对象),因为效率高于String

String VS StringBuffer

1)String保存的字符串常量,里面的值不能更改,每次String类的更新实际上就是更改了地址(相当于创建了新的对象),效率低。private final char value[];

2)StringBuffer保存的是字符串变量,里面的值可以修改,每次StringBuffer的更新实际上可以更新内容,不需要每次更新地址。但是如果数组满了,也需要重新创建对象(更新地址); char[] value; 这个value是指向堆中的。

3)如果创建一个String对象,堆中的value属性是指向常量池的。

4)如果创建一个StringBuffer对象,堆中的value属性是指向堆中的。

创建StringBuffer

//1.默认方法里什么都没有的话就创建一个大小为16的char[],用于存放字符内容,大小是16
StringBuffer stringBuffer = new StringBuffer();

//2.通过构造器传进去一个100就是给char[]数组指定大小。char[]大小就是100
StringBuffer stringBuffer1 = new StringBuffer(100);

//3.通过传一个字符串创建StringBuffer,char[]的大小就是你传入的字符串的长度 + 16 就是str.length + 16
StringBuffer stringBuffer2 = new StringBuffer("hello");

String和StringBuffer的相互转换

// String -> StringBuffer

String str = "hello";
//方法一:使用构造器
//注意:返回的才是StringBuffer对象,对str本身没有影响
StringBuffer stringBuffer = new StringBuffer(str);

//方式二:使用的是append方法
StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1 = stringBuffer1.append(str);

// StringBuffer -> String
StringBuffer stringBuffer2 = new StringBuffer("郜庆辉牛逼");
//方式一:使用StringBuffer提供的toString方法
String s = stringBuffer2.toString();

//方式二:使用构造器
String s1 = new String(stringBuffer2);

StringBuffer的常用方法

package com.example.stringbuffer_;

/**
 * @Author 郜庆辉
 * @Time 2022/5/12 21:13
 * @Version 1.0
 */
public class StringBufferMethod {
    public static void main(String[] args) {

        StringBuffer s = new StringBuffer("hello");

        //增
        s.append(",");
        s.append("张三丰");
        s.append("郜庆辉");
        s.append("赵敏").append("100").append("生活").append(10.2);
        System.out.println(s);  //这里直接调用s这个对象的引用是默认调用对象的toString方法

        //hello,张三丰郜庆辉赵敏100生活10.2

        //删
        //删除索引为>=start && <end处的字符
        //删除11-14之间的字符,包括11,不包括14 [11,14)
        s.delete(11,14);
        System.out.println(s);
        //hello,张三丰郜庆100生活10.2

        //改
        //使用周芷若替换索引为6-9之间的字符,前闭后开  [6-9)
        s.replace(6,9,"周芷若");
        System.out.println(s);
        //hello,周芷若郜庆100生活10.2

        //查
        //查找指定的字串在字符串第一次出现的索引,如果找不到返回-1
        int indexOf = s.indexOf("周芷若");
        System.out.println(indexOf);
         //6

        //插
        //在索引11的位置之前插入辉,原来索引为11的位置自动后移
        s.insert(11, "辉");
        System.out.println(s);
        //hello,周芷若郜庆辉100生活10.2

        System.out.println(s.length());
        System.out.println(s);
    }
}

StringBuilder类

  1. 一个可变的字符序列,此类提供一个与StringBuffer兼容的API,但不保证同步(StringBuilder不是线程安全)。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。
  2. 在StringBuilder上的主要操作时append和insert方法,可重载这些方法,以接受任意类型的数据。

String、StringBuffer和StringBuild的比较

  1. StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而且方法也一样
  2. String:不可变字符序列,效率低,但是复用率高;
  3. StringBuffer:可变字符序列,效率较高(增删)、线程安全;
  4. StringBuilder:可变字符序列,效率最高,线程不安全;

String的使用注意说明:

String s = “a”;//创建了一个字符串
    
s += “b”;  		
//实际上原来的“a”字符串对象已经丢弃了,现在又产生了一个字符串s + “b”(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能;

结论:如果我们对String做大量修改,不要使用String
    

String、StringBuffer和StringBuild的选择

使用的原则,结论:

1.如果字符串存在大量的修改操作,一般使用StringBuffer或StringBuilder

2.如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder

3.如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer

4.如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毕业_设计

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值