第11章 枚举与泛型总结
目录
1.枚举
1.1 使用枚举类型设置常量
例11.1
1.2 深入了解枚举类型
1.操作枚举类型成员的方法
例11.2
例11.3
例11.4
2.枚举类型中的构造方法
例11.5
例11.6
3 使用枚举类型的优势
2.泛型
2.1.回顾向上转型和向下转型
例11.7
2.2 定义泛型类
2.3 泛型的常规用法
1.定义泛型类时声明多个类型
2.定义泛型类时声明数组类型
例11.8
3.集合类声明容器的元素
例11.9
例11.10
2.4 型的高级用法
1.通过类型参数T的继承限制泛型类型
2.通过类型通配符的继承限制泛型类型
例11.11
3.继承泛型类与实现泛型接口
2.5 泛型总结
3.总结
1.枚举
JDK1.5 中新增了枚举类型与泛型。枚举类型可以取代以往常量的定义方式,即将常量封装在类或接口中,此外,它还提供了安全检查功能。泛型的出现不仅可以让程序员少写某些代码,主要的作用是解决类型安全问题,它提供编译时的安全检查,不会因为将对象置于某个容器中而失去其类型。
JDK1.5新增了举,举是一种数据类型,它是一系列具有名称的常量的集合。比如在学中所学的集合:A={1,2,3},当使用这个集合时,只能使用集合中的 1、2、3 这3个元素,不是过8个元素的值就无法使用。Java 同,比在程中定义了一个性别枚举,里只有两个值:男、女,那么在使用该枚举时,只能使用男和女这两个值,其他的任何值都是无法用的。本节将详细介绍枚举类型。
1.1 使用枚举类型设置常量
以往设置常量,通常将常量放置在接口中,这样在程序中就可以直接使用,并且该常量不能被修改,因为在接口中定义常量时,该常量的修饰符为 final与 static。
例如,在项目中创建 Constants 接口,在接口中定义常量的常规方式。
public interface Constants {
public static final int Constants A=1;public static final int Constants B=12;
}
在JDK1.5版本中新增枚举类型后就逐渐取代了这种常量定义方式,因为通过使用枚举类型,可以赋予程序在编译时进行检查的功能。使用枚举类型定义常量的语法如下:
publie enum Constanta(
Conatants_A,Constants_B,
Conatants_C,
}
其中,enum 是定义枚举类型的关键字。当需要在程序中使用该常量时,可以使用Constants ConstantsA来表示:
下面举例介绍枚举类型定义常量的方式。
例11.1
在项目中创建 Constants接口,在该接口中定义两个整型变量,其修饰符都是statie和final;之后定义名称为Constants2 的枚举类,将Constants接口的常量放置在该枚举类中;最后,创名称为 Constants类件。该类中doit和doit20进行不同方式的调用,再通过主方法进行调用,体现枚举类型定义常量的方式。
interface Constants { // 将常量放置在接口中public static final int Constants_A = 1;//在接口中定义常量的常规方式public static final int Constants_B = 12;//在接口中定义常量的常规方式}
public class H11_1 {//主函数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");//输出"doit() Constants_A"break;//结束case Constants.Constants_B://是否满足条件System.out.println("doit() Constants_B");//输出"doit() Constants_B"break;//结束}}public static void doit2(Constants2 c) { // 定义一个参数对象是枚举类型的方法switch (c) { // 根据枚举类型对象做不同操作case Constants_A://是否满足条件System.out.println("doit2() Constants_A");//输出"doit2() Constants_A"break;//结束case Constants_B://是否满足条件System.out.println("doit2() Constants_B");//输出"doit() Constants_B"break;//结束}}public static void main(String[] args) {H11_1.doit(Constants.Constants_A); // 使用接口中定义的常量H11_1.doit2(Constants2.Constants_A); // 使用枚举类型中的常量H11_1.doit2(Constants2.Constants_B); // 使用枚举类型中的常量H11_1.doit(3);// 使用枚举类型中的常量}}
结果
上述代码中,当用户调用doit法时,即使编译器不接受在接口中定义的常量参数,也不量作为其参数,也不会报错:但调用doit20方法,任意传递参数,编译器就会报错,因为这个方法只接受枚举类型的常
说明:
举类型可以在类的内部进行定义,也可以在类的外部定义。如果在类的内部定义,则类似于内部类形式,比例11.1 中,当编译该类时,除了ConstantsTest.class 外,还存在 ConstantsTestS1class 与 ConstantsTest$Constants2.class文件。
1.2 深入了解枚举类型
1.操作枚举类型成员的方法
枚举类型较传统定义常量的方式,除了具有参数类型检测的优势之外,还具有其他方面的优势。用户可以将一个枚举类型看作是一个类,它继承于java.lang.Enum 类,当定义一个枚举类型时,每一个枚举类型成员都可以看作是枚举类型的一个实例,这些枚举类型成员都默认被 final、public、 tatic修,使用类型成员时直接使用枚举类型名称调用枚举类型成员即可。
由于枚举类型对象继承于java.langEnum 类,所以该类中一些操作枚举类型的方法都可以应用到枚举类型中。表 11.1中列举了枚举类型中的常用方法。
(1)values()
枚举类型实例包含一个values()方法,该方法可以将枚举类型成员以数组的形式返回。
例11.2
在项目中创建ShowEnum类,在该类中使用枚举类型中的values()方法获取枚举类型中的成员变量。
import static java.lang.System.out;//导入 java.lang.System.out包
public class H11_2 {//主函数enum Constants2 { // 将常量放置在枚举类型中Constants_A, Constants_B// 将常量放置在枚举类型中}// 循环由values()方法返回的数组public static void main(String[] args) {//主方法for (int i = 0; i < Constants2.values().length; i++) {//使用for循环将枚举成员变量打印out.println("枚举类型成员变量:" + Constants2.values()[i]);//输出"枚举类型成员变量:" + Constants2.values()[i]}}}
结果
在例 11.2 中,由于values0方法将枚举类型的成员以数组的形式返回,所以根据该数组的长度进行循环操作,然后将该数组中的值返回。 (2)valueOf0与compareTo0) 枚举类型中静态方法valueOfO可以将普通字符串转换为枚举类型,而compareTo0)方法用于比较两个枚举类型成员定义时的顺序。调用compareTo0)方法时,如果方法中参数在调用该方法的枚举对象位置之前,则返回正整数;如果两个互相比较的枚举成员的位置相同,则返回 0;如果方法中参数在调用该方法的枚举对象位置之后,则返回负整数。
例11.3
在项目中创建EnumMethodTest类,在该类中使用枚举类型中的valueOf与compareTo()方法。
import static java.lang.System.out;//导入java.lang.System.out
public class H11_3 {//创建类enum Constants2 { // 将常量放置在枚举类型中Constants_A, Constants_B, Constants_C, Constants_D// 将常量放置在枚举类型中}// 定义比较枚举类型方法,参数类型为枚举类型public static void compare(Constants2 c) {//主函数// 根据values()方法返回的数组做循环操作for (int i = 0; i < Constants2.values().length; i++) {//使用for循环// 将比较结果返回out.println(c + "与" + Constants2.values()[i] + "的比较结果为:" + c.compareTo(Constants2.values()[i]));//输出c + "与" + Constants2.values()[i] + "的比较结果为:" + c.compareTo(Constants2.values()[i])}}// 在主方法中调用compare()方法public static void main(String[] args) {//主函数compare(Constants2.valueOf("Constants_B"));//输出Constants2.valueOf("Constants_B")}}
结果
(3)ordinalo
枚举类型中的ordinal0)方法用于获取某个枚举对象的位置索引值。
例11.4
在项目中创建EnumIndexTest类,在该类中使用枚举类型中的ordinal()方法获取枚举类型成员的位置索引。
import static java.lang.System.out;//导入java.lang.System.out
public class H11_4 {//创建类enum Constants2 { // 将常量放置在枚举类型中Constants_A, Constants_B, Constants_C // 将常量放置在枚举类型中}public static void main(String[] args) {//主函数for (int i = 0; i < Constants2.values().length; i++) {// 在循环中获取枚举类型成员的索引位置out.println(Constants2.values()[i] + "在枚举类型中位置索引值" + Constants2.values()[i].ordinal());//输出Constants2.values()[i] + "在枚举类型中位置索引值" + Constants2.values()[i].ordinal()}}}
结果
在例 11.4 中,当循环中获取每个枚举对象时,调用 ordinal()方法即可相应获取该枚举类型成员的索引位置。
2.枚举类型中的构造方法
在枚举类型中,可以添加构造方法,但是规定这个构造方法必须为 private 修饰符或者默认修饰符所修饰。从枚举类型构造方法的语法中可以看出,无论是无参构造方法还是有参构造方法,修饰权限都为private。定义一个有参构造方法后,需要对枚举类型成员相应地使用该构造方法,如 Constants_A("我是枚举成员A")和 Constants D(3)语句,相应地地使用了参数为String型和参数为int型的构造方法。然后可以在枚举类型中定义两个成员变量,在相购造方法中为这两个成员变量赋值,这样就可以在枚举类型中定义该成员变量的getXxx0方法了。
下面是在枚举类型中定义构造方法的实例。
例11.5
在项目中创建EnumConTest类, 在该类中定义枚举类型的构造方法。
import static java.lang.System.out;//导入java.lang.System.outpublic class H11_5 {//创建类enum Constants2 { // 将常量放置在枚举类型中Constants_A("我是枚举成员A"), // 定义带参数的枚举类型成员Constants_B("我是枚举成员B"),// 定义带参数的枚举类型成员Constants_C("我是枚举成员C"),// 定义带参数的枚举类型成员Constants_D(4);// 定义带参数的枚举类型成员private String description;//定义String descriptionprivate int i = 5;//定义int i = 5// 定义参数为String型的构造方法private Constants2(String description) {//创建子类this.description = description;//this.description = description}private Constants2(int i) { // 定义参数为int型的构造方法this.i = this.i + i;//this.i = this.i + i}public int getI() { // 获取i的值return i;//return i}}public static void main(String[] args) {//主函数out.println(Constants2.valueOf("Constants_C") + "调用getI()方法为:" + Constants2.valueOf("Constants_D").getI());//输出"Constants_C") + "调用getI()方法为:" + Constants2.valueOf("Constants_D").getI()}}
结果
在本实例中,调用getDescription()和getI方法,返回在枚举些类型定义的构造方法中设置的操作。这里将枚举类型中的构造方法设置为 private 修饰,以防止实例创化一个枚举对象。
除了可以使用例 11.5中所示的方法定义 getDescription()方法获取枚举类型成员定义时的描述之外,还可以将这个 getDescription()方法放置在接口中,使枚举类型实现该接口,然后使每个枚举类型实现接口中的方法。
例11.6
在项目中创建EnumInterface接口和枚举类型的 AnyEnum 类,在枚举类型AnyEnum类中实现带方法的接口,使每个枚举类型成员实现该接口中的方法。
import static java.lang.System.out;interface d {public String getDescription();public int getI();}public enum H11_6 implements d {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) {for (int i = 0; i < H11_6.values().length; i++) {out.println(H11_6.values()[i] + "调用getDescription()方法为:" + H11_6.values()[i].getDescription());out.println(H11_6.values()[i] + "调用getI()方法为:" + H11_6.values()[i].getI());}}}
结果
注意:
(1)从上面代码中可以看出,枚举类型可以实现一个或者多个接口,但是它不能继承类。因为编译器会默认将枚举类型继承自java.langEnum类,这一过程由编译器完成。
(2)枚举类型中的常量成员必须在其他成员之前定义,否则这个枚举类型不会产生对象。
1.3 使用枚举类型的优势
枚举类型声明提供了一种用户友好的变量定义方法,枚举了某种数据类型所有可能出现的值。总结枚举类型,它具有以下特点:
(1)类型安全。
(2)紧凑有效的数据定义。
(3)可以和程序其他部分完美交互。
2.泛型
在JDK1.5版本中提供了泛型概念,泛型实质上就是使程序员定义安全的类型。在没有出现泛型之前,Java也提供了对Object的引用“任意化”操作,这种任意化操作就是对Object引用进行“向下转型”及“向上转型”操作,但某些强制类型转换的错误也许不会被编译器捕捉,而在运行后出现异常,可见强制类型转换存在安全隐患,所以提供了泛型机制。本节就来探讨泛型机制。
2.1.回顾向上转型和向下转型
例11.7
public class H11_7 {private Object b; // 定义Object类型成员变量public Object getB() { // 设置相应的getXXX()方法return b;}public void setB(Object b) { // 设置相应的setXXX()方法this.b = b;}public static void main(String[] args) {//主函数H11_7 t = new H11_7();t.setB(new Boolean(true)); // 向上转型操作System.out.println(t.getB());t.setB(new Float(12.3));Float f = (Float) (t.getB()); // 向下转型操作System.out.println(f);}
}
结果
在实例中,Test 类中定义了私有的成员变量b,它的类型为Object类型,同时为其定义了相应的setXXX( )与getXXX( )方法。在类主方法中,将new Boolean(true)对象作为setB()方法的参数,由于setB()方法的参数类型为Object,这样就实现了“向上转型”操作。同时在调用getB()方法时,将getB( )方法返回的Object 对象以相应的类型返回,这个就是“向下转型”操作,问题通常就会出现在这里。因为“向上转型”是安全的,而如果进行“向下转型”操作时用错了类型,或者并没有执行该操作,就会出现异常,例如以下代码:
t.setB (new Float(12.3)) ;
Integer f= (Integer) (t.getB( ));
System. out.println(f) ;
面代码并不存 在语法错误,可以被编译器接受,但在执行时 会出现ClassCastException 异常。这样看来,“向下转型”操作通常会出现问题,而泛型机制有效地解决了这一问题。
2.2 定义泛型类
Object类为最上层的父类,很多程序员为了使程序更为通用,设计程序时通常使传入的做回的值都以Object类型为主。当需要使用这些实例时,必须正确地将该实例转换为原来的类型.则在运行时将会发生ClassCastException异常
在JDK1.5 版本以后,提出了泛型机制。其语法如下:
类名<T>
其中,T代表一个类型的名称。
public class OverClass<T> {//定义泛类型private T over; //定义泛型成员变量public T getOver() { //设置getXXX()方法return over;}public void setOver(T over) {//设置setXXX()方法this.over = over;}public static void main(String[] args) {OverClass<Boolean> over1= new OverClass<Boolean> ();OverClass<Float> over2= new OverClass<Float> ();over1.setOver(true); //不需要进行类型转换over2.setOver(12.3f); Boolean b = over1.getOver();//不需要进行类型转换Float f = over2.getOver(); System.out.println(b);System.out.println(f);}
}
结果
运行上述代码,结果与上例所示的结果一致。上面代码中定义类时,在类名后添加了一个<T>语句,这里便使用了泛型机制。可以将OverClass类称为泛型类,同时返回和接受的参数使用T这个类型。最后在主方法中可以使用Over<Boolean> 形式返回一个Boolean 型的对象,使用OverClass<Float>形式返回一个Float型的对象,使这两个对象分别调用setOver()方法不需要进行显式“向上转型”操作,setOver()方法直接接受相应类型的参数,而调用getOver()方法时,不需要进行“向下转型”操作,直接将getOver()方法返回的值赋予相应的类型变量即可。
从上面代码可以看出,使用泛型定义的类在声明该类对象时可以根据不同的需求指定<I>真正的类型,而在使用类中的方法传递或返回数据类型时将不再进行类型转换操作,而是使用在声明泛型类对象时“<>”符号中设置的数据类型。
使用泛型这种形式将不会发生ClassCastException异常,因为在编译器中就可以检查类型匹配是否正确。
例如,在项目中定义泛型类。
OverClass<Float> over2=new OverClass<F loat>();
over2.setover(12.3f);
//Integer i=over2.getOver();//不能将F1 oat型的值赋予Integer变量
在上面的代码中,由于over2对象在实例化时已经指定类型为Float,而最后一条 语句却将该对象获取出的Float类型值赋予Integer 类型,所以编译器会报错。而如果使用“向下转型”操作就会在运行上述代码时发生异常。
说明: 在定义泛型类时,一般类型名称使用T来表达,而容器的元素使用E来表达,具体的设置读者可以参看JDK 5.0以上版本的API。
2.3 泛型的常规用法
1.定义泛型类时声明多个类型
在定义泛型类时,可以声明多个类型。
Class<T1,T2>
Class:泛型类名称
其中,T1 和 T2 为可能被定义的类型。这样在实例化指定类型的对象时就可以指定多个类型。
MutiOverClass<Boolean,Float>=new Mutid OverClass<Boolean,Float>();
2.定义泛型类时声明数组类型
定义泛型类时也可以声明数组类型,下面的实例中定义泛型时便声明了数组类型。
例11.8
public class H11_8<T> {private T[] array; // 定义泛型数组public void SetT(T[] array) { // 设置SetXXX()方法为成员数组赋值this.array = array;}public T[] getT() { // 获取成员数组return array;}public static void main(String[] args) {H11_8<String> a = new H11_8<String>();String[] array = { "成员1", "成员2", "成员3", "成员4", "成员5" };a.SetT(array); // 调用SetT()方法for (int i = 0; i < a.getT().length; i++) {System.out.println(a.getT()[i]); // 调用getT()方法返回数组中的值}}
}
结果
本实例在定义泛型类时声明一个成员数组,数组的类型为泛型,然后在泛型类中相应设置setXXX()与getXXX()方法。
由此可见,可以在使用泛型机制时声明一个数组,但是不可以使用泛型来建立数组的实例。例如,下面的代码就是错误的:
public class ArrayClass <T>{
//private T[] array=newT[10]; //不能使用泛型来建立数组的实例
...
}
说明:JDK1.7版本中添加了一个新特性:自动推断实例化类型的泛型。所以这样的语法:
ArrayClass<String> a = new ArrayClass<>();
// 实现类的泛型为空会自动转换为:
ArrayClass<String> a = new ArrayClass<String>();
3.集合类声明容器的元素
实际应用中,通过在集合类中应用泛型可以使集合类中的元素类型保证唯一性,这样在运行时就不会产生ClassCastException异常,提高了代码的安全性和可维护性。可以使用K和V两个字符代表容器中的键值和与键值相对应的具体值。
例11.9
import java.util.HashMap;import java.util.Map;
public class H11_9 <K, V> {public Map<K, V> m = new HashMap<K, V>(); // 定义一个集合HashMap实例// 设置put()方法,将对应的键值与键名存入集合对象中public void put(K k, V v) {m.put(k, v);}public V get(K k) { // 根据键名获取键值return m.get(k);}public static void main(String[] args) {// 实例化泛型类对象H11_9<Integer, String> mu = new H11_9<Integer, String>();for (int i = 0; i < 5; i++) {// 根据集合的长度循环将键名与具体值放入集合中mu.put(i, "我是集合成员" + i);}for (int i = 0; i < mu.m.size(); i++) {// 调用get()方法获取集合中的值System.out.println(mu.get(i));}}
}
结果
其实在例11.9中定义的泛型类 MutiOverClass 纯属多余,因为在Java中这些集合框架已经都被泛发化了,可以在主方法中直接使用public Map<K、V>m= newHashMap <K.V>0;语句创建实例。然后题的用Map接口中的put()与get(方法完成填充容器或根据键名获取集合中具体值的功能,集合中需Hash Map这种集合类型之外,还包括Array List、Vector等。 下面的实例演示了这些集合的使用方法。
例11.10
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;public class H11_10 {public static void main(String[] args) {// 定义ArrayList容器,设置容器内的值类型为IntegerArrayList<Integer> a = new ArrayList<Integer>();a.add(1); // 为容器添加新值for (int i = 0; i < a.size(); i++) {// 根据容器的长度循环显示容器内的值System.out.println("获取ArrayList容器的值:" + a.get(i));}// 定义HashMap容器,设置容器的键名与键值类型分别为Integer与String型Map<Integer, String> m = new HashMap<Integer, String>();for (int i = 0; i < 5; i++) {m.put(i, "成员" + i); // 为容器填充键名与键值}for (int i = 0; i < m.size(); i++) {// 根据键名获取键值System.out.println("获取Map容器的值" + m.get(i));}// 定义Vector容器,使容器中的内容为String型Vector<String> v = new Vector<String>();for (int i = 0; i < 5; i++) {v.addElement("成员" + i); // 为Vector容器添加内容}for (int i = 0; i < v.size(); i++) {// 显示容器中的内容System.out.println("获取Vector容器的值" + v.get(i));}}
}
结果
注意:在定义集合对象时,如果没有指定具体的类型,泛型参数<T>的类型默认为<Object>,这时运行程序不会报错但是会有警告信息。
2.4 型的高级用法
泛型的高级用法主要包括通过类型参数T的继承和通过类型通配符的继承来限制泛型类型,另
外,开发人员还可以继承泛型类或者实现泛型接 口,本节将对泛型的一些高级用法进行讲解。
1.通过类型参数T的继承限制泛型类型
默认可以使用任何类型来实例化一个泛型类对象,但Java中也对泛型类实例的类型作了限制,这主要通过对类型参数T实现继承来体现。
class 类名称 <T extends anyClass>
anyClass:接口或者类
其中,anyClass 指某个接口或类。
使用泛型限制后,泛型类的类型必须实现或继承了anyClass 这个接口或类。无论anyClass是接口还是类,在进行泛型限制时都必须使用extends关键字。
例如,在项目中创建LimitClass类,在该类中限制泛型类型。
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class Limitclass<T extends List> {//限制泛型的类型
public static void main (string[] args) {//可以实例化已经实现List接口的类
Limitclass<ArrayList> 11 = new LimitClass<ArrayList>();
Limitclass<LinkedList>12 = new Limitclass<LinkedList>();
//这句是错误的,因为HashMap没有实List()接口
//LimitClass<HashMap> 13=new Limitclass<HashMap>();
上面代码中,将泛型作了限制,设置泛型类型必须实现List接口。例如,ArrayList和 LinkedList 都实现了List接口,而HashMap没有实现List接口,所以在这里不能实例化 HashMap类型的泛型对象。
当没有使用extends关键字限制泛型类型时,默认 Object类下的所有子类都可以实例化泛型类对象。如图11.11所示的两个语句是等价的。
2.通过类型通配符的继承限制泛型类型
在泛型机制中,提供了类型通配符,其主要作用是在创建一个泛型类对象时,限制这个泛型类的类型,或者限制这个泛型类型必须继承某个接口或某个类(或其子类)。要声明这样一个对象可以使用“?”通配符,同时使用extends 关键字来对泛型加以限制。
说明:
通过对类型参数T实现继承限制泛型类型时,在声明时就进行了限制,而通过对类型通配符实现继承限制泛型类型时,则在实例化时才进行限制。
使用泛型类型通配符的语法如下:
泛型类名称<?extends List> a=null;
其中,<? extends List>表示类型未知,当需要使用该泛型对象时,可以单独实例化。例如,在项目中创建一个类文件,在该类中限制泛型类型。
A<?extends List> a=null;
a=new A<ArrayList> ();
a=new A<LinkedList>();
如果实例化没有实现List 接口的泛型对象,编译器将会报错。例如,实例化HashMap对象时,编译器将会报错,因为 HashMap类没有实现List 接口。
除了可以实例化一个限制泛型类型的实例之外,还可以将该实例放置在方法的参数中。例如,在项目中创建一个类文件,在该类的方法参数中使用匹配字符串。
public void doSomething(A<? extends List> a){
}
在上述代码中,定义方式有效地限制了传入doSomething()方法的参数类型。
如果使用A<?>这种形式实例化泛型类对象,则默认表示可以将A指定为实例化Object 及以下的子类类型。读者可能对这种编码类型有些疑惑,下面的代码将直观地介绍A<?>泛型机制。
如下在代码中创建WildClass 类,演示在泛型中使用通配符形式。
例11.11
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;public class H11_11 {public static void main(String[] args) {List<String> l1 = new ArrayList<String>(); // 创建一个ArrayList对象l1.add("成员"); // 在集合中添加内容List<?> l2 = l1; // 使用通配符List<?> l3 = new LinkedList<Integer>();System.out.println("l1:" + l1.get(0)); // 获取l1集合中第一个值System.out.println("l2:" + l2.get(0)); // 获取l2集合中第一个值l1.set(0, "成员改变"); // 没有使用通配符的对象调用set()方法// l2.set(0, "成员改变"); // 使用通配符的对象调用set()方法,不能被调用// l3.set(0, 1);System.out.println("l1:" + l1.get(0)); // 可以使用l1的实例获取集合中的值System.out.println("l2:" + l2.get(0)); // 可以使用l2的实例获取集合中的值}
}
结果
上面代码中,由于对象11是没有使用A<?>这种形式初始化出来的对象,所以它可以调用set(方法改变集合中的值,但2与l3则是通过使用通配符的方式创建出来的,所以不能改变集合中的值,所以无法调用set()方法;另外,List<?>类型的对象可以接受String 类型的ArrayList集合,也可以接受Integer类型的LinkedList集合,也许有的读者会有疑问,List<?>12=11语句与List 12=11存在何种本质区别?使用通配符声明的名称实例化的对象不能对其加入新的信息,只能获取或删除。
技巧:
泛型类型限制除了可以向下限制之外,还可以向上限制,只要在定义时使用super关键字即可。例如,"A<? superList> a=null;”这样定义后,对象a只接受List接口或上层父类类型,如a=new A<Objec>0;o
3.继承泛型类与实现泛型接口
定义为泛型的类和接口也可以被继承与实现。
例如,在项目中创建一个类文件,在该类中继承泛型类。
public class Extendclass<T1>{
}
class Subclass<T1,T2,T3> extends ExtendClass<T1>{//泛型可以比父类多,但不可以比父
类少
}
如果在SubClass类继承ExtendClass类时保留父类的泛型类型,需要在继承时指明,如果没有指明,直接使用extends ExtendsClass语句进行继承操作,则SubClass类中的T1、T2和T3都会自动变为Object,所以在一般情况下都将父类的泛型类型保留。
定义的泛型接口也可以被实现。
例如,在项目中创建一个类文件,在该类中实现泛型接口。
interface TestInterface<T1>{
}
class SubClass2<T1,T2,T3> implements TestInterface<T1>{
}
2.5 泛型总结
使用泛型需遵循以下原则。
(1 )泛型的类型参数只能是类类型,不可以是简单类型,如A<int>这种泛型定义就是错误的,
(2)泛型的类型个数可以是多个.
(3 )可以使用extends关键字限制泛型的类型。
( 4)可以使用通配符限制泛型的类型。
3.总结
1、什么是枚举?
枚举是常量定义的一种方式;
ps:被final修饰的变量就是常量;
常量与变量的区别:https://blog.csdn.net/qq_36959774/article/details/88321229
2、枚举的好处?
(1)参数类型检测
例如: a变量为常量,EnumA.b为枚举
static final int a = 10;
void c (int d){
switch (d) {
case a:
syso(“a”)
}
} // 若要输入a但是其输入了int类型的其他值,只有在运行时才会检测出来,
void e (EnumA f){
switch (f) {
case f:
syso(“f”)
}
}// 若输入了其他类型(非枚举类型EnumA),就会编译报错;
(2)丰富的方法;
values():通过 “类名.values()” 的形式,将枚举全部返回;
valueOf();通过 “类名.valueOf(“字符串”)” 的形式,将字符串转换为枚举(若枚举中无此字符串会报错)
compareTo():通过"枚举.compareTo(“枚举”)",比较俩个枚举对象是否相等;
ordinal():通过"枚举.ordinal()"的方式,返回该枚举的索引;
(3)枚举类型的特点:
1、类型安全;
2、数据定义紧凑有效;
3、与程序的其他部分完美交互;
4、采用枚举类型的程序运行效率高。
二:泛型
1、什么是泛型?
泛型就是为了解决类型转换的问题(从上到下):及大类型到小类型的转换;
有些时候虽然我们可以强制转换,虽然编译期未报错,但是在运行期间,可能会报错;
2、泛型的使用?
(1)定义:类名A<T1,T2,T3…>, 然后为其建造get与set方法;
(2)使用:实例化:类名A<具体类型A,具体类型B,…> a = new 类名A<具体类型A,具体类型B,…>();
(3)赋值,取值:用set赋值、用get方法取值
3、泛型的特点?
(1)不可以使用泛型来建立数组的实例(编译报错);
(2)集合框架已经被泛型话了(例如Map<K,V>);
(3)可以使用extends关键字限制泛型的类型(向下限制)
通过使用 类名称A // 即T必须使anyClass的子类型 也成向下限制;
(4)可以使用 super关键字限制泛型的类型(向上限制)
通过使用 类名称A // 即T必须是AnyClass的父类型;
第11章 枚举与泛型总结相关推荐
- 第11-15章枚举|异常|常用类|集合|泛型
文章目录 第11章 枚举和注解 11.1举例 11.2枚举的二种实现方式 11.3enum 实现接口 11.4注解的理解 11.4基本的 Annotation 介绍 第12章 异常-Exception ...
- JavaSE_第11章 泛型
第11章 泛型 学习目标 能够使用泛型定义类.接口.方法 能够理解泛型上限 能够阐述泛型通配符的作用 能够识别通配符的上下限 第十一章 泛型 11.1 泛型的概念 11.1.1 泛型的引入 例如:生产 ...
- Java 第十一章总结 枚举与泛型
11.1 枚举 (1) 使用枚举类型设置常量 在项目中创建Constants接口,在接口中定义常量的常规方式. public interface Constants{ public static fi ...
- ios 获取一个枚举的所有值_凯哥带你从零学大数据系列之Java篇---第十一章:枚举...
温馨提示:如果想学扎实,一定要从头开始看凯哥的一系列文章(凯哥带你从零学大数据系列),千万不要从中间的某个部分开始看,知识前后是有很大关联,否则学习效果会打折扣. 系列文章第一篇是拥抱大数据:凯哥带你 ...
- 《JavaScript权威指南第7版》第11章 JavaScript标准库
第11章 JavaScript标准库 11.1 Set和Map 11.1.1 Set类 11.1.2 Map类 11.1.3 WeakMap和WeakSet 11.2 类型数组和二进制数据 11.2. ...
- JavaScript权威指南 第11章JavaScript标准库
JavaScript权威指南 第11章JavaScript标准库 第11章 JavaScript标准库 11.1 集合与映射 11.1.1 Set类 11.1.2 Map类 11.1.3 WeakMa ...
- Thinking in java 第11章 持有对象 笔记+习题
Thinking in java 第11章 持有对象 学习目录 11.1 泛型和类型安全的容器 1. 当你制定了某个类型作为泛型参数时,你并不仅限于只能将该确切类型的对象放置到容器中.向上转型也可一样 ...
- Linux就这个范儿 第11章 独霸网络的蜘蛛神功
Linux就这个范儿 第11章 独霸网络的蜘蛛神功 第11章 应用层 (Application): 网络服务与最终用户的一个接口. 协议有:HTTP FTP TFTP SMTP SNMP DNS ...
- 《Java编程思想》阅读笔记之第11章-持有对象
第11章-持有对象 容器类的引入:Java需要有不同的方式来保存对象(或说是对象的引用). 如数组可以保存一组对象或一组基本类型数据,也推荐使用,但是数组必需有固定的尺寸,但在实际的情况中,可能根本不 ...
- 0与1c语言编译,C语言程序设计(07776-1)第11章编译预处理课案.ppt
C语言程序设计(07776-1)第11章编译预处理课案.ppt 第11章 编译预处理 主要内容 宏定义 文件包含 条件编译 程序案例 小结 习题 11-1 宏定义 不带参数的宏定义 带参数的宏定义 终 ...
最新文章
- 数据结构 算法与应用C 语言描述第六章,数据结构算法与应用-C语言描述002.pdf
- 统计学习方法:朴素贝叶斯
- Multithread 之 introduction
- 中国交通节能减排行业运营效益状况及十四五建设格局分析报告2021-2027年
- yolo-v2 自己的数据集训练以及测试流程(仅供内部使用!)
- SAP CRM product customizing下载的第四个队列
- 漫画:什么是冒泡排序
- linux怎么修改sftp默认端口,转:linux 修改sftp服务默认提供者sshd的session timeout
- Java8————方法引用
- Web前端笔记-解决Vue编写的输入框(input、textarea等)使用JS设置value时提交表单无效的问题
- Mr.J--蓝桥杯--去注释
- poj3264Balanced Lineup(RMQ)
- 一种验证Linux kernel是否可用的Sanity Check方法
- Cocos2d-x CCNotificationCenter 通知中心
- 利用Apply的参数数组化来提高代码的优雅性,及高效性
- lindows.javaeye.com
- IntelliJ IDEA常见问题解决办法汇总
- python单例模式学习
- 打印机 打印机驱动 打印机如何与PC通信 什么通信协议 蓝牙打印机项目 蓝牙协议栈
- 数据库基础 之 “视图”