22-04-18 西安 javaSE(10)装箱拆箱、字符串与基本类型转换、String类、StringBuilder类、String类和包装类的笔试题

装箱与拆箱

包装类

包装类:基本类型对应的引用类型的类

基本类型: byte,short,int,        long  ,float,  double,    char,           boolean
对应包装类:Byte,Short,Integer,Long,Float,  Double,   Character,Boolean


包装类装箱

装箱:从基本类型转换为对应的包装类对象。
       1.以对应的基本类型为参数的构造器方式  Integer(int value) ,构造器2:Integer(String s)
       2.包装类型的静态方法:static Integer valueOf(int i)  
       3.自动装箱(jdk5.0之后有的,由jvm隐式进行操作)Integer i=5;【推荐】


包装类拆箱

拆箱:从包装类对象转换为对应的基本类型。
       1.包装类型的实例方法    int intValue() 
       2.自动拆箱  int value=new Integer(123);jdk5.0,由jvm隐式操作。【推荐】


基本类型---》字符串类型

基本类型转为字符串类型
       1.字符串连接符 String str1=123+“”;
       2.包装类的实例方法toString: String str2=new Integer(234).toString();
       3.包装类型的静态方法toString: String str3=Integer.toString(235);
       4.String的静态方法: String str4=String .valueOf(456) 【推荐


字符串类型---》基本类型

字符串类型转基本类型
       1.包装类型的构造器,再进行自动拆箱  int num01=new Integer(“123”)
       2.包装类型的静态方法  parseInt(String s) :   int num02= Integer.parseInt(“123”);【推荐】

注意事项:

Character的构造器只有:Character(char value) 。

Character类型没有提供字符串转char类型的方法

字符中内容必须在基本类型的取值范围内,否则发生数字格式化异常


包装类的笔试题1

当通过自动装箱方式的创建整数类的包装类对象,如果在-128-127,直接在整数常量池拿。不在的话再去堆里new

    public static void main(String[] args) {
        int num01=987;
        int num02=987;
        System.out.println(num01==num02);//true

        Integer num03=new Integer(654);
        Integer num04=new Integer(654);
        System.out.println(num03==num04);//false

        Integer num031=new Integer(120);
        Integer num041=new Integer(120);
        System.out.println(num031==num041);//false


//      当通过自动装箱方式的创建整数类的包装类对象,如果在-128-127,直接在整数常量池拿。不再的话再去堆里new
        Integer num05=321;
        Integer num06=321;
        System.out.println(num05==num06);//false

        Integer num07=123;
        Integer num08=123;
        System.out.println(num07==num08);//true

        Integer num09=200;
        int num10=200;
        System.out.println(num09==num10);//true 一切从简原则
        System.out.println(num10==num09);//true
    }

包装类的笔试题2

public class Demo {
    public static final Integer num01=200;
    public static final Integer num02=200;
    public static final Integer num03=100;
    public static final Integer num04=100;
    public static final Integer num05;
    public static final Integer num06;
    public static final Integer num07;
    public static final Integer num08;
    static{
        num05=200;
        num06=200;
        num07=100;
        num08=100;
    }
    public static void main(String[] args) {
//      比较的是引用类型,在-128-127,从整数常量池拿
        System.out.println(num03==num07);//true
//      比较的是引用类型,超过-128-127从堆里new
        System.out.println(num01==num02);//false
        System.out.println(num05==num06);//false
        System.out.println(num01==num05);//false

//      加法只能加基本类型,包装类型进行4则运算时,先进行自动拆箱再计算
        System.out.println(num01==(num03+num04));//true
        System.out.println(num05==(num07+num08));//true
    }
}

包装类的笔试题3

    public static void main(String[] args) {
//      在常量池中不存在浮点数。
        Double v01=0.0;
        Double v02=0.0;
        System.out.println(v01==v02);//false
//      字符常量池:存0-127 对应的字符。就是AscII码
        Character var03=129;
        Character var04=129;
        System.out.println(var03==var04);//false

        Character var031=127;
        Character var041=127;
        System.out.println(var031==var041);//true

//      布尔常量池:
        Boolean var05=true;
        Boolean var06=true;
        System.out.println(var05==var06);//true
    }

String类

创建String类对象

java.lang
第一种:字面值直接赋值。String str1="abc";
第二种:new的方式

    public static void main(String[] args) {
        //字面值直接赋值
        String str1="abc";
        //String() 无参构造器方式
        String str2=new String();创建长度为0的数组,类似于“”
        //字节数组方式【和环境编码有关】
        byte[] bytes={97,100,101};//字节是一个整数,一个汉字3个字节,一个英文一个字节
        String str3=new String(bytes);
        System.out.println("str3 "+str3);//ade
        //指定范围的字节数组方式
        byte[] bytes2={97,100,101,102};
        String str4=new String(bytes2,1, 2);
        System.out.println("str4 "+str4);//de
        //字符数组
        char[] chars={'a','b','c'};
        String str5=new String(chars);
        System.out.println("str5 "+str5);//abc
        //指定范围的字符数组方式
        char[] chars2={'a','b','c','d','e'};
        String str6=new String(chars2,1,2);
        System.out.println("str6 "+str6);//bc 从0索引开始
        //通过另外一个字符串对象创建副本
        String str7=new String("abc");//实际开发不用的

//        String(StringBuffer buffer)
//        String(StringBuilder builder)
    }

字符串数据结构

程序中所有的字符串字面值都是String类的对象,包括""

字符串是常量,它的值在创建后不能再变。
究其原因:String类的底层数据结构是一个被final修饰的数组

private final char value[];

String类底层数组的数据类型是什么:

  •      jdk 8.0前(包含jdk8.0),是char[]数组
  •      jdk 9.0后(包含jdk9.0), 是byte[]数组

char[]数组转为byte[]数组有什么好处?主要是节省字符串占用的内存空间

1、从时间复杂度:计算机中一切数据皆为字节。
如果是char[]数组,jvm底层会先将char[]数组的元素转换为字节,再由字节转为二进制位。
如果是是byte[]数组,jvm底层操作时会直接将byte[]数组中的元素转为二进制位/2

2从空间复杂度:占用内存越少越好
        2.1 如果是char[]数组,字符串存储“abc”,每个字母字符占用2个字节(按照内码标准),共占6个字节; 字符串存储“小羽毛”,每个汉字字符占用2个字节(按照内码标准),共占6个字节

        2.2如果是是byte[]数组,根据开发环境编码决定存储规则。字符串存储“abc”,开发环境为utf-8,在utf-8中每个字母字符占用1个字节,总共占用3个字节;   字符串存储“小羽毛”,开发环境为utf-8,在utf-8中每个汉字字符占用3个字节,总共占用9个字节。

String类为什么可以存储中文
            jvm的底层编码方式是utf-16,所以可以正常存储unicode码表中的中文。


字符串常量池

字符串常量是双引号引起的若干个字符。

从 Java 7 开始,为了解决永久代空间不足的问题,将字符串常量池从永久代中移动到

在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。

String str="小羽毛";//第一次
String str2="小羽毛";//不是第一次

第一次

字符串常量池没有这个”小羽毛“字符串对象,那么在堆中的字符串常量池中创建”小羽毛“字符串对象并把地址返回赋值给栈中的变量str;

不是第一次

字符串常量池有这个”小羽毛“字符串对象,直接将字符串常量池中这个 “小羽毛 的对象地址返回,赋值给栈中变量  str2

intern方法

如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。

String myInfo=new String("I love atguigu").intern();

也就是说,如果在任意字符串上调用intern()方法,那么其返回结果所指向的那个类实例,必须和直接以常量形式出现的字符串实例完全相同。

举例:如何保证栈帧中变量s指向的是字符串常量池中的数据呢?

有两种方式:
 //方式一:字面量定义的方式
 String s ="xiaoyumao";
 //方式二:调用intern(),不管前面是怎么花里胡哨的创建一个String对象
 String s = new String("xiaoyumao").intern();
 String s = new StringBuilder("xiaoyumao").toString().intern();

面试题举例:第一关

public static void main(String[] args) {
    //创建两个对象,一个是静态区的"1",一个是用new创建在堆上的对象。
    String s = new String("1");
    s.intern();//字符串常量池中已经有"1",所以调用该方法相当于没调
    String s2="1";
    System.out.println(s==s2);//不管哪个jdk版本都是false
}

===========

如果接收了intern()返回值

public static void main(String[] args) {
    String s = new String("1");
    //s.intern();//字符串常量池中已经有"1",所以调用该方法相当于没调
    s=s.intern();//如果是接收了返回值,那么返回值指向的才是字符串常量池的数据
    String s2="1";
    System.out.println(s==s2);
}

面试题举例:第二关

jdk6版本

public static void main(String[] args) {
    String s3 = new String("1")+new String("1");
    s3.intern();//字符串常量池中没有"11",jdk6 调用该方法会在常量池创建"11"
    String s4="11";
    System.out.println(s3==s4);//jdk6 s3指向的是堆中的11,s4指向的是字符串常量池的11,故为FALSE
}

jdk6下该运行结构是false

====

怎么就可能是true呢

String s3 = new String("1")+new String("1");
s3.intern();//字符串常量池中没有"11",jdk7/jdk8  调用该方法并没有在常量池中创建"11" 而是创建一个指向堆空间的地址
String s4="11";
System.out.println(s3==s4);//此时不会去常量池中创建“11”,而是s4指向常量池中存放s3地址的地方,所以为true


String笔试题1

常量区存储特点:一旦常量区中存在数据,不会创建第二遍,会拿已有的数据进行使用。

    public static void main(String[] args) {
        String str1=new String("HelloWorld");
        String str2=new String("HelloWorld");
        System.out.println(str1==str2);//false
        
        String str3="HelloWorld";
        String str4="HelloWorld";
        System.out.println(str3==str4);//true
        
        String str5=new String("Hello");
        String str6=new String("World");
        System.out.println(str1==(str5+str6));//false

        String str7="Hello";
        String str8="World";
//      str7+str8  相当于new StringBuilder().append(str7).append(str8).toString;
        System.out.println(str3==(str7+str8));//false
/*        给变量进行初始化赋值的时候,初始化只是一个式子,且运算符俩边都是字面值常量,那么jvm会在编译时期将该式子
        运算完毕。成为常量优化机制。*/
        System.out.println(str3==("Hello"+"World")); //true 相当于str3==“HelloWorld”
    }

String笔试题2

public class Demo {
    public static final String str1 = "HelloWorld";
    public static final String str2 = "HelloWorld";
    public static final String str3 = "Hello";
    public static final String str4 = "World";
    public static final String str5;
    public static final String str6;
    public static final String str7;
    public static final String str8;

    static {
        str5 = "HelloWorld";
        str6 = "HelloWorld";
        str7 = "Hello";
        str8 = "World";

    }

    public static void main(String[] args) {
        System.out.println(str1 == str2);//true 在常量池
        System.out.println(str5 == str6);//true 还是在常量池
        System.out.println(str5 == str1);//true 在常量池
//      被final修饰且直接声明初始化的自定义常量当成字面值常量
        System.out.println(str1 == (str3 + str4));//true  str=("Helllo"+"World")在编译时期就合并了
        System.out.println(str5 == (str7 + str8));//false  在运行时期走,+相当于new 相当于new StringBuilder().append(str7).append(str8).toString

    }
}

String笔试题3

    public static void main(String[] args) {
        String str1="HelloWorld";//1个,在常量区
        String str2=new String("HelloWorld");//2个,一个在常量区一个在堆内存
        
        //共创建一个String对象
        String str3="H"+"e"+"l"+"l"+"o"+"W"+"o"+"r"+"l"+"d";//1个对象,编译时期就合并了相当于str1

        //共创建8个String对象
        String s1="H";
        String s2="e";
        String s3="l";
        String s4="l";
        String s5="o";
        String s6="W";
        String s7="o";
        String s8="r";
        String s9="l";
        String s10="d";
        String str4=s1+s2+s3+s4+s5+s6+s7+s8+s9+s10;//相当于new StringBuilder()然后toString

    }

String类常见方法

判断功能的方法

public boolean equals (Object anObject) :判断俩个字符串的内容是否相同且区分大小写

public boolean equalsIgnoreCase (String anotherString) :判断俩个字符串的内容是否相同且忽略大小写【验证码,邮箱】


public boolean contains(CharSequence s) :当且仅当此字符串包含指定的 char 值序列时,返回true。


public boolean endsWith(String suffix) :测试此字符串是否以指定的后缀结束。
public boolean isEmpty() :当且仅当 length() 为 0 时返回 true。
public boolean startsWith(String prefix) :测试此字符串是否以指定的前缀开始。
public boolean startsWith(String prefix,int toffset) :测试此字符串从指定索引开始的子字符串是否以指定前缀开始。


获取功能的方法

public int length () :返回此字符串的长度。【数组没有()】
public String concat (String str) :将指定的字符串连接到该字符串的末尾。
public char charAt (int index) :返回指定索引处的字符值。
public int indexOf (String str) :返回指定子字符串第一次出现在该字符串内的索引,找不到返回-1
public int lastIndexOf (String str):返回指定子字符串最后一次出现在该字符串内的索引。
public String substring (int beginIndex) :返回一个子字符串,从beginIndex开始截取字符串到字符串结尾。
public String substring (int beginIndex, int endIndex) :返回一个子字符串,从beginIndex到endIndex截取字符串。含beginIndex,不含endIndex。


转换功能的方法

public char[] toCharArray () :将此字符串转换为新的字符数组。
public byte[] getBytes () 用于返回字符串的字节数组,可以指定编码方式
 

 String str="小羽毛";
 byte[] bytes = str.getBytes((StandardCharsets.UTF_8));
 System.out.println(Arrays.toString(bytes));//打印字节数组

public String replace (CharSequence target, CharSequence replacement) :将与target匹配的字符串使用replacement字符串替换。
public String toLowerCase()  将字符串中所有字母字符转换为小写
public String toUpperCase()  将字符串中所有字母字符转换为大写,汉字原样输出


分割功能的方法

public String[] split(String regex) :将此字符串按照给定的regex(规则)拆分为字符串数组。

一般情况

String str = "这世界很喧嚣,做你自己就好";
//使用split()拆分字符串
String[] strings = str.split(",");
//打印拆分后的字符串数组
System.out.println( Arrays.toString(strings));

-------------------------

注意特殊分割符号

1.字符" | " , " * " , " + "都得加上转义字符,前面加上"\\"。 
2.如果是" \ ",那么就得写成"\\\\"。 

比如,分隔符是|

正则表达式中使用反斜杠 \ 来转义下一个字符, 为什么用两个反斜杠呢

反斜杠本身就是一个特殊字符,需要用反斜杠来转义
使用正则表达式分割
String str = "这世界很喧嚣|做你自己就好";
Pattern pat = Pattern.compile("\\|");
//使用正则表达式()拆分字符串
String[] split = pat.split(str);
//打印拆分后的字符串数组
System.out.println( Arrays.toString(split));


字符串替换

replace() 方法通过用 newChar 字符替换字符串中出现的所有 oldChar字符,并返回替换后的新字符串。

replace(String oldChar, String newChar)

将字符串中满足正则表达式的部分替换为给定内容

String replaceAll(String regex,Stirng replace)
public static void main(String[] args) throws IOException {
    String str = "ab123sdab4543das756as876asd";
    str = str.replaceAll("\\d+", "#num#");  //"\d+",任意多个数字字符
    System.out.println(str);
}

打印输出:ab#num#sdab#num#das#num#as#num#asd


字符串拼接

使用StringBuilder

直接使用StringBuilder的方式是效率最高的。因为StringBuilder天生就是设计来定义可变字符串和字符串的变化操作的

 StringBuilder sb = new StringBuilder("小羽毛:");
 String str = "干杯~~~";
 //使用StringBuilder 字符串拼接
 System.out.println(sb.append(str));

---------------------------------

拼接null 

StringBuilder sb = new StringBuilder("小羽毛:");
String str = null;
//使用StringBuilder 字符串拼接
System.out.println(sb.append(str));

使用+

Java中的+对字符串的拼接,其实现原理是使用StringBuilder.append

String str1="小羽毛:";
String str2="干杯~~~";
//使用 + 字符串拼接
System.out.println(str1+str2);

---------------------------------

拼接null 

String str1="小羽毛:";
String str2=null;
//使用 + 字符串拼接
System.out.println(str1+str2);
“+” 号操作符会把 null 当做是 “null” 字符串来处理。

使用concat()
String str1="小羽毛:";
String str2="干杯~~~";
//使用concat() 字符串拼接
System.out.println(str1.concat(str2));

------------------------------------

拼接null 

String str1="小羽毛:";
String str2=null;
//使用concat() 字符串拼接
System.out.println(str1.concat(str2));

使用String.join()
第一个参数为字符串连接符
String str1="小羽毛";
String str2="干杯~~~";
//使用join() 字符串拼接
System.out.println(String.join(":",str1,str2));


字符串格式化

String类的format()方法用于创建格式化的字符串以及连接多个字符串对象

//制定字符串格式和参数生成格式化的新字符串。
format(String format, Object... args)

转  换  符

说    明 

示    例

%s

字符串类型

"mingrisoft"

%c

字符类型

'm'

%b

布尔类型

true

%d

整数类型(十进制)

99

public static void main(String[] args) {
    DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String format = fmt.format(new Date());
    System.out.println(String.format("时间:%s", format));
}


StringBuffer和StringBuilder

1、StringBuffer类和StringBuilder类

String 对象是常量对象,因此一旦拼接和修改就会产生新的 String 对象。
SringBuffer StringBuilder 可以在原对象上进行 append,insert,delete,replace 等修改。
StringBuffer类和StringBuilder类的相同点和不同点

StringBuilder是个字符串的缓冲区,即它是一个容器,容器中可以装很多字符串。并且能够对其中 的字符串进行各种操作。

相同点:
      1.二者都继承AbstractStringBuilder。
      2.二者都是可变的字符序列
      3.二者的方法除了同步修饰符外都是相同的。

不同点:
StringBuffer是线程安全的,适用于多线程程序,如果在单线程中使用,效率极低
StringBuilder是线程不安全的,适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全。

StringBuilder可变的原因:底层封装了一个没有被final修饰的数组
public StringBuilder() :构造一个空的StringBuilder容器。

public StringBuilder(String str) :构造一个StringBuilder容器,并将字符串添加进去。

public StringBuilder append(...) :添加任意类型数据的字符串形式,并返回当前对象自身。
public String toString() :将当前StringBuilder对象转换为String对象。

    public static void main(String[] args) {
//        StringBuilder s="Hello";//编译报错
        StringBuilder sb = new StringBuilder();
        //任意类型的参数。任何数据作为参数都会将对应的字符串内容添加到StringBuilder中。
        sb.append("Hello");
        sb.append(true);
        sb.append(1.09);
        sb.append('A');
        sb.append(new Employee("张三",18));
        System.out.println(sb);//Hellotrue1.09AEmployee{name='张三', age=18, salary=null, status=null}
        //指定索引位置插入字符串内容
        sb.insert(0, "HaHa");//HaHaHellotrue1.09AEmployee{name='张三', age=18, salary=null, status=null}
        System.out.println(sb);
        //字符串反转 因为StringBuilder是可变字符序列,所以可以对sb进行反转
        sb.reverse();
        System.out.println(sb);//}llun=sutats ,llun=yralas ,81=ega ,'三张'=eman{eeyolpmEA90.1eurtolleHaHaH
    }


2、StringBuilder源码分析

1.StringBuilder类底层数组的初始容量是多少
初始容量是多少取决于所选择的构造器

StringBuilder()                                        初始容量:16字符
StringBuilder(CharSequence seq)           初始容量:为 16 加上参数的长度
StringBuilder(int capacity)                       初始容量:自定义,初始容量由 capacity 参数指定,          capacity >=0
StringBuilder(String str)                           初始容量:为 16 加上参数的长度

2.StringBuilder类底层数组的扩容规则是多少

jdk8.0(包含)后:
   扩容规则:(原来数组长度<<1)+2;
jdk7.0:
  扩容规则:    原来数组长度*2+2;//国际笑话
jdk6.0(包含)前:
   扩容规则:(原来数组长度+1)*2;

扩容规则计算的时候为什么进行+2处理? 为了防止底层数组的长度为0的特殊情况。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值