总结Java的泛型前,先简单的介绍下C#的泛型,通过对比,比较学习Java泛型的目的和设计意图。C#泛型是C#语言2.0和通用语言运行时(CLR)同时支持的一个特性(这一点是导致C#泛型和Java泛型区别的最大原因,后面会介绍)。C#泛型在.NET CLR支持为.NET框架引入参数化变量支持。C#泛型更类似C++模板,可以理解,C#泛型实际上可以理解为类的模板类。我们通过代码实例来看C# 2.0泛型解决的问题,首先,我们通过一个没有泛型的迭代器的代码示例说起,代码实现如下:

        interface IEnumerable
{
void Add(Object x);
IEnumerator GetEnumerator();
}
interface IEnumerator
{
Object Next();
bool HasNext();
}
class NoSuchElementException : ArgumentException { }
class LinkedList : IEnumerable
{
private class Node
{
public Object Data { get; set; }
public Node Next { get; set; }
public Node(Object data)
{
this.Data = data;
}
} class DataEnumerator : IEnumerator
{
public DataEnumerator(Node ptr)
{
this.head = ptr;
}
private Node head;
public object Next()
{
if (head != null)
{
Object data = head.Data;
head = head.Next;
return data;
}
else
{
throw new NoSuchElementException();
}
}
public bool HasNext()
{
return head != null;
}
}
private Node head = null, tail = null;
public void Add(Object data)
{
if (head == null)
{
head = new Node(data);
tail = head;
}
else
{
tail.Next = new Node(data);
tail = tail.Next;
}
}
public IEnumerator GetEnumerator()
{
return new DataEnumerator(head);
}
}

  通过以上C#代码对迭代器的实现,我们发现代码至少存在以下几个问题:

  1. 如果我不想在对LinkedList集合对象存储的时候发生装箱拆箱的性能损失,只是对特点类型的元素集合进行操作。如:我们LinkedList存储了100w的整数,用LinkedList存储的时候,每次都把整数 转出 Object,相当于在堆内存中对数字进行了100w次打包,其中的性能损失我们不能不考虑。我们考虑性能的话,我们可以修改LinkedList的实现,将内嵌类Node的Data数据类型改为int类型,修改后的实现如下: 

        interface IEnumerable
    {
    void Add(int x);
    IEnumerator GetEnumerator();
    } interface IEnumerator
    {
    int Next();
    bool HasNext();
    }
    class NoSuchElementException : ArgumentException { }
    class LinkedList : IEnumerable
    {
    private class Node
    {
    public int Data { get; set; }
    public Node Next { get; set; }
    public Node(int data)
    {
    this.Data = data;
    }
    }
    class DataEnumerator : IEnumerator
    {
    public DataEnumerator(Node ptr)
    {
    this.head = ptr;
    }
    private Node head;
    public int Next()
    {
    if (head != null)
    {
    int data = head.Data;
    head = head.Next;
    return data;
    }
    else
    {
    throw new NoSuchElementException();
    }
    } public bool HasNext()
    {
    return head != null;
    }
    }
    private Node head = null, tail = null;
    public void Add(int data)
    {
    if (head == null)
    {
    head = new Node(data);
    tail = head;
    }
    else
    {
    tail.Next = new Node(data);
    tail = tail.Next;
    }
    }
    public IEnumerator GetEnumerator()
    {
    return new DataEnumerator(head);
    }
    }

    用LinkedList存储整数虽然没有问题了,但是下一次我们需要用LinkedList存储100w的字符的话,我们还要修改LinkedList的实现。分析我们的代码实现我们会发现,当我们存储不同的数据结构的时候,我们大部分代码都是相同的,只是LinkedList存储的数据类型不一样。  

  2. LinkedList linkedList = new LinkedList(),linkedList集合存储的都是Object类型的元素,对集合进行操作的时候,如果对集合存储的代码调用时元素类型信息无法直接确定,无法判断集合存储的具体类型。例如,我们有如下代码的调用:
    class Program
    {
    static void Main(string[] args)
    {
    LinkedList list = new LinkedList();
    list.Add(new A());
    list.Add(new B()); IEnumerator e = list.GetEnumerator();
    while (e.HasNext())
    {
    B b = e.Next() as B; //此处类型转换,当转换不成功时候,捕获异常,返回类型为空
    if(b != null)
    b.MethodB();
    }
    }
    }
    class A
    {
    public void MethodA()
    {
    Console.WriteLine("Invoke MethodA");
    }
    }
    class B:A
    {
    public void MethodB()
    {
    Console.WriteLine("Invoke MethodA");
    }
    }

    以上代码在调用 B b = e.Next() as B 语句的时候,此处类型转换,当转换不成功时候,捕获异常,返回类型为空。

  3. LinkedList集合对象在存储元素的时候,对元素进行隐式类型转换(子类转换成Object类型)或者(值类型发生装箱操作)。

  下面我们通过C#2.0开始支持的泛型来解决了以上的问题,泛型化修改后的代码如下:

    interface IEnumerable<T>
{
void Add(T x);
IEnumerator<T> GetEnumerator();
}
interface IEnumerator<T>
{
T Next();
bool HasNext();
}
class NoSuchElementException<T> : ArgumentException { }
class LinkedList<T> : IEnumerable<T>
{
private class Node
{
public T Data { get; private set; }
public Node Next { get; set; }
public Node(T data)
{
this.Data = data;
}
}
class DataEnumerator : IEnumerator<T>
{
public DataEnumerator(Node ptr)
{
this.head = ptr;
} private Node head;
public T Next()
{
if (head != null)
{
T data = head.Data;
head = head.Next;
return data;
}
else
{
throw new NoSuchElementException<T>();
}
}
public bool HasNext()
{
return head != null;
}
} private Node head = null, tail = null;
public void Add(T data)
{
if (head == null)
{
head = new Node(data);
tail = head;
}
else
{
tail.Next = new Node(data);
tail = tail.Next;
}
}
public IEnumerator<T> GetEnumerator()
{
return new DataEnumerator(head);
}
}

通过以上对C#泛型分析,简单总结下C#引入,在我看来至少解决了三个问题:

  1. 封装和复用通用代码逻辑;
  2. 增强了编译期类型检查,减少了运行时发生InvalidCastException异常的几率;
  3. 解决集合操作时候的装箱和拆箱的效率问题。

  简答介绍了C#泛型引入解决的问题后,下面我们开始介绍今天的主角—Java泛型。我们会对比以上三个问题来对比分析Java引入泛型所解决的问题。下面同样来一段Java实现的迭代器的实现的代码,如下:

      interface Collection {
public void add (Object x);
public Iterator iterator ();
} interface Iterator {
public Object next ();
public boolean hasNext ();
} class NoSuchElementException extends RuntimeException {} class LinkedList implements Collection { protected class Node {
Object elt;
Node next = null;
Node (Object elt) { this.elt = elt; }
} protected Node head = null, tail = null; public LinkedList () {} public void add (Object elt) {
if (head == null) { head = new Node(elt); tail = head; }
else { tail.next = new Node(elt); tail = tail.next; }
} public Iterator iterator () { return new Iterator () {
protected Node ptr = head;
public boolean hasNext () { return ptr != null; }
public Object next () {
if (ptr != null) {
Object elt = ptr.elt; ptr = ptr.next; return elt;
} else throw new NoSuchElementException ();
}
};
}
}

对比C#和Java的迭代器实现,不得不说Java的迭代器实现看起来更优雅。Java对内部类的支持,让Java在类型实现上更灵活多样。下面我们来看看Java泛型迭代器的实现如下:

interface Collection<A> {
public void add(A x);
public Iterator<A> iterator();
} interface Iterator<A> {
public A next();
public boolean hasNext();
} class NoSuchElementException extends RuntimeException {} class LinkedList<A> implements Collection<A> {
protected class Node {
A elt;
Node next = null;
Node (A elt) { this.elt = elt; }
} protected Node head = null, tail = null; public LinkedList () {} public void add (A elt) {
if (head == null) { head = new Node(elt); tail = head; }
else { tail.next = new Node(elt); tail = tail.next; }
} public Iterator<A> iterator () {
return new Iterator<A> () {
protected Node ptr = head;
public boolean hasNext () { return ptr != null; }
public A next () {
if (ptr != null) {
A elt = ptr.elt; ptr = ptr.next; return elt;
} else throw new NoSuchElementException ();
}
};
}
}

通过以上的代码的实现,我们可能觉得Java泛型和C#都能很好解决以上三个问题。看过下面的一段代码之后,可能你对Java泛型的会有不同的认识,代码如下:

public class Program {
public static void main(String[] args) {
Class<?> c1 = new ArrayList<String>().getClass();
Class<?> c2 = new ArrayList<Integer>().getClass();
if(c1 == c2)
{
System.out.println("类型相同");
}
}
}
//类型相同

按C#对泛型的理解,泛型实质就是类的模板。我们认为很容易知道类ArrayList<String>和ArrayList<Integer>应该是不同的类型。但是上面的代码输出结果,Java运行结果判断ArrayList<String>和ArrayList<Integer>是相同的类型。

  我们马上会有疑问,在运行状态,我们的泛型参数类型信息哪去了?我们的泛型怎么了?对java泛型有一定了解的同学马上就知道,在运行状态,我们无法获取泛型的参数信息。Java的泛型不是真正的泛型,只是编译器的泛型,不是运行时的泛型。关于为什么会这样设计,我们就需要去追溯java的历史。

 Java泛型历史

 Java泛型是Java 1.5开始加入的语言特性,在Java 1.5之前很长一段时间,Java程序已经在我们身边的个人设备中运行。为了支持泛型出现以前的运行在Java开发的软件中的各种库,Java语言的设计师采取一种折中的方案,Java泛型不仅能向后兼容,而且保证现有的代码和类文件也合法,仍然保持原来的意思。

 Java泛型实现机制

 Java泛型为了向前兼容,采取运行期类型擦出泛型参数的方式来实现。这就意味着,你在使用泛型的时候,任何具体的类型都已经被擦除。因此,以上的ArrayList<String>和ArrayList<Integer>实际上都恢复到他们的原生类型List,是同一种类型。正确理解Java泛型的类型擦除,能帮我们理解Java泛型中的很多奇怪特性。今天关于泛型就先写到这里,下一节开始介绍Java泛型的类型的擦除机制引起的很多奇怪泛型特性、Java泛型设计做出的一些弥补。

   

Java泛型学习笔记--Java泛型和C#泛型比较学习(一)的更多相关文章

  1. [java学习笔记]java语言核心----面向对象之this关键字

    一.this关键字 体现:当成员变量和函数的局部变量重名时,可以使用this关键字来区别:在构造函数中调用其它构造函数 原理:         代表的是当前对象.         this就是所在函数 ...

  2. [java学习笔记]java语言核心----面向对象之构造函数

    1.构造函数概念 特点: 函数名与类名相同 不用定义返回值类型 没有具体的返回值 作用:                给对象进行初始化 注意: 默认构造函数 多个构造函数是以重载出现的 一个类中如果 ...

  3. UFLDL深度学习笔记 (三)无监督特征学习

    UFLDL深度学习笔记 (三)无监督特征学习 1. 主题思路 "UFLDL 无监督特征学习"本节全称为自我学习与无监督特征学习,和前一节softmax回归很类似,所以本篇笔记会比较 ...

  4. Vue学习笔记-Django REST framework3后端接口API学习

    一  使用环境 开发系统: windows 后端IDE: PyCharm 前端IDE: VSCode 数据库: msyql,navicat 编程语言: python3.7  (Windows x86- ...

  5. java JDK8 学习笔记——第18章 自定义泛型、枚举与注释

    第十八章 自定义泛型.枚举与注释 18.1 自定义泛型 泛型定义: (1)仅定义在方法上的泛型语法 (2)用来限制泛型可用类型的extends与super关键字(3)?类型通配字符的使用 18.1.1 ...

  6. 大数据学习笔记——Java篇之集合框架(ArrayList)

    Java集合框架学习笔记 1. Java集合框架中各接口或子类的继承以及实现关系图: 2. 数组和集合类的区别整理: 数组: 1. 长度是固定的 2. 既可以存放基本数据类型又可以存放引用数据类型 3 ...

  7. Java学习笔记 -- Java定时调度工具Timer类

    1 关于 (时间宝贵的小姐姐请跳过) 本教程是基于Java定时任务调度工具详解之Timer篇的学习笔记. 什么是定时任务调度 基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行的任务. 在Ja ...

  8. 大数据学习笔记——Java篇之网络编程基础

    Java网络编程学习笔记 1. 网络编程基础知识 1.1 网络分层图 网络分层分为两种模型:OSI模型以及TCP/IP网络模型,前者模型分为7层,是一个理论的,参考的模型:后者为实际应用的模型,具体对 ...

  9. 大数据学习笔记——Java篇之IO

    IO学习笔记整理 1. File类 1.1 File对象的三种创建方式: File对象是一个抽象的概念,只有被创建出来之后,文件或文件夹才会真正存在 注意:File对象想要创建成功,它的目录必须存在! ...

随机推荐

  1. grunt配置任务

    这个指南解释了如何使用 Gruntfile 来为你的项目配置task.如果你还不知道 Gruntfile 是什么,请先阅读 快速入门 指南并看看这个Gruntfile 实例. Grunt配置 Grun ...

  2. REDHAT一总复习1 cups 打印服务配置

    停止cups服务 $ sudo systemctl stop cups $ sudo systemctl status cups 配置cups服务,使其不在系统启动时启动 $ sudo systemc ...

  3. VMware Workstation 10.0 正式版官方简体中文下载(附序列号)

    虚拟机界数一数二的王者软件VMWare Workstation 今日推出了最新的VMware Workstation 10.0 版本.该版本最大的更新是加入了简体中文语言,这意味着未来神马汉化包.中文 ...

  4. The prefix &quot;tx&quot; for element &quot;tx:annotation-driven &quot; is not bound

    The prefix "tx" for element "tx:advice" is not bound 这个错误的原因很简单是: 我们在定义申明AOP的时候. ...

  5. Objective-C学习笔记类目、协议

    不是所有的方法都可以被覆盖的!比如:intValue就不能被覆盖!! 原因正在查找中! 别人的电脑上却可以! 类目.h件 #import <Foundation/Foundation.h> ...

  6. ABAP 表格控制(Table Control)和步循环

    表格控制(Table Control)和步循环     1.两个标准Demo: SAPMTZ60,SAPMTZ61 2.简介 3.建立Table Control程序的基本流程 4.使用步循环 5.表格 ...

  7. WINDOWS下更改MYSQL数据路径(datadir)后服务启动1067解决不能改变mysql数据库存储位置

    晚上安装完MYSQL(系统:深度WINXPSP2, MYSQL版本:5.1.32)后,用MYSQL自带的配置工具配置完发现默认的数据存放路径是:C:/Documents and Settings/Al ...

  8. 对css float 浮动的学习心得

    css float浮动详解 @(css float)[hasLayout|clear float|妙瞳] css float的定义和用法 float 属性定义元素在哪个方向浮动.以往这个属性总应用于图 ...

  9. (原)matlab中使用mex编译多个cpp文件

    以前一直是mex一个文件.刚才需要编译多个文件(如a.cpp调用b.cpp的函数,b.cpp调用c.cpp的函数).如果只是mex a.cpp,提示函数找不到函数. 突然想到mex c.cpp b.c ...

  10. Beijing seminar: China shadow banking

    Beijing seminar: China shadow banking-张化桥-财新博客-新世纪的常识传播者-财新网 Beijing seminar: China shadow banking