博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 泛型初识
阅读量:5161 次
发布时间:2019-06-13

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

  1. 什么是泛型?
  • 一个泛型类(generic class)就是有一个或多个类型变量的类。
  • 又叫做参数化类型,将类型当做参数传递给一个类或者方法
  1. 为什么要使用泛型程序设计?
  • 泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用。泛型可以看作是普通的工厂
  1. 泛型类声明
原生态类型
/*** 原生态类型*/public class Stack {    private Object[] elements;    private int size = 0;    private static final int DEFAULT_INITIAL_CAPACITY = 16;    public Stack() {        elements = new Object[DEFAULT_INITIAL_CAPACITY];    }    public void push(Object e) {        ensureCapacity();        elements[size++] = e;    }    public Object pop() {        if (size == 0) {            throw new EmptyStackException();        }        Object result = elements[size--];        elements[size] = null;        return result;    }    public boolean isEmpty() {        return size == 0;    }    private void ensureCapacity() {        if (elements.length == size) {            elements = Arrays.copyOf(elements, 2 * size + 1);        }    }}

泛型类声明方式一

/*** 原生态类型转泛型类型方式一(较常用)*/public class StackE1
{ private E[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; @SuppressWarnings("unchecked") public StackE1() { // 创建Object 数组,并转换成泛型数组 elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(E e) { ensureCapacity(); elements[size++] = e; } public E pop() { if (size == 0) { throw new EmptyStackException(); } E result = elements[size--]; elements[size] = null; return result; } public boolean isEmpty() { return size == 0; } private void ensureCapacity() { if (elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1); } }}

泛型类声明二

/*** 原生态类型转泛型类型方式二*/public class StackE2
{ private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public StackE2() { // 创建Object 数组,并转换成泛型数组 elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(E e) { ensureCapacity(); elements[size++] = e; } public E pop() { if (size == 0) { throw new EmptyStackException(); } @SuppressWarnings("unchecked") E result = (E) elements[--size]; elements[size] = null; return result; } public boolean isEmpty() { return size == 0; } private void ensureCapacity() { if (elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1); } }}
  1. 泛型方法
原始泛型方法
public class StackMethod {    public static Set union(Set s1,Set s2){        Set result = new HashSet(s1);        result.add(s2);        return result;    }}

泛型方法声明

public class StackMethodM1 {    // 1.public static Set
之间的
代表什么意思? // 它表示一个类型参数,能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符,这个过程称为类型推导 // 2.Set
s1, Set
s2 代表什么意思? // 字母E是一个代号,被称为类型变量或类型参数,当然你也可以换成a,b,c...这么写更规范,通常有E(element)、T(type)、K、V、N(number) // 注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char...) public static
Set
union(Set
s1, Set
s2) { Set
result = new HashSet
(s1); result.addAll(s2); return result; }}
  1. 泛型单例工厂(类型推导的应用)
泛型静态工厂方法,目的是为了消除,Map<String,List<String>> map = new HashMap<String,List<String>>(),标记部分的冗余部分
public class HashMapUtil {    // 泛型静态工厂方法    public static 
HashMap
newInstance() { return new HashMap
(); }}

客户端实例

public class HashMapInstance {    public static void main(String[] args) {        // 利用工具类创建HashMap 对象        Map
> map = HashMapUtil.newHashMap(); // 原始方法创建HashMap 对象 Map
> map1 = new HashMap
>(); }}
  1. 递归类型限制
定义一个泛型接口,跟泛型类差不多
public interface IUnaryFun
{ T apply(T arg);}

假设需要提供一个恒等函数,如果在每次需要的时候都重新创建一个,这样会很浪费,因为他是无状态的,如果泛型被具体化了,每个类型都需要一个恒等函数,但是他们被擦除以后,就只需要一个泛型单例。

/*** 递归限制类型*/public class RecursiveType {    // 泛型单例工厂模式    private static IUnaryFun IDENTITY_FUN = new IUnaryFun() {        public Object apply(Object arg) {            return arg;        }    };    // 无状态的参数类型    @SuppressWarnings({ "unchecked" })    private static 
IUnaryFun
identityFun() { return (IUnaryFun
) IDENTITY_FUN; } public static void main(String[] args) { String[] strings = { "bob", "lily", "lucy" }; IUnaryFun
sameString = identityFun(); for (String s : strings) { System.out.println(sameString.apply(s)); } Number[] numbers = { 1, 1.1d, 2.2f }; IUnaryFun
sameNumber = identityFun(); for (Number n : numbers) { System.out.println(sameNumber.apply(n)); } }}
  1. 通配符限制和PECS
在泛型类型声明一种添加的pushAll() 方法,如下
public void pushAll(Iterable
src) { for (E e : src) { push(e); } }

客户端如下图的错误信息,因为如前所述,参数化类型是不可变得,因此无法将Integer 类型的数据插入Number 类型的参数中,尽管Number 是Integer 的父类

Java 提供一种特许的参数化类型:有限制的通配符类型 来处理这种情况。pushAll 输入的参数不应为“E 的Iterable 接口”,而应该为“E 的某个子类型的Iterable 接口”,有一个通配符类型正符合此意:Iterable<? Extends E>,修改后的代码如下,StackE3 可以正确无误地编译,这个也叫上界通配符
public void pushAll(Iterable
src) { for (E e : src) { push(e); } }

编写与pushAll 方法呼应的popAll方法,从堆栈中弹出每个元素,并将这些元素添加到指定集合中,在泛型类型声明一种添加的popAll() 方法,如下

public void popAll(Collection
dst) { while (!isEmpty()) { dst.add(pop()); } }

客户端如下图错误信息,同样的,因为Collection<Object> 不是Collection<Number> 的子类型

popAll 的输入参数类型不应该为“E 的集合”,而应该为“E 的某种超类的集合”,通俗的讲,就是Number 类型的数据无法添加到Object 类型,他们之间一开始是没关系的,这时仍有一个通配符正符合此意:Collection<? super E>。这也叫下界通配符
public void popAll(Collection
dst) { while (!isEmpty()) { dst.add(pop()); } }

  

声明:本文版权归作者和博客园共有,欢迎转载,但请在文章页面明显位置给出原文连接。 

转载于:https://www.cnblogs.com/hellovoyager1/p/9202096.html

你可能感兴趣的文章
设置无标题&设置不显示状态栏
查看>>
Exception in thread "main" org.hibernate.MappingException: You may only specify a cache for root
查看>>
ZOJ - 3201 Tree of Tree (树形背包)
查看>>
libnet/libnids库函数介绍
查看>>
saveInstallState参数使用详解(android activity状态保存和恢复)
查看>>
mark
查看>>
HTTP header
查看>>
AVD启动不了 ANDROID_SDK_HOME is defined but could not find *.ini
查看>>
1~4次
查看>>
ubuntu18.04更新源
查看>>
大道至简第七、八章 读后随笔
查看>>
react 反模式——不使用jsx动态显示异步组件
查看>>
Linux下用文件IO的方式操作GPIO(/sys/class/gpio)
查看>>
Eclipse快捷键
查看>>
CentOS下配置SMTP
查看>>
Centos7中查看IP地址命令ifconfig无法识别如何处理
查看>>
Longest Consecutive Sequence
查看>>
python --001 -- 基础小知识
查看>>
P2P简单应用之通信协议介绍
查看>>
HOMEWORK2
查看>>