【JAVA入门】Day22 - 包装类
包装类是 Java 中编写好的,基本数据类型对应的引用类型。
public class Test {
public static void main(String[] args) {
int i = 10;
}
}
int 类型对应的包装类叫 Integer。
public class Integer {
private int value;
...构造方法...
...成员方法...
}
包装类的本质就是:用一个对象来存储基本类型。
在 Java 的许多方法中,参数都可以用 Object 类传递,但如果是基本数据类型就不能接收。
public void method(Object obj){
...
}
而且,Java 的集合是不能存储基本数据类型的,只能存储用引用数据类型(包装类)。
在 Java 中,所有数据类型都有自己的包装类:
一、获取包装类里的对象
1.1 JDK5 之前的包装类
在 JDK5 以前,包装类的对象获取比较麻烦,用到下面的构造方法或 valueOf 方法。
public class IntegerDemo1 {
public static void main(String[] args) {
//1.利用构造方法获取Integer的对象(JDK5以前)
Integer i1 = new Integer(1);
Integer i2 = new Integer("1");
System.out.println(i1);
System.out.println(i2);
//2.利用静态方法获取Integer的对象(JDK5以前的方式)
Integer i3 = Integer.valueOf(123);
Integer i4 = Integer.valueOf("123");
Integer i5 = Integer.valueOf("123", 8); //八进制
System.out.println(i3);
System.out.println(i4);
System.out.println(i5);
}
}
要注意,这两种获取对象的方式在内存层面是有区别的。
首先,如果是 new 产生的 Integer 对象,一定是开辟了新的内存空间,所以它们之间比较的结果一定为 false。
但是,valueOf() 方法会对 -128 ~ 127 之间的数字(Byte的取值范围)进行优化,即缓存机制,如果已经生成了 -128 ~ 127 之间的 Integer 对象,再次创建在范围内的对象时,可以复用。因此下面例子中,i6 == i7 返回的结果为 true。
//3.这两种获取对象的区别
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
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
在 JDK5 以前,包装类对象之间不能直接用基本的数学运算符号计算,我们需要先把包装类拆箱,用基本数据类型计算,然后再装箱。
public class IntegerDemo2 {
public static void main(String[] args) {
//在以前包装类如何进行计算
Integer i1 = new Integer(1);
Integer i2 = new Integer(2);
//把两个数据进行相加
//对象之间不能直接计算
//1.把对象进行拆箱,变成基本数据类型
//2.相加
//3.装箱
int result = i1.intValue() + i2.intValue();
Integer i3 = new Integer(result);
System.out.println(i3);
}
}
1.2 JDK5 之后的包装类
JDK5 以后,我们有了改进的创建 Integer 对象的方式,即:自动拆箱和自动装箱。
- 自动装箱:基本数据类型会自动变成其对应的包装类。
- 自动拆箱:把包装类自动地变成其对应的基本数据类型。
public class IntegerDemo3 {
public static void main(String[] args) {
//自动拆箱
Integer i1 = 10;
//在底层,会自动调用静态方法valueOf()得到Integer对象
//只不过这个动作不需要我们自己去操作了
//自动拆箱
Integer i2 = new Integer(10);
int i = i2;
//在JDK5以后,int和Integer可以看作是同一个东西了
}
}
二者之间可以自动互转。
二、Integer里常用的成员方法
方法名 | 说明 |
---|---|
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类型的整数 |
四个都是静态方法,可以直接用类名调用。
package Bag;
public class IntegerDemo4 {
public static void main(String[] args) {
//1.把整数转为二进制,八进制,十六进制
String str1 = Integer.toBinaryString(100);
System.out.println(str1);
String str2 = Integer.toOctalString(100);
System.out.println(str2);
String str3 = Integer.toHexString(100);
System.out.println(str3);
//2.将字符串类型的整数转成int类型的整数
//Java 是强类型语言:每种数据都有自己的数据类型
//计算的时候,如果不是同一种数据类型,是无法直接数学运算的
int i = Integer.parseInt("123");
System.out.println(i);
System.out.println(i + 1);
//细节1:
//在类型转换的时候,括号中的参数只能是数字的字符串,否则会报错
//细节2:
//8种包装类中,除了Character,都有对应的parseXxx的方法,进行类型转换
String str = "true";
boolean b = Boolean.parseBoolean(str);
System.out.println(b);
}
}
学习完包装类字符串转数字,我们顺便学一下改进的键盘录入 nextLine(),之后键盘录入统一为这个方法。
package Bag;
import java.util.Scanner;
public class IntegerDemo5 {
public static void main(String[] args) {
//改写键盘录入代码
//原键盘录入
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个整数:");
int i = sc.nextInt();
System.out.println(i);
System.out.println("请输入一个字符串:");
String str = sc.next();
System.out.println(str);
//这种方法有弊端
//当我们在使用next,nextInt,nextDouble在接收数据的时候,遇到空格,回车,制表符就停止了
//键盘录入的是123 123,那么此时只能接收到空格前面的数据
//因此我们统一使用nextLine()方法
//它的特点是遇到回车才会停止录入
System.out.println("请输入一个数字字符串:");
String line = sc.nextLine();
System.out.println(line);
//转换为整数
int j = Integer.parseInt(line);
//转换为小数
double d = Double.parseDouble(line);
}
}
三、利用包装类写算法练习
【练习1】键盘录入:录入一些1~100之间的整数,添加到集合中,直到集合中所有数据和超过200为止。
package Bag;
import java.util.ArrayList;
import java.util.Scanner;
public class IntegerTest {
public static void main(String[] args) {
//键盘录入:录入一些1~100之间的整数
//添加到集合中,直到集合中所有数据和超过200为止。
//1.创建一个集合用来添加整数
ArrayList<Integer> list = new ArrayList<>();
//2.键盘录入数据添加到集合中,循环录入
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入一个整数:");
String numStr = sc.nextLine();
int num = Integer.parseInt(numStr);
//先把异常数据过滤
if(num < 1 || num > 100) {
System.out.println("当前数字不在1~100范围中!请重新输入:");
continue;
}else{
//num是基本数据类型int
//在添加数据的时候触发了自动装箱
//list.add(num.valueOf(num));
list.add(num);
}
//统计集合中所有的数据和,判断是否大于200
if(getSum(list)){
System.out.println("当前数字和已超过200,输入结束!");
break;
}
}
//验证集合内容
for(int i = 0; i < list.size(); i++) {
if(i < list.size() - 1) {
System.out.print(list.get(i) + ", ");
}else{
System.out.println(list.get(i));
}
}
}
private static boolean getSum(ArrayList<Integer> list) {
int sum = 0;
for(int i = 0; i < list.size(); i++) {
sum = sum + list.get(i);
}
if(sum > 200) {
return true;
}else{
return false;
}
}
}
【练习2】自己实现parseInt方法的效果,将字符串形式的数据转成整数。
要求:字符串只能是数字不能有其他字符,最少一位,最多10位,0不能作为开头。
package Bag;
public class IntegerTest2 {
public static void main(String[] args) {
/*自己实现parseInt方法的效果,将字符串形式的数据转成整数。
要求:字符串只能是数字不能有其他字符
最少一位,最多10位,0不能作为开头。*/
//1.定义一个字符串
String str = "123456789";
//2.校验字符串
//在开发中,我们习惯过滤异常数据,判断条件一般为取反
if(!str.matches("[1-9]{1,10}")) {
System.out.println("输入的字符串不符合要求!");
}else{
System.out.println("数据格式正确");
//类型转换,把字符串变整数?
//3.遍历字符串,得到里面的每一个字符
//定义一个变量代表最终结果
int number = 0;
for(int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
//'1' - '0' == 1
int num = c - '0';
//把每一位数字放到number当中
number = number * 10 + num;
}
System.out.println(number);
}
}
}
【练习3】定义一个方法自己实现toBinaryString方法的效果,将一个十进制整数转成字符串表示的二进制。
除基取余法:不断地除以基数得到余数,直到商为0,再把余数倒着拼接起来即可。
package Bag;
public class IntegerTest3 {
public static void main(String[] args) {
System.out.println(toBinaryString(100));
}
public static String toBinaryString(int number) {
//不断去除以2,得到余数,直到商为0
//定义一个StringBuilder用于拼接余数
StringBuilder sb = new StringBuilder();
while(true) {
if(number == 0) {
break;
}
//获取余数 %
int remaindar = number % 2;
//除以2
number = number / 2;
//倒着拼接,每次都要放到头部,所以用插入方法
sb.insert(0,remaindar);
}
return sb.toString();
}
}
【练习4】计算出生年月日到今日时间间隔为多少。
package Bag;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
public class IntegerTest4 {
public static void main(String[] args) throws ParseException {
//JDK7以前的方法
//计算毫秒值
//出生年月日
String birthday = "2000年1月1日";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date birthDate = sdf.parse(birthday);
long birthDateTime = birthDate.getTime();
//当前时间
Date d = new Date();
long nowTime = d.getTime();
//计算时间差值
long period = nowTime - birthDateTime;
System.out.println(period);
//将毫秒值转化为天数
System.out.println(period / 1000 / 60 / 60 / 24);
//JDK8以后的方法
LocalDate ld1 = LocalDate.of(2000,1,1);
LocalDate ld2 = LocalDate.now();
long betweenDays = ChronoUnit.DAYS.between(ld1, ld2);
System.out.println(betweenDays);
}
}
【练习5】判断任意的一个年份是闰年还是平年。
package Bag;
import java.time.LocalDate;
import java.util.Calendar;
public class IntegerTest5 {
public static void main(String[] args) {
//判断任意一个年份是平年还是闰年
//jdk7
//获取2000年1月1日 0:0:0
//获取2000年12月31日 23:59:59
//判断间隔是否为366天
//或者判断2月份天数
//2000年2月1日 0:0:0
//2000年3月1日 0:0:0
//或利用Calendar类,把时间设置为2000年3月1日
//往前减一天
//看当前时间是28号还是29号
Calendar c = Calendar.getInstance();
//注意月份是0~11,3月是2
c.set(2000, 2, 1);
//再把日历往前减一天
c.add(Calendar.DAY_OF_MONTH, -1);
//查看当前时间
int day = c.get(Calendar.DAY_OF_MONTH);
if (day == 28) {
System.out.println("是平年");
} else {
System.out.println("是闰年");
}
//JDK8
//LocalDate
LocalDate ld1 = LocalDate.of(2000, 3, 1);
LocalDate ld2 = ld1.minusDays(1);
//月份是1~12
int dayOfMonth = ld2.getDayOfMonth();
if(dayOfMonth == 28){
System.out.println("是平年");
}else{
System.out.println("是闰年");
}
//LocalDate有专门的方法
//是闰年返回true
System.out.println(ld1.isLeapYear());
}
}