Java泛型浅析
来源:互联网 发布:英国gpa标准加权算法 编辑:程序博客网 时间:2024/06/14 20:01
一句话理解
泛型是一种检查机制,使得在编译时检测出错误,而不是运行时。
优点
加强安全性。
知识要点(详细)
以下例子来源:Java语言程序设计(进阶篇)
定义的泛型类会在后续的例子中持续使用
1.定义泛型类&接口
import java.util.ArrayList;//定义泛型类public class GenericStack <E>{ArrayList<E> list = new ArrayList<>();public int getSize(){return list.size();}public E peek(){return list.get(getSize()-1);}public void push(E o){list.add(o);}public E pop(){E o = list.get(getSize()-1);list.remove(getSize()-1);return o;}public boolean isEmpty(){return list.isEmpty();}@Overridepublic String toString() {return "stack:" + list.toString() ;}}
//应用泛型类添加元素,再输出public class GenericDemo {public static void main(String[] args) {// TODO Auto-generated method stubGenericStack<String> stack1 = new GenericStack<>();stack1.push("London");stack1.push("Paris");stack1.push("Berlin");GenericStack<Integer> stack2 = new GenericStack<>();stack2.push(1);stack2.push(2);stack2.push(3);System.out.println(stack1.pop());System.out.println(stack1.pop());System.out.println(stack1.pop());System.out.println();System.out.println(stack2.pop());System.out.println(stack2.pop());System.out.println(stack2.pop());System.out.println();}}
注意这是一个栈类
2.定义泛型方法
package test;public class GenNewDemo {//定义泛型方法public static <E> void print (E[] list){for(int i = 0;i<list.length;i++){System.out.print(list[i]+ " ");System.out.println();}}public static void main(String[] args) {// TODO Auto-generated method stubInteger[] integeres = {1,2,3,4,5};String[] strings = {"London","Paris","New York"};print(integeres);System.out.println();//以下三种输出方式都是正确的print(strings);System.out.println();GenNewDemo.print(strings);System.out.println();GenNewDemo.<String>print(strings);}}
注意:
是可以为静态方法定义泛型类型。
3.受限泛型&非受限泛型
受限泛型:泛型指定为另外一种类型的子类型。eg:<E entends GenericOperation> (GenericOperation是一个自定义类)
非受限泛型:假设有一个<E>,它就等同于<E entends Object>
4.原始类型及向后兼容
原始类型:没有指定具体类型的泛型类和泛型接口被称为原始类型。
eg:
GenericStack stack = new GenericStack();//大体等价于GenericStack<Object> stack = new GenericStack<Object>();像这样不带类型参数的泛型类就是原始类型。
注意:原始类型是不安全的。
5.通配泛型(重点)
通配泛型分类:
(1)非受限通配 ?
和? exends Object是一样的
(2)受限通配 <? extends T >
表示T或T的一个子类型
(3)下限通配 <? super T >
表示T或T的一个父类型
?应用举例:
package test;public class WildCardNeedDemo {//找到stack中的最大数字public static double max(GenericStack<? extends Number> stack){double max = stack.pop().doubleValue();while(!stack.isEmpty()){double value = stack.pop().doubleValue();if(value>max){max = value;}}return max;}public static void print (GenericStack<Object> stack){while(!stack.isEmpty()){System.out.print(stack.pop() + " ");}}public static void main(String[] args) {// TODO Auto-generated method stubGenericStack<Integer> intStack = new GenericStack<>();intStack.push(1);intStack.push(2);intStack.push(-2);print(intStack);}}
错误分析:虽然Integer是Object的子类型,但是GenericStack<Integer>不是GenericStack<Object>的子类型
修改代码为
运行结果
package test;public class WildCardNeedDemo {//找到stack中的最大数字public static double max(GenericStack<Number> stack){double max = stack.pop().doubleValue();while(!stack.isEmpty()){double value = stack.pop().doubleValue();if(value>max){max = value;}}return max;}public static void main(String[] args) {// TODO Auto-generated method stubGenericStack<Integer> intStack = new GenericStack<>();intStack.push(1);intStack.push(2);intStack.push(-2);System.out.println("The max number is : " + max(intStack));}}
错误分析:虽然Integer是Number的子类型,但是GenericStack<Integer>不是GenericStack<Number>的子类型,所以要用通配泛型去解决问题。
修改代码为
运行结果
<? super T >应用举例:
package test;public class SuperWildCardDemo {public static void main(String[] args) {// TODO Auto-generated method stubGenericStack<String> stack1 = new GenericStack<>();GenericStack<Object> stack2 = new GenericStack<>();stack2.push("Java");stack2.push(2);stack1.push("Sun");add(stack1,stack2);print(stack2);}private static <T> void add(GenericStack<T> stack1, GenericStack<? super T> stack2) {while(!stack1.isEmpty()){stack2.push(stack1.pop());}}public static void print (GenericStack<?> stack){while(!stack.isEmpty()){System.out.println(stack.pop() + " ");}}}
运行结果
6.消除泛型
泛型在编译时,一旦编译器确认泛型类型是安全使用的,就会将它转换为原始类型。
例如:
确认安全后,编译器转换为Object类型代替泛型类型
7.泛型的限制
(1)不能使用new E();
eg:E object = new E();
(2)不能使用new E[ ]
eg:E[ ] elements = new E[ ];
(3)在静态上下文中不允许类的参数是泛型类型
由于泛型类的所有实例都有相同的运行时类,所以泛型类的静态变量和方法是被它的所有实例共享,因此,在静态方法、数据域或者初始化语句中,为类引用泛型类型参数是非法的,非法代码举例如下:
public class Test<E>{public static void m(E o1){//Illegal}public static E o1;//Illegalstatic {E o2;//Illegal}}
(4)异常类不能是泛型的
必须添加try/catch
泛型类不能扩展java.lang.Throwable
下面类的声明是非法的:
public class MyException<T> extends Exception{}如果允许,要为MyException<T> 添加一个catch语句
try{}catch( MyException<T> ex){}
JVM必须检查这个try句子抛出的异常,来确定是否与catch子句中指定的类型匹配,但是这是不可能的,因为运行时类型信息是不可得的。
总结
1.泛型具有参数化类型的能力,可以定义使用泛型类型的类或方法,编译器会用具体的类型来替换泛型类型。
2.泛型主要优势是能够在编译时检测错误,而不是运行时。
3.泛型类或方法允许指定这个类或方法可以带有的对象类型,如果试图使用带有不兼容对象的类或方法,编译器会检测出这个错误。
4.定义在类、接口或者静态方法中的泛型称为形式泛型类型,随后可以用一个实际具体类型来替换它。替换泛型类型的过程称为泛型实例化。
5.使用原始类型是为了向后兼容java较早的版本,因为JDK1.5之前是没有泛型的。
6.使用类型消除的方法来实现泛型。编译器使用泛型类型信息来编译代码,但是随后消除它。因此,泛型信息在运行时是不可用的。这个方法能够使泛型代码向后兼容使用原始类型的遗留代码。
7.不能使用泛型类型参数创建实例。
8.不能使用泛型类型参数创建数组。
9.不能在静态环境中使用类的泛型参数。
10.在异常类中不能使用泛型类型参数。
如有错误,欢迎指正。
- java 泛型浅析
- java 泛型浅析
- Java泛型浅析
- 浅析Java泛型的优点
- Java泛型浅析(一)
- Java范型浅析
- Java范型浅析
- Java范型浅析
- Java范型浅析
- 黑马程序员----关于JAVA中的泛型的浅析
- java 浅析
- 泛型浅析
- 泛型浅析
- 泛型编程浅析
- 浅析C#中的泛型
- 泛型浅析与应用
- 浅析c#中的泛型
- 浅析 Java 中的覆盖
- Linux内核漏洞利用入门
- 递归和非递归实现归并排序
- java生成图片验证码
- SystemServer的产生和启动
- 用verilog语言设计一个2s的呼吸灯
- Java泛型浅析
- getevent/sendevent 使用说明
- java时间转换为时间戳
- PHP-利用二叉堆实现TopK-算法
- 多线段几何图形—— 简单几何图形(布尔运算)
- 安卓7.0已知新特性汇总
- nat
- java中判断两个字符串是否相等的问题
- 推荐一个Monokai风格的EditPlus配色方案