Java|面向对象(中)-- 包装类

一. 包装类介绍

Java 语言是一个面向对象的编程语言,但是 Java 中的基本数据类型却不是面向对象的,但是我们在实际使用中经常需要将基本数据类型转换成对象,便于操作,比如,集合的操作中,这时,我们就需要将基本类型数据转化成对象,所以就出现了包装类。
基本数据类型有 8 个,对应的包装类也是 8 个,如果下图所示

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

二. 包装类的继承关系

在这里插入图片描述

三. 包装类的基本操作

8 个包装类都带有自己对应的构造方法,java 中的包装类提供了将原始数据类型转换为对象,以及将对象转换为原始数据类型的机制。这里举例说明下这个过程

3.1 基本数据类型 —> 包装类

import org.junit.Test;

/**
 * 基本数据类型 ---> 包装类:调用包装类的构造器
 * 这个过程称之为装箱:将基本类型转换成包装类型的过程叫做装箱
 */

class Order{
    boolean isMale;
    Boolean isFemale;
}

public class WrapperTest {

    @Test
    public void test1(){
        Integer in1 = new Integer(10);
        System.out.println(in1.toString()); // 10

        Integer in2 = new Integer("123");
        System.out.println(in2.toString()); // 123

        Float f1 = new Float(12.3f);
        Float f2 = new Float("12.3");
        System.out.println(f1); // 12.3
        System.out.println(f2); // 12.3

        Boolean b1 = new Boolean(true);
        Boolean b2 = new Boolean("true");
        Boolean b3 = new Boolean("true123");
        System.out.println(b3); // false

        Order order = new Order();
        System.out.println(order.isMale); // false
        System.out.println(order.isFemale); // null
    }
}

3.2 包装类 —> 基本数据类型

import org.junit.Test;

/**
 * 包装类 ---> 基本数据类型:调用包装类的 xxxValue()
 * 这个过程称之为拆箱:将包装类型转换成基本类型的过程叫做拆箱
 */

public class WrapperTest {
    
    @Test
    public void test2(){
        Integer in1 = new Integer(12);
        int i1 = in1.intValue();
        System.out.println(i1 + 1); // 13

        Float f1 = new Float(12.3);
        float f2 = f1.floatValue();
        System.out.println(f2); // 12.3
    }
}

3.3 自动装箱与自动拆箱

在 JDK1.5 版本之后新增了 ,自动装箱与自动拆箱功能

import org.junit.Test;

/**
 * 自动装箱与自动拆箱功能
 */

public class WrapperTest {
    
    @Test
    public void test3(){
        // 自动装箱:基本数据类型 ---> 包装类
        Integer in2 = 10;
        Boolean b2 = true;

        // 自动拆箱:包装类 ---> 基本数据类型
        int num3 = in2;
    }
}

3.4 基本数据类型、包装类 —> String 类

import org.junit.Test;

/**
 * 基本数据类型、包装类 ---> String 类
 */

public class WrapperTest {
    
    @Test
    public void test4(){
        int num1 = 10;
        // 方式1:链接运算
        String str1 = num1 + "";

        // 方式2:调用 String 的 valueOf() 方法
        float f1 = 12.3f;
        String str2 = String.valueOf(f1); 
        System.out.println(str2); // "12.3"

        Double d1 = 12.4;
        String str3 = String.valueOf(d1); 
        System.out.println(str3); // "12.4"
    }
}

3.5 String 类型 —> 基本数据类型、包装类

import org.junit.Test;

/**
 * String 类型 ---> 基本数据类型、包装类
 */

public class WrapperTest {
    
    @Test
    public void test5(){
        // String 类型 ---> 基本数据类型、包装类
        String str1 = "123";
        int num1 = Integer.parseInt(str1);
        System.out.println(num1 + 1); // 124

        String str2 = "true";
        boolean b1 = Boolean.parseBoolean(str2);
        System.out.println(b1); // true
    }
}

3.6 包装类的缓存机制

import org.junit.Test;

/**
 * 包装类的缓存机制
 */

public class WrapperTest {
    
    @Test
    public void test6(){
        
        // Integer 内部定义了 IntegerCache 结构,IntegerCache 中定义了 static final Integer cache[];
        // 保存了从 -128 ~ 127 范围的整数。如果我们使用自动装箱的方式给 Integer 赋值的范围在 -128 ~ 127 范围内时
        // 可以直接使用数组中的元素,不同再去 new 了,目的:提高效率

        Integer i = new Integer(1);
        Integer j = new Integer(1);
        System.out.println(i == j); // false、引用类型,== 比较地址值,不是一个对象,所以 false

        Integer m = 1;
        Integer n = 1;
        System.out.println(m == n); // true、自动装箱,这里涉及到的包装类的缓存机制,下面可以通过源码查看

        Integer x = 128; // 出了 cache[] 范围,相当于 new 了一个 Integer 对象
        Integer y = 128;
        System.out.println(x == y); // false
    }
}

静态的内部类是在整个 Integer 加载的时候就已经加载完成了,以下代码初始化了一个 Integer 类型的叫 cache 的数组,取值范围是[-128, 127]。缓存机制的作用就是提前实例化相应范围数值的包装类对象,只要创建处于缓存范围的对象,就使用已实例好的对象。从而避免重复创建多个相同的包装类对象,提高了使用效率。如果我们用的对象范围在[-128, 127]之内,就直接去静态区找对应的对象,如果用的对象的范围超过了这个范围,会帮我们创建一个新的 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 property
        int 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_VALUE
                h = 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);
}

通过分析源码我们可以发现,只有 double 和 float 的自动装箱代码没有使用缓存,每次都是 new 新的对象,其它的 6 种基本类型都使用了缓存策略。 使用缓存策略是因为,缓存的这些对象都是经常使用到的(如字符、-128至127之间的数字),防止每次自动装箱都创建一次对象的实例。

3.7 包装类和基本数据类型的区别

  • 默认值不同

包装类的默认值是 null,而基本数据类型是对应的默认值(比如整型默认值是0,浮点型默认值是0.0)

  • 存储区域不同

基本数据类型是把值保存在栈内存里,包装类是把对象放在堆中,然后通过对象的引用来调用他们

  • 传递方式不同

基本数据类型变量空间里面存储的是值,传递的也是值,一个改变,另外一个不变,而包装类属于引用数据类型,变量空间存储的是地址(引用),传递的也是引用,一个变,另外一个跟着变。

3.8 操作总结

在这里插入图片描述

四. 练习题

4.1 练习题1

import org.junit.Test;

/**
 * 练习题:以下两种情况,输入结果相同吗,各是什么?
 * 解释:三元运算符后面的表达式1和表达式2必须是同种类型、编译时自动类型提升
 */

public class WrapperTest {
    
    @Test
    public void test7(){
        
        Object o1 = true ? new Integer(1) : new Double(2.0);
        System.out.println(o1); // 1.0    编译时自动类型提升

        Object o2;
        if (true) {
            o2 = new Integer(1);
        }else {
            o2 = new Double(2.0);
        }
        System.out.println(o2); // 1
    }
}

4.2 练习题2

在这里插入图片描述

package com.base.learn2;

import java.util.Scanner;
import java.util.Vector;

/**
 * @Author myf15609
 * @Date 2022/12/10
 */
public class ScoreTest {
    public static void main(String[] args) {
        // 1. 实例化 Scanner 用于从键盘获取学生成绩
        Scanner scanner = new Scanner(System.in);

        // 2. 常见 Vector 对象
        Vector v = new Vector();

        // 3. 通过 for(;;) 或者 while(true) 的方式,给 Vector 中添加数据
        int maxScore = 0;
        for (; ; ) {
            System.out.println("请输入学生成绩(以负数代表输入结束):");
            int score = scanner.nextInt();
            if (score < 0) break;
            if (score > 100) {
                System.out.println("输入的成绩有误,请重新输入");
                continue;
            }
            // jdk 5.0 之前需要手动装箱
            // Integer integer = new Integer(score);
            // v.addElement(integer);

            // jdk 5.0 之后会自动装箱,直接写即可
            v.addElement(score);
            // 4. 获取学生成绩的最大值
            if (maxScore < score) maxScore = score;
        }
        // 5. 遍历 Vector 得到每个学生的成绩,并与最大值比较,得到学生成绩的等级
        char level = 0;
        for (int i = 0; i < v.size(); i++) {
            Object obj = v.elementAt(i);
            // jdk 5.0 之前需要手动拆箱
            // Integer intScore = (Integer) obj; // 强转为包装类
            // int score1 = intScore.intValue(); // 包装类转为基本数据类型

            // jdk 5.0 之后自动拆箱
            int score1 = (int) obj;
            if (maxScore - score1 < 10) {
                level = 'A';
            } else if (maxScore - score1 < 20) {
                level = 'B';
            } else if (maxScore - score1 < 30) {
                level = 'C';
            } else if (maxScore - score1 < 40) {
                level = 'D';
            }
            System.out.println("student - " + i + " score is " + score1 + ", level is " + level);
        }

    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值