【java基础】-java包装类/String类详解

文章介绍了Java中的包装类作用,如转换基本数据类型与对象,以及自动装箱和拆箱的概念。包装类Integer的创建方式和特性,特别是-128至127之间的Integer对象会缓存并重用。此外,讨论了String的不可变性及其创建方式,包括字符串常量池的作用和效率优势。
摘要由CSDN通过智能技术生成

包装类

包装类的作用

  1. 某些方法需要对象类型的参数,比如需要接收Object的方法
  2. 方便实现基本数据类型到String的相互转换
  3. 包装类本身有一些包含一些方法
  4. 包装类可以实现序列化与反序列化

包装类的继承体系

Character和Boolean不是数值类型,直接继承自Object。

在这里插入图片描述
而Integer、Float、Double、Short、Long、Byte都是数值类型,继承自Number,Number再继承Object。

在这里插入图片描述

基本数据类型和包装类型相互转换

装箱:基本数据类型 -> 包装类

拆箱:包装类 -> 基本数据类型

jdk5之前

只能手动实现装箱与拆箱,如下

        //手动装箱
        int n1 = 5;
        Integer n2 = Integer.valueOf(n1);//方式一
        Integer n3 = new Integer(n1);//方式二

        //手动拆箱
        Integer m1 = new Integer(5);
        int j = m1.intValue();

jdk5开始之后

可以支持自动装箱和自动拆箱,即基本数据类型和包装类可以直接相互赋值,如下

        //自动装箱
        Integer k1 = 5;//自动装箱底层调用了Integer.valueOf()
        //自动拆箱
        int k2 = k1;//自动拆箱底层调用了k1.intValue()

与String的相互转换

        //包装类与String相互转换
        Integer a = 355;
        String b = String.valueOf(a);//Integer转String,用到了自动拆箱,因为参数a需要的是int,
        Integer d = Integer.parseInt("123");//String转Integer,用到了自动装箱,因为原本结果是int

注意:调用哪个包装类的valueof()方法,就返回哪种数据类型,换句话说,你要得到什么数据类型,你就调用这个数据类型的valueof方法

包装类常用方法

转大小写、判断是否是数字、字母等等

Ingeter对象的创建

Ingeter的创建方式有两种,特别要注意直接使用赋值的方法创建的对象有什么特点。

方式一,直接new

//方式一,直接new
Integer integer = new Integer(5);
Integer integer1 = new Integer(5);
System.out.println(integer==integer1);//结果为false

结论:通过new方式创建的Integer,引用必然互不相同

方式二,通过int类型直接赋值(自动装箱)

//方式二,通过int类型直接赋值(自动装箱)
Integer integer2 = 5;
Integer integer3 = 5;
System.out.println(integer2==integer3);//结果为true
Integer integer4 = 150;
Integer integer5 = 150;
System.out.println(integer4==integer5);//结果为false

自动装箱底层调用的是valueof()方法,而valueof()源码如下

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

结论:可以得出,通过直接赋值的方法创建Ingeter,如果该值在[-128,127]之间,会返回的同一个引用(通过缓存数组实现);在此范围之外才会new新的对象,引用才会不一样

String类

String用于保存字符串常量,采用Unicode编码,汉字或字母都占用两个字节。

部分源码

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;
}

由源码可知:

  • String类本身是一个final修饰的类!
  • String底层使用的是final修饰的char数组,不可修改。(这里的不可修改指的是数组地址不可修改,而不是数组元素内容不可修改,所以String可以通过反射获取char数组,从而改变内容。)
  • String可序列化、可比较
  • String一般获取不到(除反射外)其char数组内容,所以String是内容不可变的。

String创建方式

方法一:通过new关键字创建

方法二:直接赋值字符串的方式创建,也叫做字面量方式创建

区别:

  • 字面量创建字符串会在字符串常量池中找,看是否有内容相同的对象,有的话则不创建(避免重复创建对象),没有的话就创建一个,最后返回池对象中的引用。(注:这里说的池中对象实体还是存储在堆中,只是引用放在在池中)
  • new关键字创建时,前面的操作和字面量创建一样,只不过最后在运行时会在堆中创建一个新的对象,然后返回的也是堆中对象的引用。

总结:直接赋值创建的String直接返回常量池中的引用,而new创建的String则返回堆中的引用。可以直接理解,用双引号括起来表达的字符串"",返回的是常量池中的引用地址。

字符串常量池

java内存区划分为堆(存对象)、栈(存局部变量)、和方法区,其中方法区用于存储静态变量、常量等,所以各种常量池都在方法区之中,也包括了String常量池。(JDK7.0之后,常量池被移到了堆中)。

字符串工作原理很简单,核心就是当第一次创建某个字符串时,会在常量池中创建一个标记,如果下次创建的字符串内容当池中的标记内容相等的话,就不再重复创建了,当然这个机制的触发要看具体的创建方法,参考上一节。

String的不可变性

String如何保证不可变?

一方面是String底层使用了final修饰的char数组,保证了数组的引用地址不可变;另一方面是String没有暴露这个char数组(private),保证了内容不可变。最后一方面是,String类本身是final修饰的,不可被继承,从而方法不能被重写。

为什么String字符串要设置为不可变?

  • 为了支持字符串常量池的正常工作,避免同时指向常量池中的对象之间相互影响。
  • 提高并发安全性,不可能同时修改同一个String对象,因为修改最后都会返回新的String对象
  • 提高hashcode()方法的性能,因为String不可变,所以hashcode()可以缓存起来复用

拓展:如何设计一个不可变类?

  • 类本身设置final修饰,保证不可被继承
  • 成员变量用final修饰,保证不可修改,如果是数组,则要再用privite修饰,保证不被外部访问
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值