博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java泛型二:泛型类 泛型接口 泛型方法详解
阅读量:7062 次
发布时间:2019-06-28

本文共 6259 字,大约阅读时间需要 20 分钟。

hot3.png

泛型类

单参数泛型类:

public class Rectangle
{ private T width; private T height; public Rectangle(T width, T height) { this.width = width; this.height = height; } public T getWidth() { return width; } public void setWidth(T width) { this.width = width; } public T getHeight() { return height; } public void setHeight(T height) { this.height = height; } public void showDetails(){ System.out.println("the rectangle, width is " + this.width + " height is " + this.height); }}

通过public class Rectangle<T> {}定义泛型类,在实例化该类时,必须指明泛型T的具体类型,

例如:Rectangle<String> rectangle = new Rectangle<String>();,指明泛型T的类型为String。

泛型通配符:

我们知道Ingeter是Number的一个子类,同时在特性章节中我们也验证过Generic<Ingeter>与Generic<Number>实际上是相同的一种基本类型。那么问题来了,在使用Generic<Number>作为形参的方法中,能否使用Generic<Ingeter>的实例传入呢?在逻辑上类似于Generic<Number>和Generic<Ingeter>是否可以看成具有父子关系的泛型类型呢?

为了弄清楚这个问题,我们使用Generic<T>这个泛型类继续看下面的例子:

public void showKeyValue1(Generic
obj){ Log.d("泛型测试","key value is " + obj.getKey());}
Generic
gInteger = new Generic
(123);Generic
gNumber = new Generic
(456);showKeyValue(gNumber);// showKeyValue这个方法编译器会为我们报错:Generic
// cannot be applied to Generic
// showKeyValue(gInteger);

通过提示信息我们可以看到Generic<Integer>不能被看作为Generic<Number>的子类。由此可以看出:同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。

回到上面的例子,如何解决上面的问题?总不能为了定义一个新的方法来处理Generic<Integer>类型的类,这显然与java中的多台理念相违背。因此我们需要一个在逻辑上可以表示同时是Generic<Integer>和Generic<Number>父类的引用类型。由此类型通配符应运而生。

我们可以将上面的方法改一下:

public void showKeyValue1(Generic
obj){ Log.d("泛型测试","key value is " + obj.getKey());}

类型通配符一般是使用?代替具体的类型实参,注意了,此处’?’是类型实参,而不是类型形参 。重要说三遍!此处’?’是类型实参,而不是类型形参 ! 此处’?’是类型实参,而不是类型形参 !再直白点的意思就是,此处的?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型。

可以解决当具体类型不确定的时候,这个通配符就是 ?  ;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用 ? 通配符来表未知类型。

多参数泛型类:

/** * Created with IntelliJ IDEA. * Description: * User: zhubo * Date: 2017-11-29 * Time: 17:24 */public class Container
{ private K key; private V value; public Container(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public void setKey(K key) { this.key = key; } public V getValue() { return value; } public void setValue(V value) { this.value = value; }}

通过public class Container<K, V> {}定义泛型类,在实例化该类时,必须指明泛型K、V的具体类型,

例如:Container<String, String> c1 = new Container<String, String>("name", "Messi");,指明泛型K的类型为String,泛型V的类型为String。

泛型接口

public interface Calculator
{ public T and(T a , T b);}
public class CalculatorInteger implements Calculator
{ @Override public Integer and(Integer a, Integer b) { return a + b; }}

通过public interface Calculator<T> {}定义泛型接口,在实现该接口时,必须指明泛型T的具体类型,

例如:public class CalculatorInteger implements Calculator<Integer>{},指明泛型T的类型为Integer,实例化该类时无需制定泛型类型。

泛型方法

public class Generic {    public 
T getObject(Class
c){ T t = null; try { t = c.newInstance(); } catch (Exception e){ e.printStackTrace(); } return t; } public static void main(String[] args) { try{ Generic generic = new Generic(); Object obj = generic.getObject(Class.forName("com.qf58.supplier.entity.others.Generic")); }catch (Exception e) { e.printStackTrace(); } }}

泛型方法说明: 

这里写图片描述

在调用泛型方法的时候,在不指定泛型的情况下,泛型变量的类型为该方法中的几种类型的同一个父类的最小级,直到Object。在指定泛型的时候,该方法中的几种类型必须是该泛型实例类型或者其子类。

在初始化泛型类的时候,不指定泛型的时候,泛型的类型为Object,就比如ArrayList中,如果不指定泛型,那么这个ArrayList中可以放任意类型的对象。

泛型的好处是在编译的时候进行类型安全检查,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

泛型方法例子:

/** * Created with IntelliJ IDEA. * Description: * User: zhubo * Date: 2017-11-29 * Time: 19:49 */public class Generate
{ private T key; public Generate(T key) { this.key = key; } public T getKey() { return key; } public void setKey(T key) { this.key = key; }}
/** * Created with IntelliJ IDEA. * Description: * User: zhubo * Date: 2017-11-29 * Time: 15:27 */public class DoMain {        public static void main(String[] args) {        Generate
generate = new Generate<>(123); DoMain domain = new DoMain(); Integer integer = domain.showKeyName(generate); System.out.println(integer); domain.showKeyValue2(generate); } //首先在public与返回值之间的
必不可少,这表明这是一个泛型方法,并进行泛型的T的类型声明 //这个T可以出现在这个泛型方法的任意位置 public
void showD(T e){ } //泛型的数量也可以为任意多个 public
K show(T t,K k){ K kk = null; return kk; } public
void showList(List
list){ } public
T showKeyName(Generate
container){ System.out.println("container key :" + container.getKey()); T test = container.getKey(); return test; } public void showKeyValue(Generate
obj){ System.out.println("key value is " + obj.getKey()); } public
void showKeyValue1(Generate
obj){ } public void showKeyValue2(Generate
obj){ System.out.println("key value is " + obj.getKey()); }}

泛型方法与可变参数

再看一个泛型方法和可变参数的例子:

public 
void printMsg(T ... args){ for(T t : args){ System.out.println(t); } } public static void main(String[] args) { DoMain domain = new DoMain(); domain.printMsg("111",222,"aaa","234.5"); }

静态方法与泛型

静态方法有一种情况需要注意一下,那就是在类中的静态方法使用泛型:静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。

即:如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法 。

/** * Created with IntelliJ IDEA. * Description: * User: zhubo * Date: 2017-11-29 * Time: 21:10 */public class StaticGenerator
{ /** * 如果在类中定义使用泛型的静态方法,需要添加额外的泛型声明(将这个方法定义成泛型方法) * 即使静态方法要使用泛型类中已经声明过的泛型也不可以。 * 如:public static void show(T t){..},此时编译器会提示错误信息: * "StaticGenerator cannot be refrenced from static context" */ public static
void show(T t){ }}

泛型方法总结

泛型方法能使方法独立于类而产生变化,以下是一个基本的指导原则:

无论何时,如果你能做到,你就该尽量使用泛型方法。也就是说,如果使用泛型方法将整个类泛型化,那么就应该使用泛型方法。另外对于一个static的方法而已,无法访问泛型类型的参数。所以如果static方法要使用泛型能力,就必须使其成为泛型方法。

 

 

 

 

转载于:https://my.oschina.net/LucasZhu/blog/1581748

你可能感兴趣的文章
一篇很全面的IOS面试题(下)
查看>>
极简.高性能.分布式框架,可运行于多种环境(apache/php-fpm,swoole)
查看>>
DESTOON7.0农产品B2B供应求购交易平台源码
查看>>
node js 批量处理pdf,提取关键信息,并导出excel
查看>>
05 Objective C数组的四种遍历方法总结
查看>>
少侠请重新来过 - Vue学习笔记(五) - 指令
查看>>
关闭webstorm(2017.3.5)的分号检测
查看>>
设计模式(二十三)中介者模式
查看>>
重学前端(六)-JavaScript中的class
查看>>
技术并非一切,做做 Side Project 吧
查看>>
ViewPager+seekBar的联动效果
查看>>
前端面试每日3+1(周汇总2019.05.05)
查看>>
RPA:制造业的下一个改变者
查看>>
VSCode Python开发环境配置
查看>>
208道 java 高频面试题和答案
查看>>
nginx反向代理配置
查看>>
MySQL学习笔记 初学基础篇
查看>>
一步步教你用 CSS 为 SVG 添加过滤器
查看>>
TeeChart Pro VCL/FMX教程(一):入门——构建图表
查看>>
微服务架构 SpringCloud(二)Eureka(服务注册和服务发现基础篇)
查看>>