标签:style blog color io os ar 使用 java strong
总结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#代码对迭代器的实现,我们发现代码至少存在以下几个问题:
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);
}
}
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 语句的时候,此处类型转换,当转换不成功时候,捕获异常,返回类型为空。
下面我们通过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#引入,在我看来至少解决了三个问题:
简答介绍了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#泛型比较学习(一)
标签:style blog color io os ar 使用 java strong
原文地址:http://www.cnblogs.com/Johnnie/p/4025008.html