各位小伙伴们大家好,欢迎来到这个小扎扎的《Java核心技术 卷Ⅰ》笔记专栏,在这个系列专栏中我将记录浅学这本书所得收获,鉴于 看到就是学到、学到就是赚到 精神,这波简直就是血赚
💡涉及的知识点速通
- 🛫 方法的参数传递机制是什么?
- 🪂 基本数据类型作参数
- 🪂 引用数据类型作参数
- 🛫 关于包装类你都知道什么?
- 🪂 包装类基本知识
- 🪂 什么是装箱和拆箱?
- 🪂 包装类cache缓存机制
🛫 方法的参数传递机制是什么?
方法的参数分为基本数据类型和引用数据类型,基本数据类型就是前面说过的四类八种,具体都有什么可以参考下面这篇博客的🛫 强制and自动类型转换都是啥?这个问题部分,在Java中除了这四类八种的基本数据类型之外都是引用数据类型
在答题之前先介绍一下相关概念
参数传递机制的两个专业术语:按值调用 表示方法接收到的是调用者提供的值;按引用调用 表示方法接收到的是调用者提供的变量地址
方法参数的两种形式:实参 就是方法调用的时候方法名后面的括号里的数据;形参 方法声明的时候方法名后面的括号里的数据,这就相当于一种局部变量,只在它定义的这个方法内部有效
🪂 基本数据类型作参数
基本数据类型的参数采用按值调用的传递机制,也就是说方法调用的时候传过去的是一个值,但是实参并没有作为这个值传递过去,而是将实参的副本传递过去,方法中对形参的所有操作都是对实参副本的操作,并不会更改实参的实际值
🪂 引用数据类型作参数
引用数据类型的参数也是采用按值调用的传递机制,也就是说方法调用的时候传过去的也是一个值,一个实参的副本 但是看上面代码的运行结果,许多小伙伴是不是就懵了,不是说传过去的是一个实参的副本嘛,为什么实参的结果值也互换了呢?别急,仔细想一想,数组是一个引用数据类型也就是说是一个对象,那么实参的arr是个什么?当然是这个数组对象的引用地址了,那么传递的副本也就是这个引用地址的副本,形参按照这个引用地址的副本对数组进行操作,当然也就按照地址操作了实参所对应的对象的值了。这么一来是不就是可以解释的通了
综上所述,Java中方法的参数传递机制只有按值调用,并没有按引用调用
🛫 关于包装类你都知道什么?
🪂 包装类基本知识
数据类型 | 包装类 | 储存空间(byte) | 大小 |
---|---|---|---|
byte | Byte | 1字节 | 8位 |
short | Short | 2字节 | 16位 |
int | Integer | 4字节 | 32位 |
long | Long | 8字节 | 64位 |
float | Float | 4字节 | 32位 |
double | Double | 8字节 | 64位 |
char | Character | 2字节 | 16位 |
boolean | Boolean | 1字节 | 8位 |
🚩每一个基本数据类型都有一个对应的包装类,前六个类派生于公共的超类Number
🚩包装类是不可变的,也即是说一旦构造了包装器,就不允许更改它的值,与此同时包装类还是final修饰的,因此不能派生他们的子类
🚩泛型也必须声明成包装类型,而不能使用基本数据类型
🚩包装类的值比较需要使用equals方法,而不是==判断
🪂 什么是装箱和拆箱?
Java主张一切皆对象的思想,但是基本数据类型并不是对象,于是就有了包装类的概念。其中装箱就是将一个基本数据类型包装成其对应的包装类,拆箱就是反过来将包装类拆成对应的基本数据类型数据。根据转换时是否使用方法,装箱又称为自动拆装箱和手动拆装箱
手动装箱有两种方式:使用包装类构造器、包装类的valueOf方法;手动拆箱有一种:包装类的xxxValue方法。但是Java提供了自动拆装箱,如果二者相互复赋值的话就会自动转换而无需使用方法进行转换,且使用泛型定义的集合添加基本数据类型的时候也会自动装箱为对应的包装类型
🚩装箱和拆箱是编译器的工作
🪂 包装类cache缓存机制
从Java5开始,包装类新增了自动拆、装箱的功能,除此之外还新增了cache缓存机制,该机制会将取值在一定范围内的值创建成相应的对象缓存起来,这些缓存起来的对象在以后使用到的时候就可以直接用,这样就可以避免在这个范围内的值重复创建造成的内存损耗从而降低性能。为了更好的了解这个机制,让我们看一下接下来的这段代码写下自己的答案,然后结合cache机制的解释再推测一下答案,最终结果在后面给出 这里通过源码(下面给出),以Integer为例来了解一下包装类的cache缓存机制,Integer类中有一个IntegerCache类,这个类的主要作用即就是创建[-128,127]之间的所有对象并添加到cache数组中,等到调用valueOf方法的时候就使用if判断是不是在范围内,如果在的话就直接在cache数组中直接返回,反之就使用构造器创建一个对应的Integer对象返回
private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}
}public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}
但是你可能就会有疑问了,如果我就使用一次包装类的话,它也会缓存创建范围内的所有对象,这样的话怎么实现节省内存提升性能呢?当然,包装类的cache缓存机制是针对大程序而言的概念,小程序并不能很好地体现。于是当确定同值对象使用的次数很少时,我们就可以使用构造器来创建包装类对象,因为缓存类只能通过valueOf方法才会生效
你可能又有疑问了,使用自动装箱直接赋值的形式创建包装类对象会不会使用到缓存呢?答案是 会,因为自动装箱底层就是调包装类对应的valueOf方法,那么你是怎么确定的呢?对自动装箱和自动拆箱代码编译生成的字节码文件进行反编译得出下面的内容,根据12和19行得知:自动装箱调用的是valueOf方法,自动拆箱调用的是intValue方法
public class com.example.demo.code.AutoPacking {java.lang.Integer i1;int i2;public com.example.demo.code.AutoPacking();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: iconst_16: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: putfield #3 // Field i1:Ljava/lang/Integer;12: aload_013: new #4 // class java/lang/Integer16: dup17: iconst_218: invokespecial #5 // Method java/lang/Integer."<init>":(I)V21: invokevirtual #6 // Method java/lang/Integer.intValue:()I24: putfield #7 // Field i2:I27: return
}
通过上面的分析,我们就可以很容易的得出上面那段代码的答案了
包装类的缓存范围
数据类型 | 包装类 | 缓存范围 |
---|---|---|
整型 | Byte、Short、Long、Integer | [-128,127] |
浮点型 | Float、Double | 无 |
字符型 | Character | [0,127] |
布尔型 | Boolean | true、false |