码出高效读书笔记:基本数据类型、包装类型及字符串

本文深入解析Java中的基本数据类型和包装类型,包括它们的默认值、空间占用、表示范围及包装类特性。同时,详细介绍了字符串类型及其相关类String、StringBuffer和StringBuilder的区别和使用场景。

1、基本数据类型

基本数据类型是指不可再分的原子数据类型,内存中直接存储此类型的值,通过内存地址即可直接访问到数据,并且此内存区域只能存放这种类型的值。

一般来说Java有8中数据类型,分别为byte、char、short、int、long、float、double、boolean,但是码出高效中多给出了一种基本数据类型,即refvar,这是一种面向对象世界中的引用变量,也叫作引用句柄。

前8种基本数据类型都有对应的包装数据类型,除char的对应包装类名为Character,int为Integer外,其他的6种都是把首字母大写即可。

这8种基本数据类型的默认值、空间占用大小、表示范围及对应的包装类等信息如下表所示:

重点讲一下refvar:

引用分成两种数据类型,即引用变量本身和引用指向的对象。为了强化这两个概念的区分,码出高效中把引用变量成为refvar,而把引用指向的实际对象成为refobj。

refvar是基本的数据类型,默认值是null,存储refobj的首地址,可以直接使用双等号==进行等值判断。而平时使用refvar.hashCode()返回的值,只是对象的某种哈希计算,可能与地址有关。与refvar本身存储的内存单元地址是两回事。作为一个引用变量,不管它是指向包装类、集合类、字符串类还是自定义类,refvar均占用4B空间。注意它与真正对象refobj之间的区别。无论refobj是多么小的对象,最小占用的存储空间是12B(用于存储基本信息,称为对象头),但由于存储空间分配必须是8B的倍数,所以初始分配的空间至少是16B。

一个refvar至多存储一个refobj的首地址,一个refobj可以被多个refvar存储下它的首地址,即一个堆内对象可以被多个refvar引用指向。如果refobj没有被任何refvar指向,那么它迟早会被垃圾回收。而refvar的内存释放,与其他数据类型相似。

2、包装类型

8种基本数据类型都有相应的包装类,因为Java的设计理念是一切皆是对象,在很多情况下,需要以对象的形式操作,比如使用hashCode()获取哈希值,或者getClass()获取类等。包装类的存在解决了基本数据类型无法做到的事情:泛型类型参数、序列化、类型转换、高频区间数据缓存

高频区间数据缓存非常的重要,我们都知道Integer会缓存-128-127之间的值,对于Integer var=?在-128-127之间的赋值,Integer对象由IntegerCache.cache产生,会复用已有的对象,这个区间的Integer值可以直接使用==进行判断,但是这个区间之外的所有数据都会在堆上产生,并不会复用已有对象,这是一个大问题,因此推荐所有包装类对象之间值的比较,全部使用equals()方法。

除了Float和Double外,其他包装数据类型都会缓存,6个包装类直接赋值时,就是调用对应包装类的静态工厂方法valueOf(),这就是俗称的自动装箱,如下面代码所示:

public class Test{
    public static void main(String[] args){
        //Integer的自动装箱:把一个int型的值直接赋给一个Integer类型的引用,调用的是Integer的valueOf()方法
        Integer integer = 10;

        //Integer的自动拆箱:调用的是Integer的intValue()方法
        int i = integer;
    }
}


//Integer的valueOf()方法源码
@HotSpotIntrinsicCandidate
public static Integer valueof(int i){
       if(i >= IntegerCache.low && i <=IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
       return new Integer(i);
}

如上面的源码所示,如果i在缓存区间以内,那么直接返回缓存中的Integer对象,否则就会new一个新对象,要学会合理利用缓存,提升程序的性能。各个包装类的缓存区间如下:

  • Boolean:使用静态final变量定义,valueOf()就是返回这两个静态值
  • Byte:表示范围是-128-127,全部缓存
  • Short:表示范围是-32768-32767,缓存区间是-128-127
  • Character:表示范围是0-65535,缓存区间是0-127
  • Long:表示范围是[-2^63,2^63-1],缓存区间是-128-127
  • Integer:表示范围是[-2^31,2^31-1],缓存区间是-128-127,它是唯一一个可以修改缓存区间的包装类,在VM options加入参数-XX:AutoBoxCacheMax=7777,即可设置最大缓存值为7777

码出高效中作者给出了以下几点建议:

  1. 所有的POJO类属性必须使用包装数据类型(POJO类简单理解就是不包含业务逻辑,仅仅是用来存储数据的Java类)。
  2. RPC方法的返回值和参数必须使用包装数据类型。
  3. 所有的局部变量推荐使用基本数据类型。

看了别人的博客以后我发现还有一点需要注意,请看下面代码:

public class Main {
    public static void main(String[] args) {
         
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;
        Long h = 2L;
         
        System.out.println(c==d);
        System.out.println(e==f);
        System.out.println(c==(a+b));
        System.out.println(c.equals(a+b));
        System.out.println(g==(a+b));
        System.out.println(g.equals(a+b));
        System.out.println(g.equals(a+h));
    }
}

先想一下输出结果是什么。这里需要注意的是,==两边如果是包装类的引用的话,那么比较的就是这两个引用是否指向同一个对象,如果有一边是表达式运算的话,那么比较的就是数值!另外,对于包装器类型,equals方法并不会进行类型转换。明白了这2点之后,上面的输出结果便一目了然,输出结果如下:

true
false
true
true
true
false
true

3、字符串

字符串也是常用的数据类型,它在JVM中的地位并不比基本数据类型低,JVM对字符串也做了特殊处理。

字符串相关类型主要有三种:

  1. String
  2. StringBuffer
  3. StringBuilder

String是只读字符串,典型的immutable对象,对它的任何改动,其实都是创建一个新对象,再把引用指向该对象。String对象赋值操作后,会在常量池中进行缓存,如果下次申请创建对象时,缓存中已经存在,则直接返回响应引用给创建者。

StringBuffer则可以在原对象上进行修改,是线程安全的,JDK5中引入的StringBuilder与StringBuffer均继承自AbstractStringBuilder,两个子类的很多方法都是通过“super.方法()”的方式调用抽象父类中的方法,此抽象类在内部与String一样,也是以字符数组的形式存储字符串的。StringBuilder是非线程安全的,把是否需要进行多线程加锁交给工程师决定,操作效率比StringBuffer高。线程安全的对象先产生是因为计算机的发展总是从单线程到多线程,从单机到分布式。

在非基本数据类型的对象中,String是仅支持直接相加操作的对象。这样操作比较方便,但在循环体内,字符串的连接方式应该使用StringBuilder的append()方法进行扩展,像下面这种方式是不推荐的:

String str = "start"
for(int i = 0;i < 100;i++){
    str = str + "hello";
}

此段代码的内部实现逻辑是每次循环都会new一个StringBuilder对象,然后进行append操作,最后通过toString方法返回String对象,不但造成了内存资源浪费,而且性能更差。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值