第11章 枚举与泛型

本文详细介绍了Java中的枚举和泛型。枚举是一种安全的常量集合,提供类型安全,便于使用。文章讲解了如何定义枚举类型、枚举的优势以及如何操作枚举成员。泛型则提供了类型安全的机制,避免了强制类型转换可能导致的异常。文中阐述了泛型的基本用法、高级用法,包括类型参数继承限制、类型通配符的使用等,并给出了相关示例。
摘要由CSDN通过智能技术生成

目录

11.1 枚举

11.1.1 使用枚举类型设置常量

11.1.2  深入了解枚举类型

1.操作枚举类型成员的方法

2.枚举类型中的构造方法

11.1.3使用枚举类型的优势

11.2  泛型

11.2.1 回顾“向.上转型”与“向下转型”

11.2.2 定义泛型类

11.2.3  泛型的常规用法

1.定义泛型类时声明多个类型

2.定义泛型类时声明数组类型

 3.集合类声明容器的元素

11.2.4泛型的高级用法

1.通过类型参数T的继承限制泛型类型

2.通过类型通配符的继承限制泛型类型

3.继承泛型类与实现泛型接口

11.2.5 泛型总结

11.3  小结


11.1 枚举

JDK 1.5中新增了枚举,枚举是一种数据类型, 它是系列具有名称的常量的集合。 比如在数学中所

学的集合: A={1,2,3}, 当使用这个集合时,只能使用集合中的1、 2、3这3个元素,不是这3个元素

的值就无法使用。Java 中的枚举是同样的道理,比如在程序中定义了一个性别枚举,里面只有两

个值:男、女,那么在使用该枚举时,只能使用男和女这两个值,其他的任何值都是无法使用的。

本节将详细介绍枚举类型。

11.1.1 使用枚举类型设置常量

public inrerface constants {

public static final int constants_A=1;

public static final int constants_B=12;

}

在JDK1.5版本中新增枚举类型后就逐渐取代了这种常量定义方式,因为通过使用枚举类型,可以

赋予程序在编译时进行检查的功能。使用枚举类型定义常量的语法如下:

public enum Constants {

Constants_A,

Constants_B,

Constants_C,

}

其中,enum是定义枚举类型的关键字。当需要在程序中使用该常量时,可以使用

CostansConstants_A来表示。

下面举例介绍枚举类型定义常量的方式。

在项目中创建Constats接口,在该接口中定义两个整型变量,其修饰符都是static和final;之后定义

名称为Constant2的枚举类,将Constants接口的常量放置在该枚举类中:最后,创建名称为

Constants的类文件。在该类中先通过doit()和doit2()进行不同方式的调用,再通过主方法进行调

用,体现枚举类型定义常量的方式。

interface Constants {
	 public static final int Constants_A = 1;
	 public static final int Constants_B = 12;
	}
public class ConstantsTaest {
	 enum Constants2{
	  Constants_A,Constants_B
	 }
	 public static void doit(int c) {
	  switch (c) {
	  case Constants.Constants_A:
	   System.out.println("doit() Constants.Constants_A");
	   break;
	  case Constants.Constants_B:
	   System.out.println("doit() Constants.Constants_B");
	   break;
	  }
	 }
	 public static void doit2(Constants2 c) {
	  switch (c) {
	  case Constants_A:
	   System.out.println("doit2() Constants.Constants_A");
	   break;
	  case Constants_B:
	   System.out.println("doit2() Constants.Constants_B");
	   break;
	 }
	}
	 public static void main(String[] args) {
	  ConstantsTaest.doit(Constants.Constants_A);
	  ConstantsTaest.doit2(Constants2.Constants_A);
	  ConstantsTaest.doit2(Constants2.Constants_B);
	  ConstantsTaest.doit(3); 
	  }
	 }

在上述代码中,当用户调用doit()方法时,即使编译器不接受在接口中定义的常量参数,也不会报

错:但调用doit2()方法,任意传递参数, 编译器就会报错,因为这个方法只接受枚举类型的常量作

为其参数。

11.1.2  深入了解枚举类型

1.操作枚举类型成员的方法

枚举类型较传统定义常量的方式,除了具有参数类型检测的优势之外,还具有其他方面的优势。用

户可以将一个枚举类型看作是-一个类,它继承于java.lang.Enum类,当定义一个枚举类型时,每

一个枚举类型成员都可以看作是枚举类型的一个实例,这些枚举类型成员都默认被final、public、

static修饰,所以当使用枚举类型成员时直接使用枚举类型名称调用枚举类型成员即可。

由于枚举类型对象继承于java.lang.Enum 类,所以该类中一些操作枚举 类型的方法都可以应用到

枚举类型中。表11.1 中列举了枚举类型中的常用方法。

枚举类型的常用方法

 (1) values()

枚举类型实例包含一个 values()方法,该方法可以将枚举类型成员以数组的形式返回。

在项目中创建ShowEnum类,在该类中使用枚举类型中的values()方法获取枚举类型中的成员变

量。

public class ShowEnuw {
	enum Constants{
		  Constants_A,Constants_B,Constants_C,Constants_D
		 }
		 public static void main(String[] args) {
		  Constants enumArray[] = Constants.values();
		  for(int i = 0;i<enumArray.length;i++) {
		   System.out.println("枚举类型成员变量:"+ enumArray[i]);
		  }
		 }
}

由于values()方法将枚举类型的成员以数组的形式返回,所以根据该数组的长度进行循环操作,然

后将该数组中的值返回。

(2) valueOf()与compareTo()

枚举类型中静态方法valueOf()可以将普通字符串转换为枚举类型,而compareTo()方法用于比较两

个枚举类型成员定义时的顺序。调用compareTo()方法时,如果方法中参数在调用该方法的枚举对

象位置之前,则返回正整数;如果两个互相比较的枚举成员的位置相同,则返回0;如果方法中参数在

调用该方法的枚举对象位置之后,则返回负整数。

在项目中创建EnumMethodTest类,在该类中使用枚举类型中的valueOf()与compareT0()方法。

package IFather;
import static java.lang.System.out;
enum Constants2 { // 将常量放置在枚举类型中
 Constants_A, 
 Constants_B, 
 Constants_C, 
 Constants_D
}
public class EnumMethodTest {
 // 定义比较枚举类型方法,参数类型为枚举类型
 public static void compare(Constants2 c) {
  // 根据values()方法返回的数组做循环操作
  for (int i = 0; i < Constants2.values().length; i++) {
   // 将比较结果返回
   out.println(c + "与" + Constants2.values()[i] + "的比较结果为:" + c.compareTo(Constants2.values()[i]));
  }
 }
 // 在主方法中调用compare()方法
 public static void main(String[] args) {
  compare(Constants2.valueOf("Constants_B"));
 }
}

  

(3) ordinal()

枚举类型中的ordinal0方法用于获取某个枚举对象的位置索引值。

在项目中创建EnumIndexTest类,在该类中使用枚举类型中的ordinal()方法获取枚举类型成员的位

置索引。

package IFather;
import static java.lang.System.out;
public class EnumindexTest {
 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());
  }
 }
}

  

当循环中获取每个枚举对象时,调用ordinal()方法即可相应获取该枚举类型成员的索引位置。

2.枚举类型中的构造方法

在枚举类型中,可以添加构造方法,但是规定这个构造方法必须为private 修饰符或者默认修饰符

所修饰。枚举类型定义的构造方法语法如下:

public enum Constants2{

Constants_A("我是枚举成员A"),

Constants_B("我是枚举成员B"),

Constants_C("我是枚举成员C"),

Constants_D(3);

String description;

int i;

private Constants2(){    //定义默认构造方法

}

//定义带参数的构造方法,参数类型为字符串型

private Constants2(String description){

this.description=description;

}

private Constants2(int i){    //定义带参数的构造方法,参数类型为整型

this.i=this.i+i;

}

}

 从枚举类型构造方法的语法中可以看出,无论是无参构造方法还是有参构造方法,修饰权用食为

private。定义一个有参构造方法后,需要对枚举类型成员相应地使用该构造方法,如Constants A

我是枚举成员A")和Constants_ D(3)语句,相应地使用了参数为String型和参数为int型的构造方

法,然后可以在枚举类型中定义两个成员变量,在构造方法中为这两个成员变量赋值,这样就可以

在为举类型中定义该成员变量的getXXX()方法了。

下面是在枚举类型中定义构造方法的实例。

在项 目中创建EnumConTest类,在该类中定义枚举类型的构造方法。

package IFather;
import static java.lang.System.out;
public class EnumConTest {
		enum Constants2 { // 将常量放置在枚举类型中
			Constants_A("我是枚举成员A"), // 定义带参数的枚举类型成员
			Constants_B("我是枚举成员B"), Constants_C("我是枚举成员C"), Constants_D(3);
			private String description;
			private int i = 4;

			private Constants2() {
			}

			// 定义参数为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 main(String[] args) {
			for (int i = 0; i < Constants2.values().length; i++) {
				out.println(Constants2.values()[i] + "调用getDescription()方法为:" + Constants2.values()[i].getDescription());
			}
			out.println(Constants2.valueOf("Constants_D") + "调用getI()方法为:" + Constants2.valueOf("Constants_D").getI());
		}
	}

  

在本实例中,调用getDescription()和getI()方法,返回在枚举类型定义的构造方法中设置的操作。

这里将枚举类型中的构造方法设置为private修饰,以防止实例化一个枚举对象。

除了可以使用例11.5中所示的方法定getDescription()方法获取枚举类型成员定义时的描述之外,还

可以将这个getDescription()方法放 置在接口中,使枚举类型实现该接口,然后使每个枚举类型实

现接口中的方法。

在项目中创建EnumInterface接口和枚举类型的AnyEnum类,在枚举类型AnyEnum类中实现带方

法的接口,使每个枚举类型成员实现该接口中的方法。

interface EnumInterface {
		public String getDescription();
		public int getI();
	}
import static java.lang.System.out;
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");
			}
			@Override
				public int getI() {
					return i;
				}
			};
			private static int i = 5;
 
			public static void main(String[] args) {
				for (int i = 0; i < AnyEnum.values().length; i++) {
					out.println(AnyEnum.values()[i] + "调用getDescription()方法为:" + AnyEnum.values()[i].getDescription());
					out.println(AnyEnum.values()[i] + "调用getI()方法为:" + AnyEnum.values()[i].getI());
		}
	}
}

注意:

       1.从上面代码中可以看出,枚举类型可以实现一个或者多个接口,但是它不能继承类。因为编译器会默认将枚举类型继承自java.lang.Enum 类,这一过程由编译器完成。
        2.枚举类型中的常量成员必须在其他成员之前定义,否则这个枚举类型不会产生对象。

11.1.3使用枚举类型的优势

枚举类型声明提供了一种用户友好的变量定义方法,枚举了某种数据类型所有可能出现的值。总结

枚举类型,它具有以下特点:

(1)类型安全。
(2)紧凑有效的数据定义。
(3)可以和程序其他部分完美交互。
(4)运行效率高

11.2  泛型

在JDK 1.5版本中提供了泛型概念,泛型实质上就是使程序员定义安全的类型。在没有出现泛之

前,Java也提供了对Object的引用“任意化”操作,这种任意化操作就是对Object引用进行“向转型”

及“向上转型”操作,但某些强制类型转换的错误也许不会破编译器捕捉,而在运行后出现异常,可

见强制类型转换存在安全隐患,所以提供了泛型机制。本节就来探讨泛型机制。

11.2.1 回顾“向.上转型”与“向下转型”

在介绍泛型之前,先来看一个例子。

在项目中创建Test类,在该类中使基本类型向上转型为Objet类型。

package IFather;
	public class Test {
		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) {
			Test t = new Test();
			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类型,同时为其定义了相应的

seXXX()与getXXX()方法。在类主方法中,将newBoean(true)对象作为seB()方法的参数,由于

sctB()方法的参数类型为Object,这样就实现了“向上转型”操作。同时在调用geB()方法时,将getB()

方法返回的Objeet对象以相应的类型返回,这个就是“向下转型”操作,问题通常就会出现在这里。

因为“向上转型”是安全的,而如果进行“向下转型”操作时用错了类型,或者并没有执行该操化会出

现异常,例如以下代码:

t.setB(new Float(12.3));

Integer f= (Integer) (t.getB());

System. out. println(f);

上面代码并不存在语法错误,可以被编译器接受,但在执行时会出现ClassCastException异常这样

看来,“向下转型”操作通常会出现问题,而泛型机制有效地解决了这一问题。

11.2.2 定义泛型类

Object类为最上层的父类,很多程序员为了使程序更为通用,设计程序时通常使传入的值与返回的

值都以object类型为主。当需要使用这些实例时,必须正确地将该实例转换为原来的类型,否则在

运行时将会发生ClassCastException异常。

在JDK 1.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);
	}
}

运行上述代码,结果与图11.7所示的结果一致。 上面代码中定义类时,在类名后添加了一个<T>语

句,这里便使用了泛型机制。可以将OverClass类称为泛型类,同时返回和接受的参数使用T个类

型。最后在主方法中可以使用Over<Boolean>形式返回一个Boolean型的对象,使用

OverClass<Float>形式返回一个Float型的对象,使这两个对象分别调用setOver()方法不需要进行

显式“向上转型”操作,setOver()方法直接接受相应类型的参数,而调用getOver()方法时,不需到行

“向下转型”操作,直接将getOver()方法返回的值赋子相应的类型变量即可。

从上面代码可以看出,使用泛型定义的类在声明该类对象时可以根据不同的需求指定<D真正的类

型,而在使用类中的方法传递或返回数据类型时将不再进行类型转换操作,而是使用在声明泛刑类

对象时“<>”符号中设置的数据类型。

使用泛型这种形式将不会发生ClassCastException异常,因为在编译器中就可以检查类型匹配是否

正确。

例如,在项目中定义泛型类。

OverClass<Float> over2=new OverClass<Float>() ;
over2 .setOver (12.3f) ;
//Integer i=over2.getOver(); ! /不能将Float型的值赋予Integer变量

在上面的代码中,由于over2对象在实例化时已经指定类型为Float,而最后一条语句却将该对象获取

出的Float类型值赋予Integer 类型,所以编译器会报错。而如果使用“向下转型”操作就会在运行上

述代码时发生异常。

11.2.3  泛型的常规用法

1.定义泛型类时声明多个类型

在定义泛型类时,可以声明多个类型。语法如下:

MutiOverClass<T1, T2>
MutiOverClass:泛型类名称

其中,T1和T2为可能被定义的类型。这样在实例化指定类型的对象时就可以指定多个类型。例如:

MutiOverClass<Boolean,Float>=newMutiOverClass<Boolean, Float>();

2.定义泛型类时声明数组类型

定义泛型类时也可以声明数组类型,下面的实例中定义泛型时便声明了数组类型。

在项目中创建ArrayClass类,在该类中定义泛型类声明数组类型。

package IFather;
public class ArrayClass <T> {
	private T[] array; // 定义泛型数组

	public void SetT(T[] array) { // 设置SetXXX()方法为成员数组赋值
		this.array = array;
	}

	public T[] getT() { // 获取成员数组
		return array;
	}

	public static void main(String[] args) {
		ArrayClass<String> a = new ArrayClass<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=new T[10]; //不能使用泛型来建立数组的实例
...
}

 3.集合类声明容器的元素

在第10章中学习了集合类,实际应用中,通过在集合类中应用泛型可以使集合类中的元素类型保证

唯一性, 这样在运行时就不会产生ClassCastException异常,提高了代码的安全性和可维护性。

可以使用K和V两个字符代表容器中的键值和与键值相对应的具体值。

在项目中创建MutiOverClass类,在该类中使用集合类声明容器的元素。

package IFather;
import java.util.HashMap;
import java.util.Map;
public class MutiOverClass <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) {
		// 实例化泛型类对象
		MutiOverClass<Integer, String> mu = new MutiOverClass<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));
		}
	}
}

其实定义的泛型类MutiOverClass纯属多余,因为在Java中这些集合框架已经都被泛型化了,可以

在主方法中直接使用public Map<K,V> m= new HashMap<K,V>0;语句创建实例,然后相应调用

Map接口中的put()与get()方法完成填充容器或根据键名获取集合中具体值的功能。集合中除了

HashMap这种集合类型之外,还包括ArrayList、Vector 等。表11.2 列举了几个常用的被泛型化的

集合类。

 下面的实例演示了这些集合的使用方式。

在项目中创建ListClass类,在该类中使用泛型实例化常用集合类。

package IFather;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
public class ListClass {
	public static void main(String[] args) {
		// 定义ArrayList容器,设置容器内的值类型为Integer
		ArrayList<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));
		}
	}
}

  

11.2.4泛型的高级用法

泛型的高级用法主要包括通过类型参数T的继承和通过类型通配符的继承来限制泛型类型,另外,

开发人员还可以继承泛型类或者实现泛型接口,本节将对泛型的一些高级用法进行讲解。

1.通过类型参数T的继承限制泛型类型

默认可以使用任何类型来实例化一个泛型类对象,但java中也对泛型类实例的类型作了限制,这主

河通过对类型参数T实现继承来体现,语法如下:

class类名称<T extends anyClass>

其中,anyClas指某个接口或类。

使用泛型限制后,泛型类的类型必须实现或继承了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> l3=new LimitClass<HashMap> () ;

上面代码中,将泛型作了限制,设置泛型类型必须实现List 接口。

例如,ArrayList和LinkedIist都实现了List接口,而HashMap没有实现

List接口,所以在这里不能实例化HashMap类型的泛型对象。

当没有使用extends关键字限制泛型类型时,默认Object类下的所有子类都可以实例化泛型类对

象。如图1.11所示的两个语句是等价的。

2.通过类型通配符的继承限制泛型类型

在泛型机制中,提供了类型通配符,其主要作用是在创建个设型类对象时, 的个园要的类型,或

者限制这个泛型类型必须继承某个接口或某个类(或其子类)。要声明这样个时复可以使用“?”通配

符,同时使用extends关键字来对泛型加以限制。

使用泛型类型通配符的语法如下:

泛型类名称<? 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) {
}

在上述代码中,定义方式有效地限制了传入doSomething0方法的参数类型。

如果使用A<?>这种形式实例化泛型类对象,则默认表示可以将A指定为实例化Object及以吓的子类

类型。读者可能对这种编码类型有些疑惑,下面的代码将直观地介绍A<?>泛型机制。例11.11在项

目中创建 Widclass类,演示在泛型中使用通配符形式。

package IFather;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
public class Widclass {
	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的实例获取集合中的值
	}
}

  

上面代码中,由于对象1I是没有使用A<?>这种形式初始化出来的对象,所以它可以调用set()方法

改变集合中的值,但12与13则是通过使用通配符的方式创建出来的,所以不能改变集合中的值,

所以无法调用set0方法;另外,List<?>类型的对象可以接受String类型的ArrayList集合,也可以接受

Integer类型的LinkedList集合,也许有的读者会有疑问,List<?>12=11语句与List12=11存在何种本

质区别?使用通配符声明的名称实例化的对象不能对其加入新的信息,只能获取或删除。

3.继承泛型类与实现泛型接口

定义为泛型的类和接口也可以被继承与实现。

例如,在项目中创建一个类文件,在该类中继承泛型类。

public class ExtendClass<T1>

class SubClass<T1, T2, T3> extendsExtendClass<T1> {// 泛型可以比父类多,但不可以比父类少

}

如果在SubClass类继承ExtendClass类时保留父类的泛型类型,需要在继承时指明,如果没有指明,直接使用extends ExtendsClass语句进行继承操作,则SubClass类中的T1、T2和T3都会自动变为Object,所以在-般情况下都将父类的泛型类型保留。

定义的泛型接口也可以被实现。

例如,在项目中创建一个类文件, 在该类中实现泛型接口。

interface TestInterface<T1> {
}
class SubClass2<T1, T2,T3> implements TestInterfaceT1> {
}

11.2.5 泛型总结

使用泛型需遵循以下原则。

(1)泛型的类型参数只能是类类型,不可以是简单类型,如A<int>这种泛型定义就是错误的。

(2)泛型的类型个数可以是多个。

(3)可以使用extends关键字限制泛型的类型。

(4)可以使用通配符限制泛型的类型。

11.3  小结

本章主要讲述了枚举类型以及泛型的用法。枚举类型与泛型都为JDK 1.5版本新增的内容。虽然枚举类型与泛型的语法比较简单,但是展开后的写法比较复杂,所以初学者应该仔细揣摩,并且对这两种机制做到简单掌握。此外,读者应该积极了解每个JDK版本新增的内容,而查看相应版本的API便是一种极为有效的手段。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值