包装类

包装类就是基本数据类型所对应的引用数据类型. 就是把基本数据类型变成了一个对象.

包装类可以理解为: 用一个对象, 将基本数据类型包起来.


图 1

Java 中万物皆对象, 所有的东西都可以看作是一个对象, 而且由于多态特性, 所有的对象都可以用 Object 来表示.


图 2

图 3

此时, 如果没有包装类, 传递过来了一个整数, 方法就无法接受, 程序就有局限性. 另一方面, 集合不能存储基本数据类型, 只能存储对象.

JDK5 对获取对象的方式进行了优化.

JDK5 之前, 如果要获取包装类的对象, 需要根据构造方法自己 new. 或者根据静态方法 valueOf() 来获取, 这是一个被重载的方法.


图 4

valueOf() 源码:


图 5

传进来的参数, 如果在 [-128, 127] 范围内, 就直接从一个数组中去获取, 否则 new 一个出来.

进入 1080 行的 cache 的源码:


图 6

可以看见, cache 是一个 Integer 类型的数组.

low 和 high 的值:


图 7

程序示例:

public class IntegerDemo1 {
    public static void main(String[] args) {
        /*
         * public Integer(int value) 根据传递的整数创建一个 Integer 对象
         * public Integer(String s) 根据传递的字符串创建一个 Integer 对象
         * public static Integer valueOf(int i) 根据传递的整数创建一个 Integer 对象
         * public static Integer valueof(String s) 根据传递的字符串创建一个 Integer 对象
         * public static Integer valueof(String s, int radix) 根据传递的字符串和进制创建一个 Integer 对象
         */

        // 1. 利用构造方法获取 Integer 的对象 (JDK5 以前的方式)
        Integer i1 = new Integer(1);
        Integer i2 = new Integer("1");
        System.out.println(i1);  // 1
        System.out.println(i2);  // 1

        // 2. 利用静态方法获取 Integer 的对象 (JDK5 以前的方式)
        Integer i3 = Integer.valueOf(123); // 123
        Integer i4 = Integer.valueOf("123"); // 123
        Integer i5 = Integer.valueOf("123", 8); // 83

        System.out.println(i3);  // 123
        System.out.println(i4);  // 123
        System.out.println(i5);  // 83

        // 3. 这两种方式获取对象的区别 (掌握)
        // 底层原理: 
        // 因为在实际开发中, -128~127 之间的数据, 用的比较多. 
        // 如果每次使用都是 new 对象, 那么太浪费内存了
        // 所以, 提前把这个范围之内的每一个数据都创建好对象
        // 如果要用到了不会创建新的, 而是返回已经创建好的对象. 
        Integer i6 = Integer.valueOf(127);
        Integer i7 = Integer.valueOf(127);
        System.out.println(i6 == i7);  // true

        Integer i8 = Integer.valueOf(128);
        Integer i9 = Integer.valueOf(128);
        System.out.println(i8 == i9);  // false

        // 下面的代码中, 因为看到了 new 关键字, 在 Java 中, 每一次 new 都是创建了一个新的对象
        // 所以下面的两个对象都是 new 出来, 地址值不一样. 

        Integer i10 = new Integer(127);
        Integer i11 = new Integer(127);
        System.out.println(i10 == i11);  // false

        Integer i12 = new Integer(128);
        Integer i13 = new Integer(128);
        System.out.println(i12 == i13);  // false
    }
}

程序示例:

public class IntegerDemo2 {
    public static void main(String[] args) {
        // 在以前包装类如何进行计算

        Integer i1 = new Integer(1);
        Integer i2 = new Integer(2);

        // 需求: 要把两个数据进行相加得到结果 3
        // 对象之间是不能直接进行计算的. 
        // 步骤:
        // 1. 把对象进行拆箱, 变成基本数据类型
        // 2. 相加
        // 3. 把得到的结果再次进行装箱 (再变回包装类)

        int result = i1.intValue() + i2.intValue();
        Integer i3 = new Integer(result);
        System.out.println(i3);
    }
}

程序示例:

public class Demo3 {
    public static void main(String[] args) {
        // 在 JDK5 的时候提出了一个机制: 自动装箱和自动拆箱
        // 自动装箱: 把基本数据类型会自动的变成其对应的包装类
        // 自动拆箱: 把包装类自动的变成其对应的基本数据类型

        // 自动装箱的动作, 在底层, 此时还会去自动调用静态方法 valueOf 得到一个 Integer 对象, 只不过这个动作不需要我们自己去操作了
        Integer i1 = 10;

        Integer i2 = new Integer(10);
        // 自动拆箱的动作
        int i = i2;

        // 结论: 在 JDK5 以后, int 和 Integer 可以看做是同一个东西, 因为在内部可以自动转化. 
    }
}

图 8

包装类 Integer 的成员方法:


图 9

程序示例:

public class demo4 {
    public static void main(String[] args) {
        /*
         * public static string toBinaryString(int i) 得到二进制
         * public static string toOctalString(int i) 得到八进制
         * public static string toHexString(int i) 得到十六进制
         * public static int parseInt(String s) 将字符串类型的整数转成 int 类型的整数
         */

        // 1. 把整数转成二进制, 十六进制
        String str1 = Integer.toBinaryString(100);
        System.out.println(str1);  // 1100100

        // 2. 把整数转成八进制
        String str2 = Integer.toOctalString(100);
        System.out.println(str2);  // 144

        // 3. 把整数转成十六进制
        String str3 = Integer.toHexString(100);
        System.out.println(str3);  // 64

        // 4. 将字符串类型的整数转成 int 类型的整数
        // 强类型语言:每种数据在 Java 中都有各自的数据类型
        // 在计算的时候, 如果不是同一种数据类型, 是无法直接计算的. 
        int i = Integer.parseInt("123");
        System.out.println(i);
        System.out.println(i + 1);  // 124
        // 细节 1:
        // 在类型转换的时候, 括号中的参数只能是数字不能是其他, 否则代码会报错
        // 细节 2:
        // 8 种包装类当中, 除了 Character 都有对应的 parseXxx 的方法, 进行类型转换
        String str = "true";
        boolean b = Boolean.parseBoolean(str);
        System.out.println(b);
    }
}

程序示例:

import java.util.Scanner;

public class Demo {
    public static void main(String[] args) {
        // 键盘录入
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串");
        // String str = sc.next();
        // System.out.println(str);
        // 弊端:
        // 当我们在使用 next, nextInt, nextDouble 在接收数据的时候, 遇到空格, 回车, 制表符的时候就停止了
        // 键盘录入的是 123 123 那么此时只能接收到空格前面的数据
        // 我想要的是接收一整行数据
        // 约定:
        // 以后我们如果想要键盘录入, 不管什么类型, 统一使用 nextLine
        // 特点: 遇到回车才停止
        String line = sc.nextLine();
        System.out.println(line);
        System.out.println(line + 1);
        double v = Double.parseDouble(line);
        System.out.println(v);
        System.out.println(v + 1);
    }
}

执行结果:

请输入一个字符串
2.3
2.3
2.31
2.3
3.3

练习题:

第一题:

import java.util.Scanner;

public class A05_IntegerDemo5 {
    public static void main(String[] args) {
        // 键盘录入
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串");
        /*
         * String str = sc.next();
         * System.out.println(str);
         */
        // 弊端:
        // 当我们在使用 next, nextInt, nextDouble 在接收数据的时候, 遇到空格, 回车, 制表符的时候就停止了
        // 键盘录入的是 123 123 那么此时只能接收到空格前面的数据
        // 我想要的是接收一整行数据
        // 约定:
        // 以后我们如果想要键盘录入, 不管什么类型, 统一使用 nextLine
        // 特点: 遇到回车才停止
        String line = sc.nextLine();
        System.out.println(line);
        double v = Double.parseDouble(line);
        System.out.println(v);
    }
}

第二题:

public class Test2 {
    public static void main(String[] args) {
        /*
         * 自己实现 parseInt 方法的效果, 将字符串形式的数据转成整数. 要求: 字符串中只能是数字不能有其他字符最少一位, 最多 10 位, 0 不能开头
        */
        // 1. 定义一个字符串
        String str = "123";
        // 2. 校验字符串
        // 习惯: 会先把异常数据进行过滤, 剩下来就是正常的数据. 
        if (!str.matches("[1-9]\\d{0,9}")) {
            // 错误的数据
            System.out.println("数据格式有误");
        } else {
            // 正确的数据
            System.out.println("数据格式正确");
            // 3. 定义一个变量表示最终的结果
            int number = 0;
            // 4. 遍历字符串得到里面的每一个字符
            for (int i = 0; i < str.length(); i++) {
                int c = str.charAt(i) - '0';  // 把每一位数字放到 number 当中
                number = number * 10 + c;
            }
            System.out.println(number);
            System.out.println(number + 1);
        }
    }
}

第三题:

public class Test3 {
    public static void main(String[] args) {
        /*
         * 定义一个方法自己实现 toBinaryString 方法的效果, 将一个十进制整数转成字符串表示的二进制
        */
    }

    public static String tobinarystring(int number) {// 6
        // 核心逻辑:
        // 不断的去除以 2, 得到余数, 一直到商为日就结束. 
        // 还需要把余数倒着拼接起来

        // 定义一个 StringBuilde r用来拼接余数
        StringBuilder sb = new StringBuilder();
        // 利用循环不断的除以 2 获取余数
        while (true) {
            if (number == 0) {
                break;
            }
            // 获取余数 %
            int remaindar = number % 2;  // 倒着拼接
            sb.insert(0, remaindar);
            // 除以 2
            number = number / 2;
        }
        return sb.toString();
    }
}

第四题:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Date;

public class Test4 {
    public static void main(String[] args) throws ParseException {
        // 请使用代码实现计算你活了多少天, 用 JDK7 和 JDK8 两种方式完成
        // JDK7
        // 规则: 只要对时间进行计算或者判断, 都需要先获取当前时间的毫秒值
        // 1. 计算出生年月日的毫秒值
        String birthday = "2000年1月1日";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        Date date = sdf.parse(birthday);
        long birthdayTime = date.getTime();
        // 2. 获取当前时间的毫秒值
        long todayTime = System.currentTimeMillis();
        // 3. 计算间隔多少天
        long time = todayTime - birthdayTime;
        System.out.println(time / 1000 / 60 / 60 / 24);

        // JDK8
        LocalDate ld1 = LocalDate.of(2000, 1, 1);
        LocalDate ld2 = LocalDate.now();
        long days = ChronoUnit.DAYS.between(ld1, ld2);
        System.out.println(days);
    }
}

第五题:

import java.time.LocalDate;
import java.util.Calendar;

public class Test5 {
    public static void main(String[] args) {
        /*
         * 判断任意的一个年份是闰年还是平年要求: 用 JDK7 和 JDK8 两种方式判断提示:
         * 二月有 29 天是闰年一年有 366 天是闰年
         */

        // JDK7
        // 我们可以把时间设置为 2000 年 3 月 1 日
        Calendar c = Calendar.getInstance();
        c.set(2000, 2, 1);
        // 月份的范围: 0~11
        // 再把日历往前减一天
        c.add(Calendar.DAY_OF_MONTH, -1);
        // 看当前的时间是 28 号还是 29 号?
        int day = c.get(Calendar.DAY_OF_MONTH);
        System.out.println(day);

        // JDK8
        // 月份的范围: 1~12
        // 设定时间为 2000 年的 3 月 1 日
        LocalDate ld = LocalDate.of(2001, 3, 1);
        // 把时间往前减一天
        LocalDate ld2 = ld.minusDays(1);
        // 获取这一天是一个月中的几号
        int day2 = ld2.getDayOfMonth();
        System.out.println(day2);

        // true: 闰年
        // false: 平年
        System.out.println(ld.isLeapYear());
    }
}
posted @ 2024-11-17 15:05  有空  阅读(28)  评论(0)    收藏  举报