16Java基础之枚举、泛型、API、Objects类、包装类
枚举
- 枚举是一种特殊类。
- 枚举类的格式:
修饰符 enum 枚举类名{
名称1,名称2...;
其他成员...
}
注意:
- 枚举类中的第一行,只能写一些合法的标识符(名称),多个名称用逗号隔开。
- 这些名称,本质是常量,每个常量都会记住枚举类的一个对象。
案例:
// 枚举类
public enum A {
// 枚举类的第一行必须罗列的是枚举对象的名称
X, Y, Z;
// 其他成员
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试方法:
// 目标:认识枚举类,搞清楚枚举类的特点
public class Test {
public static void main(String[] args) {
// 枚举无法创建对象,构造器是私有的
// A a = new A();
A a1 = A.X;
A a2 = A.Y;
System.out.println(a1);
System.out.println(a2);
System.out.println("---------------------------");
//编译器为枚举类新增了几个方法
//拿到枚举类的全部对象,放到一个数组中返回。
A[] as = A.values();
for (int i = 0; i < as.length; i++) {
A a = as[i];
System.out.println(a);
}
//拿到X的枚举对象
A y = A.valueOf("X");
System.out.println(y == a1);
// ordinal,拿对象的索引
System.out.println(a1.ordinal());
System.out.println(a2.ordinal());
}
}
输出结果:
X
Y
---------------------------
X
Y
Z
true
0
1

- 上图为枚举类反编译后的代码截图。
枚举的特点:
- 枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象。
- 枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象。
- 枚举类中,从第二行开始,可以定义类的其他各种成员。
- 编译器为枚举类新增了几个方法,并且枚举类都是继承:java.lang.Enum类的,从enum类也会继承到一些方法。
枚举的应用场景
- 枚举通常用来表示一组信息,然后作为参数进行传输。
选择定义一个一个的常量来表示一组信息,并作为参数传递,参数值不受约束。
选择定义枚举表示一组信息,并作为参数传递,代码可读性好,参数值得到了约束,对使用者更友好,建议使用。
案例:
需求:需要提供一个方法,可以完成向下取整,向上取整,四舍五入,去掉小数部分。
如果用常量来表示一组功能信息,代码如下:
常量类:
// 常量类
public class Constant {
public static final int DOWN = 1;
public static final int UP = 2;
public static final int HAFL_UP = 3;
public static final int INT = 4;
}
测试方法:
// 目标:搞清楚枚举的应用场景:信息标志和信息分类
public class Test {
public static void main(String[] args) {
// 需求:需要提供一个方法,可以完成向下取整,向上取整,四舍五入,去掉小数部分。
// 常量信息标准和分类:参数值不被约束。
System.out.println(handleData(3.768, Constant.DOWN));
System.out.println(handleData(3.768, Constant.UP));
}
public static double handleData(double number,int type){
switch(type){
case Constant.DOWN:
// 向下取整
number = Math.floor(number);
break;
case Constant.UP:
// 向上取整
number = Math.ceil(number);
break;
case Constant.HAFL_UP:
// 四舍五入
number = Math.round(number);
break;
case Constant.INT:
// 去掉小数部分
number = (int)number;
break;
default:
System.out.println("输入的类型有误");
}
return number;
}
}
//----------------------------------------------------
如果使用枚举,代码如下:
枚举类:
public enum Constant2 {
DOWN,UP,HAFL_UP,INT;
}
测试方法:
public class Test2 {
public static void main(String[] args) {
// 需求:需要提供一个方法,可以完成向下取整,向上取整,四舍五入,去掉小数部分。
// 枚举做信息标准和分类:参数值被约束,最好的信息标志和分类的理想方案。
System.out.println(handleData(3.768, Constant2.DOWN));
System.out.println(handleData(3.768, Constant2.UP));
}
public static double handleData(double number,Constant2 type){
switch(type){
case Constant2.DOWN:
// 向下取整
number = Math.floor(number);
break;
case Constant2.UP:
// 向上取整
number = Math.ceil(number);
break;
case Constant2.HAFL_UP:
// 四舍五入
number = Math.round(number);
break;
case Constant2.INT:
// 去掉小数部分
number = (int)number;
break;
default:
System.out.println("输入的类型有误");
}
return number;
}
}
注意:handleData方法中的,Constant2.是可以省略的。
泛型
-
在定义类、接口、方法是,同时声明了一个或多个类型变量(如:“
”),称为泛型类、泛型接口、泛型方法,它们统称为泛型。
![image]()
-
作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的异常。
-
泛型的本质:把具体的数据类型作为参数传给变量。
案例:
// 目标:认识泛型
public class Test {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("魔法");
list.add("霍格沃兹");
list.add("我是一个中国人");
list.add(true);
list.add(123);
list.add(12.23);
// 1. 开发中很多时候需要统一的数据类型。(如果不使用泛型,类型没办法统一,就需要类型转换,容易出现bug)
for (int i = 0; i < list.size(); i++) {
Object object = list.get(i);
String st = (String)object;// 强制类型转换,编译不报错,运行报错。
System.out.println(st);
}
System.out.println("------------------");
ArrayList<String> list2 = new ArrayList<>(); //JDK1.7开始,后面类型可以不写
list2.add("魔法");
list2.add("霍格沃兹");
list2.add("我是一个中国人");
// list2.add(true); // 报错
// list2.add(123); // 报错
// list2.add(12.23);// 报错
}
}
泛型类
- 格式:
修饰符 class 类名<类型变量,类型变量,……>{
……
}
举例:
public class ArrayList<E>{
……
}
注意:类型变量建议用大写的英文字母,常用的有E、T、K、V等。
- E:通常代表Enum类型,用于表示枚举类型。
- T:代表Type类型,常用于泛型类或方法中表示类型参数。
- K:代表Key类型,通常用于表示键或标识符。
- V:代表Value类型,用于表示值或数据
案例:
import java.util.ArrayList;
// 泛型类
public class MyArrayList<E> {
private ArrayList list = new ArrayList();
public boolean add(E e){
list.add(e);
return true;
}
public boolean remove(E e){
return list.remove(e);
}
@Override
public String toString(){
return list.toString();
}
}
泛型接口
- 格式
修饰符 interface接口名<类型变量,类型变量,……>{
……
}
举例:
public interface A{
……
}
案例:
// 需求:必须完成学生、老师数据的增删改查操作。
学生类:
public class Student {}
老师类:
public class Teacher {}
泛型接口:
// 泛型接口
//T : 表示泛型的类型,是一个占位符,在编译期会被替换为具体的类型
public interface Data<T> {
void add(T t);
void remove(T t);
void update(T t);
T get(int index);
}
学生实现类:
public class DataStudent implements Data<Student>{
@Override
public void add(Student student) {
}
@Override
public void remove(Student student) {
}
@Override
public void update(Student student) {
}
@Override
public Student get(int index) {
return null;
}
}
老师实现类:
public class DataTeacher implements Data<Teacher>{
@Override
public void add(Teacher teacher) {
}
@Override
public void remove(Teacher teacher) {
}
@Override
public void update(Teacher teacher) {
}
@Override
public Teacher get(int index) {
return null;
}
}
测试方法:
// 目标:认识泛型接口的使用框架
public class Test {
public static void main(String[] args) {
// 需求:必须完成学生、老师数据的增删改查操作。
Student s1 = new Student();
Data data = new DataStudent();
data.add(s1);
data.remove(s1);
data.update(s1);
data.get(1);
}
}
泛型方法、泛型通配符、上下限
泛型方法
- 格式
修饰符<类型变量,类型变量,……> 返回值类型 方法名(形参){}
举例: public staticvoid test(T t){}
案例:
学生类:
public class Student{}
测试方法:
// 目标:认识泛型方法
public class Test {
public static void main(String[] args) {
//需求:要求接收任意对象数组
String[] name = {"刘德华", "郭富城", "黎明", "张学友" };
Student[] students = new Student[50];
printarray(name);
printarray(students);
}
// 泛型方法
// 返回值也是泛型,这样可以避免类型转换
public static <T> T printarray(T[]array){
return array[0];
}
}
通配符
- 就是"?", 可以在"使用泛型"的时候代表一切类型;ETKV是在定义泛型的时候使用。
泛型的上下限
- 泛型上限:?extends Car: ? 能接收的必须是Car或者其子类。
- 泛型下限:? super Car: ? 能接收的必须是Car或者其父类。
案例:
// 目标:通配符和上下限
public class Test2 {
public static void main(String[] args) {
// 需求:所有汽车要一起参与比赛。
ArrayList<BMW> bmws = new ArrayList<BMW>();
bmws.add(new BMW());
bmws.add(new BMW());
bmws.add(new BMW());
ArrayList<Benz> benzs = new ArrayList<Benz>();
benzs.add(new Benz());
benzs.add(new Benz());
benzs.add(new Benz());
// 正常是送车的集合,结果送成狗了,但程序依然可以运行,这是有bug的
// ArrayList<Dog> dogs = new ArrayList<Dog>();
// dogs.add(new Dog());
// dogs.add(new Dog());
// dogs.add(new Dog());
// go(dogs);
go(bmws);
go(benzs);
}
// 虽然BMW和Benz都是Car的子类,但是ArrayList<BMW>、ArrayList<Benz>、ArrayList<Car>并不是同一个类型
// 通配符:其实就是?,可以使用泛型的时候代表一切类型。ETKV是在定义时使用,而?是在使用时使用
// 泛型的上下限:? extends Car(上限,?必须是Car或者Car的子类),? super Car(下限,?必须是Car或者Car的父类)
//public static void go(ArrayList<BMW> cars){
//public static void go(ArrayList<?> cars){
public static void go(ArrayList<? extends Car> cars){}
}
class Car{}
class BMW extends Car{}
class Benz extends Car{}
class Dog{}
泛型的注意事项:擦除问题、基本数据类型问题
- 泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型的擦除。
- 泛型不能直接支持基本数据类型,只能支持对象类型(引用数据类型)
API
什么是API?
- API(Application Programming interface):应用程序编程接口。
- 就是Java帮我们已经写好一些程序,如:类、方法等,我们直接拿过来用就可以解决一些问题。
为什么要学别人写好的程序?
- 提高开发效率。
Object类的作用:
- Object类是Java中所有类的祖宗类,因此,Java中所有类的对象都可以直接使用Objcet类中提供的一些方法。
Objcet类的常见方法

toString存在的意义:toString默认返回的地址形式其实没什么意义,开发中输出对象更想看内容,因此toString是为了让子类重写
equals存在的意义:equals方法默认是比较两个对象的地址是否一样。比较两个对象的地址是否一致,可以直接使用“==”来比较,完全没必要使用equals。因此,Object提供的equals方法的意义是为了让子类重写,以便子类自己来定义比较规则(按照内容比较)。
案例:
学生类:
import java.util.Objects;
public class Student {
private String name;
private int age;
private String score;
public Student() {
}
public Student(String name, int age, String score) {
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getScore() {
return score;
}
public void setScore(String score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score='" + score + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
// 1.判断两个对象是否是同一个对象在比较,如果是,返回true
if (this == o) return true;
// 2. 判断o如果是null,或者两个对象的类型不一样,直接返回false
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name) && Objects.equals(score, student.score);
}
@Override
public int hashCode() {
return Objects.hash(name, age, score);
}
}
测试方法:
// 目标:掌握object的常用方法。
public class Test {
public static void main(String[] args) {
Student s1 = new Student("小昭", 18, "100");
// 1.toString默认返回的地址形式其实没什么意义,开发中输出对象更想看内容,因此toString是为了让子类重写
//System.out.println(s1.toString());//直接输出对象时,toString方法可以不写
System.out.println(s1);
System.out.println("-----------------------------");
// 2.equals方法默认是比较两个对象的地址是否一样。
// 比较两个对象的地址是否一致,可以直接使用“==”来比较,完全没必要使用equals。
// 因此,Object提供的equals方法的意义是为了让子类重写,以便子类自己来定义比较规则(按照内容比较)。
Student s2 = new Student("郡主", 20, "97");
Student s3 = new Student("郡主", 20, "97");
System.out.println(s2.equals(s3));
}
}
Objects
- Object是一个工具类,提供了很多操作对象的静态方法给我们使用。
案例:
学生类:
import java.util.Objects;
public class Student {
private String name;
private int age;
private String score;
public Student() {
}
public Student(String name, int age, String score) {
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getScore() {
return score;
}
public void setScore(String score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score='" + score + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
// 1.判断两个对象是否是同一个对象在比较,如果是,返回true
if (this == o) return true;
// 2. 判断o如果是null,或者两个对象的类型不一样,直接返回false
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name) && Objects.equals(score, student.score);
}
@Override
public int hashCode() {
return Objects.hash(name, age, score);
}
}
测试:
// 目标:掌握object的常用方法。
public class Test {
public static void main(String[] args) {
Student s1 = new Student("小昭", 18, "100");
// 1.toString默认返回的地址形式其实没什么意义,开发中输出对象更想看内容,因此toString是为了让子类重写
//System.out.println(s1.toString());//直接输出对象时,toString方法可以不写
System.out.println(s1);
System.out.println("-----------------------------");
// 2.equals方法默认是比较两个对象的地址是否一样。
// 比较两个对象的地址是否一致,可以直接使用“==”来比较,完全没必要使用equals。
// 因此,Object提供的equals方法的意义是为了让子类重写,以便子类自己来定义比较规则(按照内容比较)。
Student s2 = new Student("郡主", 20, "97");
Student s3 = new Student("郡主", 20, "97");
System.out.println(s2.equals(s3));
System.out.println("---------------------------------------");
Student s4 = null;
Student s5 = new Student("陈昆", 18, "78");
System.out.println(s4.equals(s5)); // 如果主调对象是null,直接就会报空指针异常。
// 今后
System.out.println(Objects.equals(s4, s5)); // 更安全,更可靠的解决空指针异常
}
}
包装类
为什么要有包装类?
- 包装类就是把基本类型的数据包装成对象。
![image]()
包装类的其他基本操作
-
可以把基本类型的数据转换成字符串类型。
public static String toString(double d)
public String toString() -
可以把字符串类型的数值转换成数值本身对应的数据类型。
public static int parseInt(String s)
public static Integer valueOf(String s)
案例:
// 目标:认识包装类,搞清楚他的作用
public class Test {
public static void main(String[] args) {
// 1. 把基本类型通过包装类包装成对象
int a = 10;
// Integer it = new Integer(a);
Integer it = Integer.valueOf(a);//手动包装
System.out.println(it);
// 2. 自动装箱机制,会把基本类型的数据可以直接变成对象赋值给包装类。
Integer it2 = 12;
Integer it3 = 12;
System.out.println(it2 == it3);
// 3. 自动拆箱机制,把包装类的对象直接变成基本类型的数据。
int it4 = it2;
System.out.println(it4);
System.out.println("--------------Java为包装类提供了新功能----------------");
//1. 功能1:包装类可以把基本类型的数据转换成字符串
int a1 = 123;
System.out.println(Integer.toString(a1));
String rs = a1 + ""; //这种方式简单,但是效率低,底层是通过StringBuilder实现的。
System.out.println(rs);
// 功能2:把字符串类型的数字转换成基本类型的数据(很有用)
String agestr = "23";
int a2 = Integer.parseInt(agestr);
String corcestr = "87.2";
double a3 = Double.parseDouble(corcestr);
a2 = Integer.valueOf(agestr);
a3 = Double.valueOf(agestr);
//3.由于泛型和集合都不支持基本数据类型,因为万物皆对象,因此包装类在集合和泛型中大量使用,而且必须使用。
}
}
总结:
- Integer.valueOf(a)方法中,会自动创建-128~127的类,在这个区间内的对象都一样,超过这个值会新建对象。
- 由于泛型和集合都不支持基本数据类型,因为万物皆对象,因此包装类在集合和泛型中大量使用,而且必须使用。



浙公网安备 33010602011771号