java泛型:泛型类、泛型接口和泛型方法
根据《Java编程思想 (第4版)》中的描述,泛型出现的动机在于:
有许多原因促成了泛型的出现,而最引人注意的一个原因,就是为了创建容器类。
泛型类
容器类应该算得上最具重用性的类库之一。先来看一个没有泛型的情况下的容器类如何定义:
public class Container { private String key; private String value; public Container(String k, String v) { key = k; value = v; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
Container类保存了一对key-value键值对,但是类型是定死的,也就说如果我想要创建一个键值对是String-Integer类型的,当前这个Container是做不到的,必须再自定义。那么这明显重用性就非常低。
当然,我可以用Object来代替String,并且在Java SE5之前,我们也只能这么做,由于Object是所有类型的基类,所以可以直接转型。但是这样灵活性还是不够,因为还是指定类型了,只不过这次指定的类型层级更高而已,有没有可能不指定类型?有没有可能在运行时才知道具体的类型是什么?
所以,就出现了泛型。
public class Container<K, V> { private K key; private V value; public Container(K k, V v) { key = k; value = v; } 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; } }
在编译期,是无法知道K和V具体是什么类型,只有在运行时才会真正根据类型来构造和分配内存。可以看一下现在Container类对于不同类型的支持情况:
public class Main { public static void main(String[] args) { Container<String, String> c1 = new Container<String, String>("name", "findingsea"); Container<String, Integer> c2 = new Container<String, Integer>("age", 24); Container<Double, Double> c3 = new Container<Double, Double>(1.1, 2.2); System.out.println(c1.getKey() + " : " + c1.getValue()); System.out.println(c2.getKey() + " : " + c2.getValue()); System.out.println(c3.getKey() + " : " + c3.getValue()); } }
输出:
name : findingsea age : 24 1.1 : 2.2
泛型接口
在泛型接口中,生成器是一个很好的理解,看如下的生成器接口定义:
public interface Generator<T> { public T next(); }
然后定义一个生成器类来实现这个接口:
public class FruitGenerator implements Generator<String> { private String[] fruits = new String[]{"Apple", "Banana", "Pear"}; @Override public String next() { Random rand = new Random(); return fruits[rand.nextInt(3)]; } }
调用:
public class Main { public static void main(String[] args) { FruitGenerator generator = new FruitGenerator(); System.out.println(generator.next()); System.out.println(generator.next()); System.out.println(generator.next()); System.out.println(generator.next()); } }
输出:
Banana Banana Pear Banana
泛型方法
一个基本的原则是:无论何时,只要你能做到,你就应该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类泛化,那么应该有限采用泛型方法。下面来看一个简单的泛型方法的定义:
public class Main { public static <T> void out(T t) { System.out.println(t); } public static void main(String[] args) { out("findingsea"); out(123); out(11.11); out(true); } }
可以看到方法的参数彻底泛化了,这个过程涉及到编译器的类型推导和自动打包,也就说原来需要我们自己对类型进行的判断和处理,现在编译器帮我们做了。这样在定义方法的时候不必考虑以后到底需要处理哪些类型的参数,大大增加了编程的灵活性。
再看一个泛型方法和可变参数的例子:
public class Main { public static <T> void out(T... args) { for (T t : args) { System.out.println(t); } } public static void main(String[] args) { out("findingsea", 123, 11.11, true); } }
输出和前一段代码相同,可以看到泛型可以和可变参数非常完美的结合。

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

Java 8引入了Stream API,提供了一种强大且表达力丰富的处理数据集合的方式。然而,使用Stream时,一个常见问题是:如何从forEach操作中中断或返回? 传统循环允许提前中断或返回,但Stream的forEach方法并不直接支持这种方式。本文将解释原因,并探讨在Stream处理系统中实现提前终止的替代方法。 延伸阅读: Java Stream API改进 理解Stream forEach forEach方法是一个终端操作,它对Stream中的每个元素执行一个操作。它的设计意图是处

胶囊是一种三维几何图形,由一个圆柱体和两端各一个半球体组成。胶囊的体积可以通过将圆柱体的体积和两端半球体的体积相加来计算。本教程将讨论如何使用不同的方法在Java中计算给定胶囊的体积。 胶囊体积公式 胶囊体积的公式如下: 胶囊体积 = 圆柱体体积 两个半球体体积 其中, r: 半球体的半径。 h: 圆柱体的高度(不包括半球体)。 例子 1 输入 半径 = 5 单位 高度 = 10 单位 输出 体积 = 1570.8 立方单位 解释 使用公式计算体积: 体积 = π × r2 × h (4

Java是热门编程语言,适合初学者和经验丰富的开发者学习。本教程从基础概念出发,逐步深入讲解高级主题。安装Java开发工具包后,可通过创建简单的“Hello,World!”程序实践编程。理解代码后,使用命令提示符编译并运行程序,控制台上将输出“Hello,World!”。学习Java开启了编程之旅,随着掌握程度加深,可创建更复杂的应用程序。
