`
zddava
  • 浏览: 243662 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

深入了解Java泛型(四) -- 有限制通配符

阅读更多
大概有限制通配符的使用是源于Java的泛型的不可变性,所谓的不可变性就是说对于两个Set<T1>和Set<T2>,不管T1和T2谁是谁的父类,Set<T1>和Set<T2>都不会是父子类的关系。

Java泛型的不可变性在应用中可能会遇到一些不方便的地方,尽管它很安全,比如一段这样的代码,加入我们要自己实现一个简单的List类如下:

public class MyList<T> {

	private T[] elements = null;

	private int cursor = -1;

	private static final int DEFAULT_CAPACITY = 10;

	public MyList() {
		this(DEFAULT_CAPACITY);
	}

	public MyList(int capacity) {
		@SuppressWarnings("unchecked")
		T[] t = (T[]) new Object[capacity];
		elements = t;
	}

	private void allocateNew() {
		@SuppressWarnings("unchecked")
		T[] t = (T[]) new Object[elements.length * 2];
		for (int i = 0; i < elements.length; i++) {
			t[i] = elements[i];
		}
		elements = t;
	}

	public MyList<T> add(T t) {
		if (cursor >= elements.length - 1) {
			allocateNew();
		}

		cursor++;
		elements[cursor] = t;
		return this;
	}

	public T get(int i) {
		return elements[i];
	}

	public int size() {
		return elements.length;
	}

	public MyList<T> addAll(MyList<T> myList) {
		int size = myList.size();
		for (int i = 0; i < size; i++) {
			add(myList.get(i));
		}
		return this;
	}
}


很简单,内部维护一个数组去实现列表,下面是使用这个类的代码:

public class InvariantTester {

	public static void main(String[] args) {
		MyList<CharSequence> charSeqList = new MyList<CharSequence>();
		charSeqList.add("s").add("t").add("r").add("i").add("n").add("g");

		MyList<String> stringList = new MyList<String>();
		stringList.add("s").add("t").add("r").add("i").add("n").add("g");

		charSeqList.addAll(stringList);

	}

}


这里前面的charSeqList.add("s").add("t").add("r").add("i").add("n").add("g")这步是不会报错的,而后边的charSeqList.addAll(stringList)是通不过编译的,原因就是泛型的不可变性,这里就要通过有限制的通配符类型去解决了,很简单,修改一下addAll的方法声明就可以了:

	public MyList<T> addAll(MyList<? extends T> myList) {
		int size = myList.size();
		for (int i = 0; i < size; i++) {
			add(myList.get(i));
		}
		return this;
	}


这里就是有限制通配符类型的一个典型应用,当然还可以使用<? super T>这种限制方式的。

为了在泛型的方法参数上获得最大限度的灵活性,就需要有限制通配符类型的参与了,这里需要重点介绍的是使用有限制通配符类型时的PECS(producer-extends, consumer-super)原则,也就是<? extends T>和<? super T>的使用时机选择的原则。

如果类型是一个生产者,那么就使用extends,如果是消费者,那么就用super。

比如前面的例子,addAll(MyList<? extends T> myList)这个方法的参数是为了给MyList类消费的,所以参数是生产者,下面再举个消费者的例子。还是上边的MyList类,我再添加一个方法进去:

	public void copyTo(MyList<? super T> dstList) {
		dstList.addAll(this);
	}


基本就是addAll()方法的逆方法,这里的参数dstList就是一个消费者了,同样,稍稍修改一下InvariantTester,加入这个方法的使用:

public class InvariantTester {

	public static void main(String[] args) {
		MyList<CharSequence> charSeqList = new MyList<CharSequence>();
		charSeqList.add("s").add("t").add("r").add("i").add("n").add("g");

		MyList<String> stringList = new MyList<String>();
		stringList.add("s").add("t").add("r").add("i").add("n").add("g");

		charSeqList.addAll(stringList);

		stringList.copyTo(charSeqList);

	}

}


到这里,有限制通配符类型就大致叙述到这里了,实际应用中可能会遇到非常复杂的应用,到时候就要具体问题具体分析了,我在工作中基本上用不到,也谈不上有什么经验了。
分享到:
评论

相关推荐

    全面总结Java泛型--实例

    标题与描述均提到了“全面总结Java泛型--实例”,这表明文章旨在深入解析Java泛型的概念,并通过具体示例来展示其应用。Java泛型是Java编程语言的一个强大特性,它允许在编译时检查类型安全,并且所有的强制转换都是...

    java泛型深入.pdf

    Java泛型还支持带有通配符的泛型类型,例如`List&lt;?&gt;`表示未知类型的`List`,这是不可变的。`List&lt;? extends T&gt;`表示`T`类型或其子类型的`List`,而`List&lt;? super T&gt;`表示`T`类型或其父类型的`List`。 使用泛型时,...

    java泛型技术之发展

    本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展历程** - **早期版本的局限**:在Java泛型出现之前,程序员通常使用Object作为容器类(如ArrayList、HashMap等)的默认类型...

    Java泛型应用实例

    Java泛型是Java编程语言中的一个强大特性,它允许我们在定义类、接口和方法时指定类型参数,从而实现代码的重用和类型安全。在Java泛型应用实例中,我们可以看到泛型如何帮助我们提高代码的灵活性和效率,减少运行时...

    Java泛型和集合-英文版

    由于书籍的作者是Maurice Naftalin和Philip Wadler,这两人都是在泛型和集合方面有着深入研究的专家,因此书中内容被期待会是权威和详尽的,为读者提供全面的Java泛型和集合知识。本书适合有一定Java基础并希望深入...

    java 泛型的使用 详细讲解

    ### Java泛型的使用详细讲解 #### 一、引言 在Java开发中,泛型是一种重要的语言特性,它能够帮助开发者在不增加代码量的情况下处理多种数据类型,同时还能保持代码的清晰度和可读性。本文将详细介绍Java泛型的...

    java 泛型方法使用示例

    下面我们将深入探讨Java泛型方法的概念、语法以及使用示例。 **一、泛型方法概念** 泛型方法是一种具有类型参数的方法,这些类型参数可以在方法声明时指定,并在方法体内部使用。与类的泛型类似,它们提供了编译时...

    java 泛型入门 实例

    本篇文章将带你入门Java泛型,通过实例深入理解其核心概念。 1. **泛型的基本概念** - 泛型是一种允许在定义类、接口和方法时使用类型参数的机制。这使得代码可以在编译时期检查类型,避免了不必要的类型转换,并...

    Java泛型技术之发展.pdf

    本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展历程** Java泛型的引入是为了解决早期版本中类型转换频繁和潜在的ClassCastException问题。在Java泛型出现之前,集合框架...

    Java泛型类型擦除后的补偿

    本文将深入探讨Java泛型类型擦除的概念,并介绍在类型擦除后,为了保持泛型的安全性和便利性,Java设计者所采取的一些补偿机制。 1. **类型擦除**: - 在编译期间,所有的泛型类型信息都会被替换为它们的实际类型...

    java泛型的内部原理及更深应用

    在“java泛型的内部原理及更深应用”这个主题中,我们将深入探讨以下几个关键知识点: 1. **类型擦除**:Java泛型的主要特点是类型擦除。这意味着在编译完成后,所有的泛型信息都会被擦除,替换为Object或者其他...

    Java泛型总结(2)进阶篇

    在本文中,我们将深入探讨Java泛型的进阶概念,包括通配符、边界、类型擦除以及在实际开发中的应用。 1. 通配符 通配符在Java泛型中扮演着重要角色,它允许我们处理多种类型的参数。例如,`&lt;?&gt;` 表示未知类型,...

    SUN公司Java泛型编程文档

    SUN公司的Java泛型编程文档,包括英文原版和网络翻译版,为开发者提供了深入理解和熟练运用泛型的重要资源。 首先,泛型的基本概念是允许在定义类、接口和方法时使用类型参数,这样就可以在编译时检查类型安全,...

    关于C#、java泛型的看法

    这意味着Java的泛型不支持协变和逆变,但可以通过通配符(如?)来放宽类型限制。Java的泛型约束则相对较少,主要通过extends和super关键字来限制类型参数的范围。 在实际应用中,C#的泛型在效率上可能具有优势,...

    Java泛型实例

    Java泛型是Java编程语言中的一个重要特性,它在2004年随着Java SE 5.0的发布而引入。这个特性允许程序员在定义类、接口和方法时声明类型参数,从而增强了代码的类型安全性和重用性。通过使用泛型,我们可以编写更加...

    java泛型Demo

    在这个"java泛型Demo"中,我们将深入探讨泛型的概念、用法以及它们如何提升Java编程的效率和安全性。 1. **泛型的基本概念**: 泛型允许我们在类、接口和方法中定义参数化类型。这意味着我们可以在不指定具体数据...

    java泛型源码-Java-Generics-Our-Generics-Class-Part-3-Source-code:通用课程

    在本教程中,我们将深入探讨Java泛型的源码实现,特别是"Java-Generics-Our-Generics-Class-Part-3-Source-code"项目中的部分。 首先,泛型的主要目标是消除运行时类型转换异常,例如`ClassCastException`。通过在...

    java泛型指南 经典

    ### Java泛型指南经典知识点解析 #### 一、引言 Java 1.5 版本引入了一系列重要的语言特性,其中“泛型”是其中一项关键特性。泛型的引入极大地提高了 Java 语言的类型安全性和代码重用性。本文档旨在深入探讨 ...

    Java泛型编程最全总结

    Java泛型还有通配符,用于表示对类型的限制。例如,`?`表示任何类型,`? extends Number`表示任何Number的子类,这在处理多种类型集合时非常有用。比如,`accept(List)`可以接收`List&lt;Integer&gt;`、`List&lt;Double&gt;`等。...

Global site tag (gtag.js) - Google Analytics