11.1枚举
枚举是一个被命名的整型常数的集合,用于声明一组带标识符的常数。枚举在曰常生活中很常见,例如一个人的性别只能是“男”或者“女”,一周的星期只能是 7 天中的一个等。类似这种当一个变量有几种固定可能的取值时,就可以将它定义为枚举类型。
11.1.1使用枚举类型设置常量
以往设置常量,通常将常量放置在接口中,这样在程序中就可以直接使用,并且该常量不能被修改,因为在接口中定义常量时,该常量的修饰符为final与static.
public interface Constants{
public static final int Constants_A=1;//定义一个泛型变量并赋初值
public static final int Conostants_B=12;
}
interface Constants { // 将常量放置在接口中
public static final int Constants_A = 1;
public static final int Constants_B = 12;
}
public class test12{
enum Constants2 { // 将常量放置在枚举类型中
Constants_A, Constants_B
}
// 使用接口定义常量
public static void doit(int c) { // 定义一个方法,这里的参数为int型
switch (c) { // 根据常量的值做不同操作
case Constants.Constants_A:
System.out.println("doit() Constants_A");
break;
case Constants.Constants_B:
System.out.println("doit() Constants_B");
break;
}
}
public static void doit2(Constants2 c) { // 定义一个参数对象是枚举类型的方法
switch (c) { // 根据枚举类型对象做不同操作
case Constants_A:
System.out.println("doit2() Constants_A");
break;
case Constants_B:
System.out.println("doit2() Constants_B");
break;
}
}
public static void main(String[] args) {
test12.doit(Constants.Constants_A); // 使用接口中定义的常量
test12.doit2(Constants2.Constants_A); // 使用枚举类型中的常量
test12.doit2(Constants2.Constants_B); // 使用枚举类型中的常量
test12.doit(3);
// ConstantsTest.doit2(3);
}
}
package com.lzw;
public class ConstantsTest {
enum Constants2 { //将常量放置在枚举类型中
constants_A, Constants_B
}
public static void doit2(Constants2 c) { //定义一个参数对象是枚举类型的方法
switch (c) { //根据枚举类型对象做不同操作
case constants_A:
System.out.println("doit2() Constants_A");
break;
case Constants_B:
System.out.println("doit2() Constants_B");
break;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ConstantsTest.doit2(Constants2.constants_A);//使用枚举类型中的常量
ConstantsTest.doit2(Constants2.Constants_B);//使用枚举类型中的常量
}
}
1.操作枚举类型成员的方法
枚举类型较传统定义常量的方式,除了具有参数类型检测的优势之外,还具有其他方面的优势。用户可以将一个枚举类型看作是一个类,它继承于java. lang. Enum类,当定义一个枚举类型时,每一个枚举类型成员都可以看作是枚举类型的一个实例,这些枚举类型成员都默认被final、public、static修饰,所以当使用枚举类型成员时直接使用枚举类型名称调用枚举类型成员即可。由于枚举类型对象继承于java. lang. Enum类,所以该类中一些操作枚举类型的方法都可以应用到枚举类型中。
public class ShowEnum {
enum Constants { // 将常量放置在枚举类型中
Constants_A, Constants_B, Constants_C, Constants_D
}
// 循环由values()方法返回的数组
public static void main(String[] args) {
Constants enumArray[] = Constants.values();//values()方法返回枚举数组
for (int i = 0; i < enumArray.length; i++) {
// 将枚举成员变量打印
System.out.println("枚举类型成员变量:" + enumArray[i]);
}
}
}
2.valueOf()与compareTo()
枚举类型中静态方法valueOft)可以将普通字符串转换为枚举类型,而compareTo(万房)较两个枚举类型成员定义时的顺序。调用compareTo(方法时,如果方法中参数在调用该方法对象位置之前,则返回正整数;如果两个互相比较的枚举成员的位置相同,则返回0;如参数在调用该方法的枚举对象位置之后,则返回负整数。
package com.lzw;
enum Constants { //将常量放置在枚举类型中
Constants_A, Constants_B, Constants_C, Constants_D
}
public class EnumMethodTest {
//定义比较枚举类型方法,参数类型为枚举类型
public static void compare(Constants c) {
//根据values()方法返回的数组
Constants array[] = Constants.values();
for (int i = 0; i < array.length; i++) {
//将比较结果返回
System.out.println(c + "与" + array[i] + "的比较结果为:" + c.compareTo(array[i]));
}
}
//主方法中调用compare()方法
public static void main(String[] args) {
// TODO Auto-generated method stub
compare(Constants.valueOf("Constants_B"));
}
}
package com.lzw;
public class EnumIndexTest {
enum Constants2 { //将常量放置在枚举类型中
Constants_A, Constants_B, Constants_C
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Constants2[] arrayCon = Constants2.values();
for (int i = 0; i < arrayCon .length; i++) {
//在循环中获取枚举类型成员的索引位置
System.out.println(arrayCon [i] + "在枚举类型中位置索引值" + arrayCon [i].ordinal());
}
}
}
package com.lzw;
public class EnumConTest {
enum Constants2 { //将常量放置在枚举类型中
Constants_A("我是枚举成员A"), //定义带参数的枚举类型成员
Constants_B("我是枚举成员B"),
Constants_C("我是枚举成员C"),
Constants_D(3);
private String description;
private int i = 4;
//定义参数为String型的构造方法
private Constants2(String description) { //定义默认构造方法
this.description=description;
}
private Constants2(int i) { //定义带参数为int型的构造方法
this.i=this.i+i;
}
public String getDescription() { //获取description的值
return description;
}
public int getI() {//获取i的值
return i;
}
}
public static void mian(String[] args) {
Constants2 array[] = Constants2.values();//获取枚举成员数组
for (int i = 0; i < array.length; i++) {
System.out.println(array[i] + "调用getDescription()方法为:"+array[i].getDescription());
}
Constants2 c2 = Constants2.valueOf("Constants_D");//将字符串转换成枚举对象
System.out.println(c2 + "调用getI()方法为:" + c2.getI());
}
}
interface EnumInterface {
public String getDescription();
public int getI();
}
public enum AnyEnum implements EnumInterface {
Constants_A { // 可以在枚举类型成员内部设置方法
public String getDescription() {
return ("我是枚举成员A");
}
public int getI() {
return i;
}
},
Constants_B {
public String getDescription() {
return ("我是枚举成员B");
}
public int getI() {
return i;
}
},
Constants_C {
public String getDescription() {
return ("我是枚举成员C");
}
public int getI() {
return i;
}
},
Constants_D {
public String getDescription() {
return ("我是枚举成员D");
}
public int getI() {
return i;
}
};
private static int i = 5;
public static void main(String[] args) {
AnyEnum array[] = AnyEnum.values();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]+ "调用getDescription()方法为:" +array[i].getDescription());
System.out.println(array[i] + "调用getI()方法为:" +array[i].getI());
}
}
}
11.1.3使用枚举类型的优势
enum Signal {
// 定义一个枚举类型
GREEN,YELLOW,RED;
}
public static void main(String[] args) {
for(int i = 0;i < Signal.values().length;i++) {
System.out.println("枚举成员:"+Signal.values()[i]);
}
}
EnumMap 与 EnumSet
为了更好地支持枚举类型,java.util 中添加了两个新类:EnumMap 和 EnumSet。使用它们可以更高效地操作枚举类型。
EnumMap 类
EnumMap 是专门为枚举类型量身定做的 Map 实现。虽然使用其他的 Map(如 HashMap)实现也能完成枚举类型实例到值的映射,但是使用 EnumMap 会更加高效。
HashMap 只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定并且有限,所以 EnumMap 使用数组来存放与枚举类型对应的值,使得 EnumMap 的效率非常高。
11.2泛型
Java 集合之所以被设计成这样,是因为集合的设计者不知道我们会用集合来保存什么类型的对象,所以他们把集合设计成能保存任何类型的对象,只要求具有很好的通用性,但这样做带来如下两个问题:
集合对元素类型没有任何限制,这样可能引发一些问题。例如,想创建一个只能保存 Dog 对象的集合,但程序也可以轻易地将 Cat 对象“丢”进去,所以可能引发异常。
由于把对象“丢进”集合时,集合丢失了对象的状态信息,集合只知道它盛装的是 Object,因此取出集合元素后通常还需要进行强制类型转换。这种强制类型转换既增加了编程的复杂度,也可能引发 ClassCastException 异常。
泛型本质上是提供类型的“类型参数”,也就是参数化类型。我们可以为类、接口或方法指定一个类型参数,通过这个参数限制操作的数据类型,从而保证类型转换的绝对安全。
11.2.1回顾”向上转型“与”向下转型“
public class Jjjj {
public static void main(String[] args) {
// 创建3个Book对象
Book book1 = new Book(1, "唐诗三百首", 8);
Book book2 = new Book(2, "小星星", 12);
Book book3 = new Book(3, "成语大全", 22);
Map<Integer, Book> books = new HashMap<Integer, Book>(); // 定义泛型 Map 集合
books.put(1001, book1); // 将第一个 Book 对象存储到 Map 中
books.put(1002, book2); // 将第二个 Book 对象存储到 Map 中
books.put(1003, book3); // 将第三个 Book 对象存储到 Map 中
System.out.println("泛型Map存储的图书信息如下:");
for (Integer id : books.keySet()) {
// 遍历键
System.out.print(id + "——");
System.out.println(books.get(id)); // 不需要类型转换
}
List<Book> bookList = new ArrayList<Book>(); // 定义泛型的 List 集合
bookList.add(book1);
bookList.add(book2);
bookList.add(book3);
System.out.println("泛型List存储的图书信息如下:");
for (int i = 0; i < bookList.size(); i++) {
System.out.println(bookList.get(i)); // 这里不需要类型转换
}
}
}
public class Jjjj {
public static <T> void List(T book) { // 定义泛型方法
if (book != null) {
System.out.println(book);
}
}
public static void main(String[] args) {
Book stu = new Book(1, "细学 Java 编程", 28);
List(stu); // 调用泛型方法
}
}
11.2.4泛型的高级用法
泛型的用法非常灵活,除在集合、类和方法中使用外,本节将从三个方面介绍泛型的高级用法,包括限制泛型可用类型、使用类型通配符、继承泛型类和实现泛型接口。
1. 限制泛型可用类型
在 Java 中默认可以使用任何类型来实例化一个泛型类对象。
// 限制ListClass的泛型类型必须实现List接口
public class ListClass<T extends List> {
public static void main(String[] args) {
// 实例化使用ArrayList的泛型类ListClass,正确
ListClass<ArrayList> lc1 = new ListClass<ArrayList>();
// 实例化使用LinkedList的泛型类LlstClass,正确
ListClass<LinkedList> lc2 = new ListClass<LinkedList>();
// 实例化使用HashMap的泛型类ListClass,错误,因为HasMap没有实现List接口
// ListClass<HashMap> lc3=new ListClass<HashMap>();
}
11.2.5泛型总结
泛型方法使得该方法能够独立于类而产生变化。如果使用泛型方法可以取代类泛型化,那么就应该只使用泛型方法。另外,对一个 static 的方法而言,无法访问泛型类的类型参数。因此,如果 static 方法需要使用泛型能力,就必须使其成为泛型方法。