您的位置:首页 > 编程语言 > Java开发

Java中的泛型

2016-07-29 00:00 561 查看
 1、Java.util的集合类中的元素必须是对象化的,他们不能是基本类型。如不能声明Set<char>或List<int>。但对List<Integer>,可以往里面加int型数据,它会用Java的autoboxing机制自动转换成Integer对象。

2、参数化类中的类型参数可以是数组类型,如Map<String[],int[]),注意int[]型是一个对象,而不是原始类型。

3、如果不想用泛型功能,可以通过带-source1.4标记来编译;也可以在声明的域或方法前用@SuppressWarings("unchecked")标注来忽略。

4、一个List<Integer>是一个Collection<Integer>,但不是一个List<Object>,否则List<Integer>可以转换成List<Object>,那么转换后什么类型的数据都可以加进去,没有达到编译期类型安全的目的。即:类可以上转型,类型参数不能上转型。

5、Java中引入泛型的本质:为了提供编译期的类型安全检查,以免类型不安全的bug出现在运行期。(注意这与C++及C#中泛型的目的不同)

6、一个List<T>上转型成List是合法的,这是为了向后兼容,但不推荐这样做。因为上转型后可以添加任意类型的元素,会在后面引入bug。
注意:上转型是编译期行为,在运行时运行的还是未转型前的那个类型

7、不能创建参数化类型的数组。如List<String>[] wordlists=new ArrayList<String>[10];编译通不过。编译器为什么要这样做呢?如下:

List<String>[] wordlists=new ArrayList<String>[10]; //若可以创建数组,继续往下执行
ArrayList<Integer> ali=new ArrayList<Integer>();
ali.add(123);   //autoboxing
Object[] objs=wordlists; //是上转型,编译通过。编译时objs各元素是Object类型,
//运行时objs各元素是ArrayList<String>类型
objs[0]=ali; //是上转型,编译通过。编译时objs[0]是Object类型,
//运行时是ArrayList<Integer>类型,与上面的ArrayList<String>矛盾,但运行
//时仍无错,因为对String还是Integer的检查在编译期完成,运行期并不知道
String s=wordlists[0].get(0); //运行时wordlists[0](==objs[0])是
//ArrayList<Integer>,把Integer赋给String,故出错


可见不能保证编译期类型安全,所以编译器干脆在第一行就拒绝编译。

8、如果类型是泛型,但您希望能添加各种类型的元素,可以把元素类型声明为Object类型,如Set<Object>,这样就可以往里面添加不同类型 的元素。如果这还不行,比如,您并不关心值的类型,您希望您的list可以是List<Integer>,也可以是List<String>,可以用List<?>,但 是不能在构造器中使用"?"通配符。

9、List<?>既不是List<Object>也不是未经处理的List。?表示未知类型,它是只读的,调用get()返回Object类型,调用add()编译出错。

10、上界通配符:如List<? extends Number>,?为未知类型,但必须是Number的子类,Number被认为是其自身的子类。注意由于类型仍然未知不允许添加未知类型的元素,故它仍然是只读的。

11、下界通配符:如Set<? super Integer>,?为未知类型,但必须是Integer的父类,Integer被认为是自己的父类。

12、切记,类型变量仅在编译时存在,所以不能使用instanceof和new这类运行时操作符来操作类型变量。

13、一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而是不能被静态变量和方法调用。原因很简单,参数化的泛型 运行时是一些实例,类的类型参数不存在了。静态成员是被类的实例和参数化的类所共享的,所以静态成员不应该和类型参数关联。

14、类的类型变量T可以用于声明变量的类型,声明构造函数和方法的入口类型和返回类型,未知类型?,? extends T,? super T可以用于声明 变量的类型,声明方法的入口类型和返回类型,但不能用于声明构造函数。

15、方法、构造函数可以声明自己的类型变量,这时就叫做范型方法。调用范型方法时,根据传入的实际值的类型来确定类型变量,一般无需显式指明参数类型。但在非常罕见的情况下,可能必须指明。如java.util.Collections.emptySet(),返回一个空集,他虽不带入口参数但需要指明返回类型,可以这样写Set<String> empty=Collections.emptySet(),也可以这样写Set<String> empty=Collections.<String>emptySet(),但是在方法调用表达式中则必须显示的说明emptySet()的返回值类型,如:
printWords(Collections.<String>emptySet())

16、类型参数不能同没有限制的方法名结合使用:他们必须跟随在一个.后,或者在new后,或者在this前,或者构造函数的super前。

17、若创建一个方法使用varargs和类型变量,记住调用varargs隐含创建一个数组。但是在方法里面我们不能创建参数化类型的数组,这点要注意。

18、参数化异常是不允许的,因为异常是在运行时抛出和捕获的,没办法让编译器完成类型检查。因此不允许创建任何Throwable类型的子类。但是可以使用类型变量在throw块里的方法签名中。如:

public interface Command<X extends Exception>{
public void  doit(String arg) throws X;
}


19、Integer的类标签:public final class Integer extends Number implements Comparable<Integer>
java.math.BigInteger的类标签:public class BigInteger extends Number implements Comparable<BigInteger>

20、java.util.Collections.max()为找集合中的最大元素,其方法标签为:
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
方法中包含一个类型变量T,返回值类型为T,方法的参数是一个集合,集合中的元素类型上限为T,上限为T的任何类型都可作为返回类型
T必须实现Comparable接口,且必须与T或T的父类比较。可见,T自己实现Comparable接口,或者T的父类实现Comparable接口都可以满足这个要求。

21、考察Collections的addAll()方法:
public static <T> boolean addAll(Collection<? super T> c,T... a)
这是一个varargs方法,接受任意数量的参数,并且传递给他们一个T[],命名为a。他将a中的所有元素都赋给集合c。集合的元素类型下界 为T,这样可以确保数组的元素都是类型的实例,是类型安全的,所以往集合中添加元素是合法的。回想上界通配符,它是只读的,不能添 加不可知类型的元素,可见下界通配符虽是不可知类型的,但是可写,因为可以保证类型安全。

22、下界通配符不能实现只写的集合,如List<? super Integer>,它的get()方法一样返回Object。

23、java.lang.Enum类的标签:public class Enum<E extends Enum<E>> implements Comparable<E>,Serializable
Enum是可比较的,其元素本身必须是Enum类型,而且他们的子类可以同他们的父类比较。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: