Java泛型
来源:互联网 发布:mysql datetime 减法 编辑:程序博客网 时间:2024/05/20 18:01
1、为什么需要泛型
package com.xiya.generic;import java.util.ArrayList;import java.util.List;public class GenericTest { public static void main(String[] args) { List list = new ArrayList(); list.add("abc"); list.add(111);//可以通过编译 for (Object o : list) { String value = (String) o;//抛出ClassCastException异常(java.lang.Integer cannot be cast to java.lang.String) System.out.println(value); } }}
如上,我们向List
类型集合中加入了一个String
类型的值和一个Integer
类型的值(这样是合法的,因为此时list默认的存储类型为Object
类型)。
上面的代码会在运行时抛出ClassCastException异常,因为它尝试将一个Integer转换为String java.lang.Integer cannot be cast to java.lang.String
。接着,来看一下从java5开始,Collection的用法:
package com.xiya.generic;import java.util.ArrayList;import java.util.List;public class GenericTest { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("abc"); list.add("def"); //list.add(111);//不可以通过编译 for (String s : list) { System.out.println(s);//无需任何强制类型转换 } }}
注意到,List
的创建增加了类型参数String,因此只能向List
中添加String类型对象,添加其他对象会抛出编译异常;
同样可以注意到,foreach循环不需要再添加任何强制类型转换,也就移除了运行时的ClassCastException异常。
泛型的两个好处:
- 编译时类型检查。
- 避免强制类型转换。
2、泛型类与泛型接口
考虑以下场景:您希望开发一个用于在应用中传递对象的容器。但对象类型并不总是相同。因此,需要开发一个能够存储各种类型对象的容器。
鉴于这种情况,要实现此目标,显然最好的办法是开发一个能够存储和检索 Object 类型本身的容器,然后在将该对象用于各种类型时进行类型转换。
package com.xiya.generic;class ObjectContainer { private Object obj; /** * @return the obj */ public Object getObj() { return obj; } /** * @param obj the obj to set */ public void setObj(Object obj) { this.obj = obj; }}public class GenericTest { public static void main(String[] args) { ObjectContainer objectContainer = new ObjectContainer(); objectContainer.setObj("Hello World"); System.out.println(objectContainer.getObj()); }}
原始类的定义,容易引发ClassCastException。
现在来看一下泛型类来重新定义ObjectContainer
使用<T>
指定泛型参数,如下:
package com.xiya.generic;class ObjectContainer<T> { private T obj; /** * @return the obj */ public T getObj() { return obj; } /** * @param obj the obj to set */ public void setObj(T obj) { this.obj = obj; }}public class GenericTest { public static void main(String[] args) { ObjectContainer<String> objectContainer = new ObjectContainer<>(); objectContainer.setObj("Hello World"); //objectContainer.setObj(111);//无法通过编译 String str = objectContainer.getObj(); System.out.println(str); }}
接口的泛型应用和类的泛型应用很类似,如下:
public interface List <E> { void add(E x); Iterator<E> iterator();}public interface Iterator<E> { E next(); boolean hasNext();}
类似的,可以将此应用到自定义的接口与类当中。
3、泛型的命名规范
为了更好地去理解泛型,我们也需要去理解java泛型的命名规范。为了与java关键字区别开来,java泛型参数只是使用一个大写字母来定义。各种常用泛型参数的意义如下:
E — Element,常用在java Collection里,如:List< E >,Iterator< E >,Set< E >
K,V — Key,Value,代表Map的键值对
N — Number,数字
T — Type,类型,如String,Integer等等
S,U,V etc. - 2nd, 3rd, 4th 类型,和T的用法一样
4、泛型方法
定义泛型方法语法格式如下:
调用泛型方法语法格式如下:
public class GenericTest { public static <T> T getObject(Class<T> c) throws IllegalAccessException, InstantiationException { return c.newInstance(); } public static void main(String[] args) { try { Person person = getObject(Person.class); person.setName("lgh"); person.setAge(25); System.out.println(person); } catch (IllegalAccessException | InstantiationException e) { e.printStackTrace(); } }}
<T>
和 T
的区别?
其实说白了就是先声明后使用,和变量的使用没有本质区别。
5、泛型参数的界限
有时候,你会希望泛型类型只能是某一部分类型,比如操作数据的时候,你会希望是Number或其子类类型。这个想法其实就是给泛型参数添加一个界限。其定义形式为: <T extends BoundingType>
此定义表示T应该是BoundingType的子类型(subtype)。T和BoundingType可以是类,也可以是接口。另外注意的是,此处的extends
表示的子类型,不等同于继承。
public class GenericTest { public static <T extends Number> void test(List<T> list) { System.out.println(list); } public static void main(String[] args) { List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5); List<Number> list2 = Arrays.asList(6, 7, 8, 9, 10); List<String> list3 = Arrays.asList("111", "222"); test(list1); test(list2); //test(list3);//报错 }}
此外,泛型只在编译阶段有效。运行时会进行类型擦除。
即List<String> list = new ArrayList<>();
编译后变成 List list = new ArrayList<>();
。
package com.xiya.generic;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;public class GenericTest { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("111"); list.add("222");// list.add(333); try { Method method = list.getClass().getMethod("add", Object.class); method.invoke(list, 333); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } System.out.println(list); }}
参考:
http://peiquan.blog.51cto.com/7518552/1302898
https://www.ziwenxie.site/2017/03/01/java-generic/
http://www.oracle.com/technetwork/cn/articles/java/juneau-generics-2255374-zhs.html
http://www.infoq.com/cn/articles/cf-java-generics
https://www.ibm.com/developerworks/cn/java/j-lo-gj/index.html
http://oldratlee.com/278/tech/java/study-material-of-java-generic.html
http://blog.csdn.net/LonelyRoamer/article/category/1212099
- 【java 2】java泛型
- Java 泛型 Java generic
- Java Tutorials_Generics(java泛型)
- Java基础 Java 泛型
- java 泛型
- java泛型
- Java泛型
- Java泛型
- java泛型
- java泛型
- java泛型
- Java 泛型
- Java泛型
- Java 泛型
- JAVA 泛型
- java 泛型
- java泛型
- Java泛型
- C语言 printf输出字符串数据
- 位运算
- var 和varStatus的区别
- vim命令详细说明
- Vue.js 踩坑
- Java泛型
- 理解原型和原型链
- J
- dubbo 粘滞连接 源代码分析
- jdk问题
- 强大的动态SQL
- CodeForces
- FragmentManager冲突问题
- 菜鸟与 cef 的邂逅之旅(二):Soui 中接入 Cef3 的实现