枚举类型可以取代以往的常用的定义方式,即将常量封装在类或者接口中,此外它还提供了安全检查功能。枚举类型本质上还剋以类的形式存在。泛型的出现不仅可以让程序员少写一些代码,更重要的是它可以解决类型安全问题。泛型提供了编译时的安全检查。不会因为将对象至于某个容器中而失去其类型,
13.1枚举类型
使用枚举类型可以取代前面的学习过的定义常量的方式,同时枚举类型还复制程序在编译时进行检查功能能
13.1.1 使用枚举类型定义常量
设置常量时 我们通常将常量放在接口中的 这样在程序中就可以直接使用。该常量不能被修改,因为在接口中定义常量时,该常量的修饰符final与static 常规的定义和枚举的定义如下
常规的定义:
package 第十三章;public interface SeasonInterface {//接口类//在接口中定义了四个常量final int spring=1;final int summer=2;final int autumn=3;final int winter=4;
}
枚举类型定义如下:
package 第十三章;public enum SeasonEnum {//枚举类 enun里面默认包含了 public final staticspring("万物复苏"),//注意参数后面不是分后而是逗号summer("烈日炎炎"),autumn("秋草枯黄"),winter("白雪皑皑"),
}
使用枚举类型定义常量的话 可以剪短代码量
下面使用例题来解释:
//接口定义
public interface SeasonInterface {//接口类//在接口中定义了四个常量final int spring=1;final int summer=2;final int autumn=3;final int winter=4;
}
//枚举类型定义
public enum SeasonEnum {//枚举类 enun里面默认包含了 public final staticspring("万物复苏"),//注意参数后面不是分后而是逗号summer("烈日炎炎"),autumn("秋草枯黄"),winter("白雪皑皑"),
}
package 第十三章;public class SeasonDemo {public static void main(String[]args) {printSeason1(3);printSeason2(SeasonEnum.spring);//使用枚举方法}private static void printSeason2(SeasonEnum season) {//传入枚举类switch(season) {//传入季节的枚举类case spring://传入枚举类型的springSystem.out.println("春天");break;//如果是的话就输出 再跳出不是就接着下一条case summer:System.out.println("夏天");break;case autumn:System.out.println("秋天");break;case winter:System.out.println("冬天");break;default:System.out.println("数字有误");}}public static void printSeason1(int i) {//传入参数 printSeason1(3)到int i 中 传入给iswitch(i) {case SeasonInterface.spring:System.out.println("春天");break;case SeasonInterface.summer:System.out.println("夏天");break;case SeasonInterface.autumn:System.out.println("秋天");break;case SeasonInterface.winter:System.out.println("冬天");break;default:System.out.println("数字有误");}}
}
代码图如下
运行结果如下:
秋天
春天
13.1.2深入了解枚举类型
枚举类型较传统定义常量的方式,除具有参数类型检测的优势外 还有其他的又是,,用户可以将一个枚举类型看作一个类,它继承于java.lang.Enum类,当定义了一个枚举类型时,没一个枚举类型的成员都看作是一个实例,这些枚举类型的成员都默认为final public static修饰 所以当使用枚举类型成员是可以直接使用枚举类型的名称调用枚举类型成员即可 所以该类中的一些操作枚举类型的方法都可以应用到枚举类型中 常用方法如下:
方法 | 具体含义 | 使用方法 | 举例 |
values() | 该方法可以将枚举类型成员以数组的形式返回 | 枚举类型名称.values() | cibstabts2.value() |
valueOf() | 该方法可以实现将普通字符串转换为枚举实例 | 枚举类型名称.valueOf() | cibstabts2.valueOf("ABC") |
CompareTo() | 该方法将比较两个枚举对象定义时的顺序 | 枚举对象.compareTo() | Constants_A. compareTo(comparets_b) |
ordinal() | 该方法用于得到枚举成员的位置索引 | 枚举对象.ordinal() | Constants_A.ordinal() |
1.values()方法
枚举类型实例包含一个values()方法,该方法将没居中的所有枚举类型值以数组的形式返回 代码如下:
package 第十三章;public enum SeasonEnum {//枚举类 enun里面默认包含了 public final staticspring("万物复苏"),//注意参数后面不是分后而是逗号summer("烈日炎炎"),autumn("秋草枯黄"),winter("白雪皑皑");//枚举类的构造方法只能是私有的private String introduce;public String getIntroduce() {return introduce; }private SeasonEnum() {}private SeasonEnum(String introduce) {this.introduce = introduce;}
}
public class SeasonDemo1 {public static void main(String[] args) {SeasonEnum[] seasons = SeasonEnum.values();//SeasonEnum.values是获取SeasonEnum的最初值 就是将SeasonEnum文件中的值传入给该数组 然后再for循环打印出来for(int i = 0; i<seasons.length;i++) {SeasonEnum temp =seasons[i];System.out.println(temp+temp.getIntroduce());}}}
代码图如下
运行结果如下
spring万物复苏
summer烈日炎炎
autumn秋草枯黄
winter白雪皑皑
2.valueOf()方法与compareTo方法()
枚举类型中静态方法valueOf()方法可以将普通字符串转换为枚举类型,而compareTo方法用于比较两个枚举类型对象定义是的顺序
3.ordinal()方法
枚举类型中的ordinal()方法用于获取某个枚举对象的位置索引值
4.枚举类型中的构造方法
在美剧类型中可以添加构造方法但是规定这个构造方法必须配private修饰符所修饰枚举类型定义的构造方法语法如下
//package 第十三章;public enum SeasonEnum {//枚举类 enun里面默认包含了 public final staticspring("万物复苏"),//注意参数后面不是分后而是逗号summer("烈日炎炎"),autumn("秋草枯黄"),winter("白雪皑皑");//枚举类的构造方法只能是私有的private String introduce;public String getIntroduce() {return introduce; }private SeasonEnum() {}private SeasonEnum(String introduce) {this.introduce = introduce;}
}
package 第十三章;public class SeasonDemo1 {public static void main(String[] args) {SeasonEnum[] seasons = SeasonEnum.values();//SeasonEnum.values是获取SeasonEnum的最初值 就是将SeasonEnum文件中的值传入给该数组 然后再for循环打印出来for(int i = 0; i<seasons.length;i++) {SeasonEnum temp =seasons[i];System.out.println(temp+temp.getIntroduce());}}}
13.1.3使用枚举类型的优势
枚举类型声明提供了一种对用户有好的变量定义方法,枚举某种数据类型所有可能出现的值 总结枚举类型,它具有以下特点
1.类型安全
2.紧凑有效的数据定义
3.可以和程序其他部分完美交互
4.允许显效率高
13.2泛型
泛型实质上就是程序员定义安全的类型,在没有出现泛型之前,java也提供了队Object类型的引用“任意化” 操作 这种任意话操作就是对object类型引用进行向上或者向下的转型操作,但某些强制类型转换的错误也许不会背编译器捕捉,而运行后出现的异常,可见强制类型转换存在安全隐患,所以在此提供了泛型机制,
13.2.2定义泛型类
Object类为最上层的父类,很多程序员为了让程序更为通用,设计程序的时候通常使用传入的值与返回的值都已Object类型为主。当需要使用这些实例的时候,必须正确地将该实例转换为原来的实例,否则在运行是会发生ClassCastException异常
为了预防这种问题 java提供了泛型机制
类名 <T>
其中T是泛型地名称 , 代表了某一种类型。开发者在创建该类对象时 需要制定T代表了具体哪种类型,如果不指定的话 T则采用了Object类型
如以下代码所示
package 第十三章;public class Book <T>{
private T booklnfo;
public Book(T booklnfo) {//参数为类型参地构造方法this.booklnfo =booklnfo;//给消息赋值
}
public T getBooklnfo() {return booklnfo;
}public static void main(String[] args) {// TODO Auto-generated method stubBook<String>bookName = new Book<String>("《java从入门到退学》");//创建String类型的书名Book<String>bookAuthor = new Book<String>("明日科技");//创建String类型的作者Book<Double>bookPrice = new Book<Double>(69.8); //创建Double类型的价格对象Book<Boolean>hasSource = new Book<Boolean>(true);//创建boolean类型判断是否赋值源代码System.out.println("书名:"+bookName.getBooklnfo());//然后依次输出System.out.println("作业:"+bookAuthor.getBooklnfo());System.out.println("价格:"+bookPrice.getBooklnfo());System.out.println("是否附赠源码:"+hasSource.getBooklnfo());}}
87代码图 以及运行结果图
代码中一共new了四个对象 两个 String类型 一个double类型 一个boolean类型 依次定义 然后输出 使用泛型定义额类在生命该类对象时 可以根据不同地需求指定<T>真正地类型 ,而是在使用类中的方法传递或返回 数据类型时将不再进行类型转换操作,而是使用在生命泛型类对象是“<>”符号中设置数据类型
13.2.3 泛型的常规用法
1. 在定义泛型类时,可以声明多个类型 代码如下
class MyClass<T1,T2>{}
其T1,T2是可以背定义的类型
这样的话既可以一下实例化多个类型 代码如下
MyClass<Boolean,Float> m = new MyClass <Boolean,Float>();
2. 定义泛型类 时声明数组类型 代码如下
package 第十三章;public class ArrayClass <T>{
private T[]array;//创建泛型的数组v
public T[]getArray(){//使用get方法来读取return array;//返回array
}
public void steArray(T[]array) {//使用set方法this.array=array;//this关键字给array赋值
}
public static void main (String[]args) {ArrayClass<String>demo=new ArrayClass<String>();//创建泛型为String类型的独享String value[]= {"成员1","成员2","成员3","成员4","成员5",};//添加数据demo.steArray(value);String array[] = demo.getArray();//使用get方法读取读取然后一次遍历输出for(int i = 0;i<array.length;i++) {//循环遍历出数组中的数据System.out.println(array[i]);}
}
}
代码图 以及运行结果图
3.集合类声明容器的元素
JDK中的集合接口,集合类都被定义了泛型,其中List<E>的泛型E实际上就是element元素的首字母Map<K,V>的泛型 K和V就是key键和value键的首字母。常用的被泛型化的集合类如下
表13.2常用的被泛型化的集合类
集合类 | 泛型定义 |
ArrayList | ArrayList<E> |
HashMap | HashMap<K,V> |
HashSet | HashSet<E> |
package 第十三章;
public class Book <T>{
private T booklnfo;
public Book(T booklnfo) {this.booklnfo =booklnfo;
}
public T getBooklnfo() {return booklnfo;
}public static void main(String[] args) {// TODO Auto-generated method stubBook<String>bookName = new Book<String>("《java从入门到退学》");//创建String类型的书名Book<String>bookAuthor = new Book<String>("明日科技");//创建String类型的作者Book<Double>bookPrice = new Book<Double>(69.8); //创建Double类型的价格对象Book<Boolean>hasSource = new Book<Boolean>(true);//创建boolean类型判断是否赋值源代码System.out.println("书名:"+bookName.getBooklnfo());System.out.println("作业:"+bookAuthor.getBooklnfo());System.out.println("价格:"+bookPrice.getBooklnfo());System.out.println("是否附赠源码:"+hasSource.getBooklnfo());}}
13.2.4泛型的高级用法
泛型的高级使用包括用法包括限制泛型可用类型和使用类型的通配符等等
1.限制泛型可用类型
默认可以使用任何类型来实例化一个泛型对象,但是java中也对泛型类实例的类型做了限制 如下:
class 类名 <T extebds anyClass>
其中anyClass时之某个接口或者类
使用泛型限制后,泛型类的类型必须实现继承anyClass这个接口或者类anyClass是接口还是类在进行泛型限制时都必须使用extends关键字
package 第十三章;import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;public class LimitClass <T extends List>{
public static void main (String[]args) {LimitClass<ArrayList>l1=new LimitClass<ArrayList>();LimitClass<LinkedList>l2=new LimitClass<LinkedList>();//这句时错误的因为hashMap类没有实现Lis()接口LimitClass<HashMap>l3 =new LimitClass<HashMap>();
}}
在实例中设置泛型类型必须实现List接口 例如ArrayList类和LinkedLisr类都实现了List接口,而HashMap没有实现List接口,所以在这里不能实力换HashMao类型的泛型对象
当没有使用extends关键字限制类型时默认Object类夏的所有子类都可以实例化泛型对象
2.使用通配符
在泛型机制中,提供了类型通配符 其主要作用是在创建一个泛型类对象时限制了这个泛型类的类型实现或某个接口或类的子类。要声这昂一个对象使用“?”通配符来表示同时使用exens关键字来对泛型加以限制 语法如下:
泛型类名称<? extends List> a=null;
其中<? extends List> a=null表示类型未知,当需要使用该反省对象时,可以单独的实例化
<? extends List> a=null
a = new A<ArrayList>();
a =new A<LinkedList>();
如果实例化没有实现List接口对象,编译器会报错的,例如实例化HashMap对象时,编译器将会报错,因为HashMap类没有实现List接口
处理可以实例化一个限制泛型类型的实例还可以将该实例放置在方法中的参数中
public void doSomething(A<?extendx List>a){}
在上述代码中,定义方法有效的限制了传入diSimething()方法
如果使用A<?>这种形式实例化泛型对象,则默认表示可以将A指定为实例化Object及以下的子类类型
List<String>l1=new ArrayList<String>();//实例化一个ArrayList对象
l1.add("成员")//添加成员
List<?>l2=l1;//使用通配符
List<?>l3=new LinkedList<linger>();
System.out.println("l2.get(0));//获取集合中第一个值
3.继承泛型类与实现泛型接口
定义为泛型的类和接口也可以被继承与实现如下:
class ExtendsClass<T1>{}
class SybClass<T1 T2 T3>extends ExtendClass<T1>{}
如果在SubClass类继承ExtendClass类时保留父类泛型类型,需要继承时指明,如果没有指明直接使用“extends ExtendsClass” 语句进行继承操作则SubClass中的T1 T2 T3douhuizidongbianchengwei Object类型,所以在一般情况下都会将父类的繁星欸写保存,
顶贴一泛型的接口也可以被实现。如下
interface Somelnterface<T1>{}
class SubClass <T1 T2 T3>impements Somlnterface<T1>{}
总结如下
泛型的类型参数只能是类类型,不可以时简单类型 入A<int>这种泛型定义就是错误的
泛型的类型个数可以是多个
可以使用extends关键字限制泛型的类型
可以使用通配符限制泛型的类型