在面向对象编程语言中,多态算是一种泛化机制。例如,你可以将方法的参数类型设置为基类,那么该方法就可以接受从这个基类中导出的任何类作为参数,这样的方法将会更具有通用性。此外,如果将方法参数声明为接口,将会更加灵活。
在Java增加泛型类型之前,通用程序的设计就是利用继承实现的,例如,ArrayList类只维护一个Object引用的数组,Object为所有类基类。
- public class BeforeGeneric {
- static class ArrayList{//泛型之前的通用程序设计
- private Object[] elements=new Object[0];
- public Object get(int i){
- return elements[i];
- }
- public void add(Object o){
- //这里的实现,只是为了演示,不具有任何参考价值
- int length=elements.length;
- Object[] newElments=new Object[length+1];
- for(int i=0;i)
4、泛型在静态方法和静态类中的问题
泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数
- public class Test2 {
- public static T one; //编译错误
- public static T show(T one){ //编译错误
- return null;
- }
- }
因为泛型类中的泛型参数的实例化是在定义泛型类型对象(例如ArrayList)的时候指定的,而静态变量和静态方法不需要使用对象来调用。对象都没有创建,如何确定这个泛型参数是何种类型,所以当然是错误的。public class Test2 { public static T one; //编译错误 public static T show(T one){ //编译错误 return null; } }
但是要注意区分下面的一种情况:
- public class Test2 {
- public static T show(T one){//这是正确的
- return null;
- }
- }
public class Test2 { public static T show(T one){//这是正确的 return null; } }
因为这是一个泛型方法,在泛型方法中使用的T是自己在方法中定义的T,而不是泛型类中的T。
泛型相关面试题1. Java中的泛型是什么 ? 使用泛型的好处是什么? 泛型是一种参数化类型的机制。它可以使得代码适用于各种类型,从而编写更加通用的代码,例如集合框架。
泛型是一种编译时类型确认机制。它提供了编译期的类型安全,确保在泛型类型(通常为泛型集合)上只能使用正确类型的对象,避免了在运行时出现ClassCastException。
2、Java的泛型是如何工作的 ? 什么是类型擦除 ? 泛型的正常工作是依赖编译器在编译源码的时候,先进行类型检查,然后进行类型擦除并且在类型参数出现的地方插入强制转换的相关指令实现的。
编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。例如List在运行时仅用一个List类型来表示。为什么要进行擦除呢?这是为了避免类型膨胀。
3. 什么是泛型中的限定通配符和非限定通配符 ? 限定通配符对类型进行了限制。有两种限定通配符,一种是表示了非限定通配符,因为可以用任意类型来替代。
4. List和List之间的区别是什么? 这道题跟上一道题看起来很像,实质上却完全不同。List 是一个未知类型的List,而List其实是任意类型的List。你可以把List, List赋值给List,却不能把List赋值给List。
- List listOfAnyType;
- List listOfObject = new ArrayList();
- List listOfString = new ArrayList();
- List listOfInteger = new ArrayList();
- listOfAnyType = listOfString; //legal
- listOfAnyType = listOfInteger; //legal
- listOfObjectType = (List) listOfString; //compiler error - in-convertible types
13、List和原始类型List之间的区别. 该题类似于“原始类型和带参数类型之间有什么区别”。带参数类型是类型安全的,而且其类型安全是由编译器保证的,但原始类型List却不是类型安全的。你不能把String之外的任何其它类型的Object存入String类型的List中,而你可以把任何类型的对象存入原始List中。使用泛型的带参数类型你不需要进行类型转换,但是对于原始类型,你则需要进行显式的类型转换。List listOfAnyType; List listOfObject = new ArrayList(); List listOfString = new ArrayList(); List listOfInteger = new ArrayList(); listOfAnyType = listOfString; //legal listOfAnyType = listOfInteger; //legal listOfObjectType = (List) listOfString; //compiler error - in-convertible types
- List listOfRawTypes = new ArrayList();
- listOfRawTypes.add(”abc”);
- listOfRawTypes.add(123); //编译器允许这样 - 运行时却会出现异常
- String item = (String) listOfRawTypes.get(0); //需要显式的类型转换
- item = (String) listOfRawTypes.get(1); //抛ClassCastException,因为Integer不能被转换为String
- List listOfString = new ArrayList();
- listOfString.add(”abcd”);
- listOfString.add(1234); //编译错误,比在运行时抛异常要好
- item = listOfString.get(0); //不需要显式的类型转换 - 编译器自动转换
通配符 通配符上界List listOfRawTypes = new ArrayList(); listOfRawTypes.add("abc"); listOfRawTypes.add(123); //编译器允许这样 - 运行时却会出现异常 String item = (String) listOfRawTypes.get(0); //需要显式的类型转换 item = (String) listOfRawTypes.get(1); //抛ClassCastException,因为Integer不能被转换为String List listOfString = new ArrayList(); listOfString.add("abcd"); listOfString.add(1234); //编译错误,比在运行时抛异常要好 item = listOfString.get(0); //不需要显式的类型转换 - 编译器自动转换
常规使用- public class Test {
- public static void printIntValue(List list) {
- for (Object elem: list)
- System.out.print(elem + ”“);
- System.out.println();
- }
这样就可以兼容更多的输出,而不单纯是List,如下:public static void printList(List list) { for (Object elem: list) System.out.print(elem + ""); System.out.println(); }
- List li = Arrays.asList(1, 2, 3);
- List ls = Arrays.asList(”one”, “two”, “three”);
- printList(li);
- printList(ls);
List li = Arrays.asList(1, 2, 3); List ls = Arrays.asList("one", "two", "three"); printList(li); printList(ls);
参考:
《Java核心技术 卷一》
http://blog.csdn.net/lonelyroamer/article/details/7868820
http://www.oschina.net/translate/10-interview-questions-on-java-generics
http://www.linuxidc.com/Linux/2013-10/90928.htm