一.概述
上一篇讲了万物皆对象的Object类的方法。链接:Java万物皆对象Object类
今天讲解对象包装器,其实它们并没有什么特殊的用法,只是将基本类型包装成对象形式。然后讲解参数数量可变的方法print方法,最后讲解枚举类的基本使用方法。
二.包装类对象
1.理解实例:
比如有这样一个需求,我们要分辨一个同学考试是否考的是0分还是没有考试,该怎么区分呢??如果使用基本数据类型int,那么只能赋值为0,通过数字0并不能知道该同学是因为缺考还是因为空白卷呢,显然这样是不行的。或者我们可以自己定义数字来代表每个数字的含义,但是这是双方自定义的,其他人并不知道数字所代表的真正含义。这时候包装器对象就派上用场了,如果该同学没有考试,那么它的值为null值,如果是参加考试,但试卷是空白的可以记为0分。这样子就可以区分了。
2.包装类:
包装类对象都是基本类型包装类的的首字母大写。除了int和char类型是不同的。Integer和Character。他们都有公共的超类Number类。包装器对象是不可变的。并且类是final类型不能被继承。
/**
* 对象包装类
*/
public class IntegerDemo {
public static void main(String[] args) {
// 声明一个int类型的包装对象
Integer num1 = new Integer(1);
// 拆箱成int的基本类型
int num2 = num1.intValue();
// 包装成Integer类型的对象
num1 = Integer.valueOf(num2);
// 自动装箱(autoboxing) 将基本类型直接装箱成包装类型(推荐)
Integer num3 = 1;
// 自动拆箱 将对象类型直接拆箱成基本类型
int num4 = num3;
// 注意包装对象是可以为null的所以在使用的时候一定要防止空指针异常。
num1 = null;
}
}
3.基本类型和包装类型的不同点。
如果用==号来比较两个对象,是比较两个对象的地址。如果新创建两个对象他们肯定是不同的因为需要使用不同的内存来存放。
那么来看看两个包装对象是不是相等呢????
/**
* 对象包装类
*/
public class IntegerDemo {
public static void main(String[] args) {
Integer num5 = new Integer(3);
Integer num6 = new Integer(3);
// 当创建两个对象的时候是false是正确的,因为只要new对象,那两块内存地址肯定不同
System.out.println(num5 == num6);
System.out.println(num5.equals(num6));
num5 = 3;
num6 = 3;
// 当自动装箱和拆箱的时候内存地址是相同的
System.out.println(num5 == num6);
System.out.println(num5.equals(num6));
num5 = 130;
num6 = 130;
// 当数字在-128和127之间的时候内存地址才相同
System.out.println(num5 == num6);
System.out.println(num5.equals(num6));
// 可以使用对应的基本类型的包装器静态方法,将字符串可以转换成基本类型或包装器类型
int num7 = Integer.parseInt("1");
}
}
int类型和short类型比较地址的时候是相同的。因为在-128和127使用的频率非常高,防止频繁的创建对象。所以会将这个区间的数字放进缓存,避免创建对象的开销。
装箱和拆箱是编译器认可的,而不是虚拟机。
三.参数可变的方法
在打印的时候会使用到printf函数,可以添加多个参数。称这种方法就是可变参数的方法。
// print函数的源码
// 实际上方法传递的是两个参数一个是String 另一个是Object[]
public PrintStream printf(String format, Object ... args) {
return format(format, args);
}
/**
* 可变参数
*/
public class ParamsChangeDemo {
public static void main(String[] args) {
double m = max(3.1,45,-5);
System.out.println(m);
// 也可以传递一个参数,那么该类型就是多定义类型的变量。
double h = max(1);
}
public static double max(double... values) {
// 声明一个double类型的最小值
double largest = Double.NEGATIVE_INFINITY;
// 循环比较参数的大小,选出最大的值并返回
for (double value : values) {
if (value > largest) {
largest = value;
}
}
return largest;
}
}
四.枚举类
枚举类的基本使用方法,见下面:
import java.util.Scanner;
/**
* 枚举类
*/
public class EnumDemo {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Enter a size: (SMALL,MEDIUM,LARGE,EXTRA_LARGE)" );
String input = in.next().toUpperCase();
// 返回指定名字,给定类的枚举常量
Size size = Enum.valueOf(Size.class,input);
System.out.println("size = " + size);
System.out.println("abbreviation = " + size.getAbbreviation());
// 在进行枚举值比较的时候使用== 而不是equals 因为枚举值在定义类的时候已经创建,无需构造对象。
if (size == Size.EXTRA_LARGE) {
System.out.println("Good job!");
}
// 常用API
// 打印枚举常量的名称
System.out.println(Size.EXTRA_LARGE.toString());
// 获取所有的常量名称
Size[] sizes = Size.values();
for (Size s : sizes) {
System.out.println(s.toString());
}
// 返回定义该常量的位置 从0开始计数
System.out.println(Size.LARGE.ordinal());
}
}
/**
* 所有的枚举类都是Enum的子类
* 每个枚举类型都有一个静态的values方法
*/
enum Size {
// 小号 声明枚举常量
SMALL("S"),
// 中号
MEDIUM("M"),
// 大号
LARGE("L"),
// 超大号
EXTRA_LARGE("XL");
/**
* 构造器只是在构造常量的时候被调用
* @param abbreviation
*/
private Size(String abbreviation) {
this.abbreviation = abbreviation;
}
/**
* 缩写
*/
private String abbreviation;
public String getAbbreviation() {
return abbreviation;
}
}
五.总结
学习包装类后,在以后定义实体类的使用推荐使用包装类型,避免使用基本类型来定义实例域。可变参数,个人认为用到的地方不是很多,枚举类其实是一个很好用来列举有限个数的一组区分不同含义的常量值类。用好了会使代码更加的简洁和清晰。
下一篇讲反射的基本使用。
有些可能我理解的不够深刻,大家如果觉得我说的不够详细可以参考我的推荐书,详细的看一下。欢迎大家评论。第一时间我会回复大家。谢谢!