包装类

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

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


图 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 @   有空  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示