Java--泛型浅谈
来源:互联网 发布:麟龙选股决策软件下载 编辑:程序博客网 时间:2024/04/29 16:06
泛型
我们看下以下五个关于泛型的定义 哪几个可行:
泛型一定要注意两边的E保持一致,如果不用两边,保持一边一致。
由于泛型是Java 1.5引入的,也就是1.5以前,都没有泛型的概念
因此,为了向下(1.5+ ---> 1.4-)兼容
List<String> list2 = new ArrayList();//这行代码是可行的
同理,为了向上(1.4- ---> 1.5+)兼容
List list3 = new ArrayList<String>(); // 这行代码是可行的
demo说明:
//非泛型方法 public void a(List list) { //1.5以前,程序员不知道有泛型这个概念 } //泛型方法 public void b(List<String> list){ //1.5+以后,泛型在程序中随处可见 } public void test1(){ b(new ArrayList());//一个不知道泛型是什么的老程序员调用一个用泛型方法 a(new ArrayList<String>());//一个学会用泛型的程序员调用一个非泛型方法 }
上述代码,在编译期间,不会报错,为的就是兼容新老版本。知道有这种写法就行。
泛型的使用
例1(List集合,泛型实际参数类型为String):
public static void main(String[] args){List<String> list = new ArrayList<String>();list.add("aa");list.add("bb");list.add("cc");//1、传统的取出泛型集合list中的元素 --> 迭代器迭代(next)出元素(String 类型)Iterator<String> it = list.iterator();while(it.hasNext()){String s = it.next();System.out.println(s);}System.out.println("-------------------------");//2、加强for(for-each)遍历list中的String元素for(String s : list){System.out.println(s);}}
效果:
注意,一定要使用包装类型Integer,而不是基本数据类型int(报错),Java有自动装箱和拆箱操作。
看下完整demo:
public static void main(String[] args){ Map<Integer, String> week = new HashMap<>(); week.put(1, "Mon"); week.put(2, "Tue"); week.put(3, "Wen"); /*传统获取Map中的键值对的方法 -->entrySet() Set类似于Map,只不过Set集合中只有键key,没有键值value 感兴趣的朋友可以看下我写的Python3学习系列 里面有介绍集合set和dict,dict就相当于Java的Map */ Set<Entry<Integer, String>> set = week.entrySet(); Iterator<Entry<Integer, String>> it = set.iterator(); while(it.hasNext()){ Entry<Integer, String> entry = it.next(); int key = entry.getKey(); //自动完成拆箱,getKey()返回一个包装类型的Integer对象 String value = entry.getValue(); System.out.println(key+" : "+value); } System.out.println("------------------"); //加强for(for-each),遍历Map中的entrySet for(Entry<Integer, String> entry : week.entrySet()){ System.out.println(entry.getKey()+" : "+entry.getValue()); } }
效果:
注意,HashMap是一个无序集合,比如,添加的是1、2、3,可能取出的是2、1、3。(当然,拿Int打个比方)
如果想要使用有序Map集合,我们需要改成LinkedHashMap:
比如,购物车里面的商品,就可以用一个顺序的LinkedHashMap集合存放,而不能用无序的HashMap。
泛型类和泛型方法
泛型变量T、K、E未定义就使用了,因此上述泛型方法定义错误
我们看下正确的定义方式:
对比类,也一样,如果定义类的一开始就定义了这些泛型变量T,K,E,则类中的非静态方法和成员变量可以直接使用泛型变量:
因此,我们需要给上述泛型类中的静态泛型方法B也加上泛型变量的定义,定义后才能使用(切记规则):
通过反射reflect获得泛型类的相关参数化类型
由于性能驱使,Java在编译泛型类的时候,对应.class文件中,会擦除掉有关类的泛型参数类型<Integer,String>的字眼,比如:
我们看到,类DemoTest是一个泛型类,参数化类型一个是Integer,另一个是String,但是我们getClass的时候,和普通的Class一样
我们看到,类DemoTestA继承自泛型类DemoTest,打印子类的父类的时候,显示了DemoTest的类型为generic,表示父类是一个泛型类,但是,泛型的参数化类型<Integer,String>却没有体现出来,因此,如果,在编译的时候,重载方法的参数为泛型类的对象的时候,你就要小心了,因为编译的时候会擦出掉参数化类型,下面的代码是编译不通过的:
但是,你换成其他类型,就可以通过了:
那我们怎么拿到泛型类的实际泛型参数化类型呢?
通过Java的reflect 反射技术
下面的讲解主要以demo为主,涵盖注释
泛型类:Week<T,K> ---->父类,T,K并没有被实际赋予其参数类型
方法 :A 无泛型实际参数化类型,简单点就是无参数类型,但是返回值是一个泛型参数化类型
方法 :B 正好和A颠倒,本篇主要讲解A,方法B的反射同理A
Week.java:
package com.appleyk.generic;import java.util.Map;public class Week<T,K>{public Map<T, K> A() {System.out.println("父类:get week");return null;}public void B(Map<T, K> week) {System.out.println("父类:set week");}}
子类 :W,继承自Week<T,K>,由于,子类要具体化父类,因此,这里我们要指定父类的泛型实际参数化类型为
Week<Integer,String>,如果你继承泛型类,泛型类的参数类型都不指定的话,鬼晓得你要干嘛,意义何在?
Demo3.java:
package com.appleyk.generic;import java.lang.reflect.Method;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.HashMap;import java.util.List;import java.util.Map;class W extends Week<Integer,String>{public Map<Integer, String> A() {System.out.println("子类:get week");return null;}public void B(Map<Integer, String> week) {System.out.println("子类:set week");}} public class Demo3 {public static void main(String[] args) throws Exception{ //getGenericSuperclass() 获得带有泛型的父类 //ParameterizedType 实际泛型参数化类型 ParameterizedType type =(ParameterizedType)W.class.getGenericSuperclass(); System.out.println(type); System.out.println("---------------"); //getActualTypeArguments() 获取参数化类型数组,泛型可能有多个 Type[] t = type.getActualTypeArguments(); System.out.println("泛型类Week的实际泛型参数化数组的元素:"); for(Type paramType : t){ //打印父类泛型的实际参数类型 System.out.println("#"+paramType); } System.out.println("获得子类W的相关泛型信息---------------"); W w = new W(); w.A(); w.B(new HashMap<Integer,String>()); System.out.println("子类W的类---------------"); System.out.println(w.getClass()); System.out.println("父类Week的类---------------"); System.out.println(w.getClass().getSuperclass()); System.out.println("反射方法A的参数泛型信息---------------"); Method methodA = W.class.getMethod("A", null); Type[] mt = methodA.getGenericParameterTypes(); System.out.println("A的泛型参数类型数组长度="+mt.length); //方法A的泛型参数类型数组长度为0 for(Type parT : mt){ System.out.println(parT); //显然方法A没有使用泛型参数,这个for不会执行 } System.out.println("反射方法A的返回参数的泛型信息---------------"); //getGenericReturnType 获得泛型丰富的返回值类型(注意不是一个 Type[]) Type gReturnType = methodA.getGenericReturnType(); if(gReturnType instanceof ParameterizedType)//如果返回值类型是一个实际泛型参数类型的话(有意义) { //转化一下类型,将方法的泛型返回值类型转化为实际泛型参数化的类型(-->比如Week<Integer,String>) Type[] gTypes = ((ParameterizedType) gReturnType).getActualTypeArguments(); //for遍历 for(Type gType : gTypes){ System.out.println("返回值的实际泛型参数类型:"+gType); } } }}
注释很详细了,这里我就不一一讲解了,不要看着demo一麻团,其实没使用多少类,多少方法,反射泛型信息的,也就那么几个常用的对象和方法:
ParameterizedType实际泛型参数化类型
getGenericSuperclass()获得带有泛型的父类
getActualTypeArguments() 获取参数化类型数组(Type[]),泛型可能有多个
getGenericParameterTypes()获得方法的泛型参数化类型(Type[])
getGenericReturnType() 获得方法的泛型返回类型(注意不是一个Type数组,需要另外类型转换)
我们看下,执行效果:
最后,我们写一个小面试题,结束我们今天的泛型讲解
题目:利用泛型编写一个方法,实现指定数组的元素反转。
注意,是指定数组,并没有说是String类型的还是Int类型的数组,另外,注意,使用泛型的时候,一定要用包装类型,比如,int类型用Integer,而不用基本数据类型int
答案:
package com.appleyk.generic;public class demo4 { //第一个元素和倒数第一个元素互换,第二个元素和倒数第二个元素互换,依次类推 public static<T> T[] reverse(T[] arr){ int start = 0; //第一个元素 int end = arr.length-1 ; //第二个元素 T temp ; //临时变量 while(true){ if (start>=end) {break;//如果start 和 end 碰头了,意味着两边元素的交换已经到尽头了} temp = arr[start]; arr[start] = arr[end]; arr[end] = temp;start++;end --; } return arr; } public static void main(String[] args){ String[] names ={"a","b","c","d"}; names = reverse(names); for(String s: names){ System.out.println(s); } System.out.println("---------泛型的使用--------"); Integer[] ages = {1,2,3,4}; ages = reverse(ages); for(Integer s: ages){ System.out.println(s); } }}
验证下:
本篇虽然有点长,但是从头到尾耐心的跟我所讲的走一遍,一定会收获不少,泛型在Java中是很重要的一个角色,掌握了本篇所讲,基本上Java泛型的操作就会了百分之八九十吧。
- JAVA泛型浅谈
- Java--泛型浅谈
- JAVA泛型浅谈
- 浅谈Java泛型编程
- 浅谈java的泛型
- 浅谈Java泛型编程
- 浅谈Java中的泛型
- JAVA 泛型浅谈(1)
- JAVA第十七弹(浅谈泛型)
- Java泛型浅谈(2)
- 浅谈Java泛型中的extends和super关键字
- 黑马程序员——浅谈java中的泛型
- 浅谈Java泛型中的extends和super关键字
- 浅谈Java泛型中的extends和super关键字
- 浅谈Java和C#泛型及C++模板
- 浅谈Java泛型中的extends和super关键字
- [Java] 浅谈泛型的意义与不足
- 浅谈Java泛型中的extends和super关键字
- 顺时针按层打印矩阵
- SQL中判断字符串中包含字符的方法
- jQuery文档处理 删除
- numpy入门3
- 在网站发布之后不需要修改默认文档
- Java--泛型浅谈
- 网易云课堂-数据结构-第一讲-基本概念
- 微信 接口配置信息修改
- 3分钟实现iOS语言本地化/国际化(图文详解)
- numpy入门4
- MathType6.9b中文版
- 图片上传
- SpringMVC工作流程
- 外卖小程序源代码免费下载-微信小程序教程30