包装类
将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据。
基本类型能做的事情,包装类也能做。但包装类能做的,基本类型不一定能做,比如要赋一个 null 值。
基本类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
Integer类
// Integer.valueOf(int i):返回表示指定的 int 值的 Integer 实例
Integer i = Integer.valueOf(100);
// Integer.valueOf(String s):返回一个保存指定值的 Integer 对象 String
Integer i = Integer.valueOf("100"); //只能用数字字符串
int和String类型相互转换
// int转String
//String.valueOf(int i)
String str = String.valueOf(number);
// String转int
// ①String ---> Integer ---> int
Integer i = Integer.valueOf(s);
// int.intValue()
int number = i.intValue();
// 自动装箱拆箱:
int number = Integer.valueOf(s);
// ②Integer.parseInt(String s)
int number = Integer.parseInt(s);
自动装箱拆箱
装箱:把基本数据类型转换为对应的包装类类型
拆箱:把包装类类型转换为对应的基本数据类型
示例:
Integer i = 100; // 自动装箱
i += 200; // i = i + 200; i + 200 自动拆箱;i = i + 200; 是自动装箱
注意:在使用包装类类型的时候,如果做操作,最好先判断是否为 null。
只要是对象,在使用前就必须进行不为 null 的判断。
装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。
常见问题
1.下面这段代码的输出结果是什么?
public class Main {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
//true
//false
i1和i2指向的是同一个对象,而i3和i4指向的是不同的对象。
为啥??
看一下Integer的valueOf方法的源码:
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
private static class IntegerCache {
static final int high;
static final Integer cache[];
static {
final int low = -128;
// high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
// Use Long.decode here to avoid invoking methods that
// require Integer's autoboxing cache to be initialized
int i = Long.decode(integerCacheHighPropValue).intValue();
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - -low);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}
由源码可知,在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。
2.下面这段代码的输出结果是什么?
public class Main {
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
//false
//false
Double.valueOf()源码:
public static Double valueOf(double d) {
return new Double(d);
}
注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。
Double、Float的valueOf方法的实现是类似的。
3.下面这段代码输出结果是什么:
public class Main {
public static void main(String[] args) {
Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
//true
//true
Boolean.valueOf()源码:
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
// 在Boolean中定义了2个静态成员属性:
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
4.谈谈Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。
当然,这个题目属于比较宽泛类型的。但是要点一定要答上,我总结一下主要有以下这两点区别:
1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;
2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。
PS:为啥?
5.下面程序的输出结果是什么?
public class Main {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
System.out.println(c==d); // true
System.out.println(e==f); // false
System.out.println(c==(a+b)); // true
System.out.println(c.equals(a+b)); // true
System.out.println(g==(a+b)); // true
System.out.println(g.equals(a+b)); // false
System.out.println(g.equals(a+h)); // true
}
}
// 反编译为:
System.out.println(c==d);
System.out.println(e==f);
System.out.println(c.intValue()==(a.intValue()+b.intValue()));
System.out.println(c.equals(Integer.valueOf(a.intValue()+b.intValue())));
System.out.println(g.longValue()==(long)(a.intValue()+b.intValue()));
System.out.println(g.equals(Integer.valueOf(a.intValue()+b.intValue())));
System.out.println(g.equals(Long.valueOf((long)a.intValue()+h.longValue())));
③ a+b包含了运算符,因此会触发自动拆箱过程
④.equal()会触发自动装箱过程,因此整个过程是先触发自动拆箱过程再触发自动装箱过程。
⑦a、h分别是Integer和Long,而g是Long,.equal()会根据比较的两个包装类自动转换为Long或Integer。
Date类
// 当前时间
new Date()
// 时间戳,类型为long
.getTime()
SimpleDateFormat类
SimpleDateFormat是一个具体的类,用于以区域设置敏感的方式格式化和解析日期。
常用的模式字母及对应关系如下:
y年 M月 d日 H时 m分 s秒
// 将日期格式化成日期/时间字符串(Date --> String) .format()
Date nowDate = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String nowDateStr = sdf.format(nowDate);
// 从给定字符串的开始解析文本以生成日期(String --> Date) .parse()
String dateStr = "2021年10月1日 12:13:14";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date date = sdf.parse(dateStr);
Calendar类
Calendar 为特定瞬间与一组日历字段之间的转换提供了一些方法,并为操作日历字段提供了一些方法。
// 获取日志类对象 calendar.getInstance()
// 假设今天是2021/10/01
Calendar cldCurrent = Calendar.getInstance(); // cldCurrent:2021/10/01
// Calendar .get 的属性值类型都是int类型
int year = cldCurrent.get(Calendar.YEAR);
int month = cldCurrent.get(Calendar.MONTH) + 1; // 月份是从0开始的,所以要+1
int date = cldCurrent.get(Calendar.DATE);
// 3年前的今天
Calendar cldCurrent = Calendar.getInstance();
cldCurrent.add(Calendar.YEAR, -3);
// cldCurrent:2018/10/01
// 设置当前日历的年月日
// 设置为2008/08/08
Calendar cldCurrent = Calendar.getInstance();
cldCurrent.set(2008, 08, 08);
// 案列:某一年的二月有几天
int anyYear = 2008; // anyYear:某一年
Calendar cldCurrent = Calendar.getInstance();
cldCurrent.set(anyYear, 3, 1); // 设置为该年的3月1号
cldCurrent.add(Calendar.DATE, -1); // 3月1号往前推一天
int FebDate = cldCurrent.get(Calendar.DATE);