I学霸官方免费教程三十:Java基础教程之泛型

泛型

先给大家举个例子;如现在有一家工厂,可以生产手机,也可以生产电脑。以后还可能生产其他产品。
如果给某个工厂加上了泛型,就规定了这个工厂只能生产手机或电脑,不能再生产其他产品了。

实例:
package generic;
/**
 * 产品枚举Product
 * @author 学霸联盟 - 赵灿
 */
public enum Product {
	手机,电脑
}

package generic;
/**
 * 手机类Phone
 * @author 学霸联盟 - 赵灿
 */
public class Phone {
	/**
	 * 拨打电话的方法call
	 */
	public void call(){
		System.out.println("拨打电话");
	}
}

package generic;
/**
 * 电脑类Computer
 * @author 学霸联盟 - 赵灿
 */
public class Computer {
	/**
	 * 编写代码的方法
	 */
	public void coding() {
		System.out.println("编写代码");
	}
}
package generic;
/**
 * 普通工厂类Factory:用于和泛型工厂类做对比
 * @author 学霸联盟 - 赵灿
 */
public class Factory {
	/**
	 * 创建返回值类型为Object[],功能是生产多个产品对象
	 * 由于存在多种产品类型,所以返回值取所有产品共同的父类型Objec的数组
	 */
	public Object[] getProduct(){
		// 创建长度为2的Object类型的一维数组,可以存储手机,也可以存放电脑
		Object[] products = new Object[2];
		// 创建手机对象,存入数组下标为0的位置
		products[0] = new Phone();
		// 创建电脑对象,存入数组下标为1的位置
		products[1] = new Computer();
		// 返回数组products
		return products;
	}

	/**
	 * 创建根据参数值获取相应的产品
	 * 如果以后需要使用该方法创建其他产品,还要在switch语句中增加case语句,拓展性差
	 */
	public Object[] getProduct(Product productType){
		// 创建长度为2的Object类型的一维数组,可以存储手机,也可以存放电脑
		Object[] products = new Object[2];
		switch (productType) {
		case 手机:
			// 创建手机对象,存入数组下标为0的位置
			products[0] = new Phone();
			/*
			 * 即使productType的值为手机,此处依然可以存入电脑对象
			 * 如果此处误创建成Computer对象,获取时极有可能被误转为Phone类型
			 * 从而导致类型转换异常,健壮性(安全性)差
			 */
			products[1] = new Computer();
			break;
		case 电脑:
			// 创建两个Computer对象存入数组
			products[0] = new Computer();
			products[1] = new Computer();
			break;
		}
		// 返回数组products
		return products;
	}
}
package generic;
import java.lang.reflect.Array;
/**
 * 泛型工厂类GenericFactory<T>:用于演示泛型
 * 其中T是类型GenericFactory类的形参
 * 使用类型GenericFactory可以传入一个类型(类名)作为实参
 * 在类型GenericFactory的内部便可以将T作为数据类型使用
 * 例如:GenericFactory<String>这样编译后类中所有的T都会被替换为String
 * 
 * T在这里一般称作占位符,也可以是其他的任意符合标识符命名规则的符号
 * 常用的为T和E,T:type(类型)首字母;E:element(元素)首字母
 * 
 * 如果需要使用多个泛型,占位符中间使用英文格式的逗号隔开
 * 例如:GenericFactory<T,E>
 * 使用时也是按照位置顺序对应传入
 * 例如:GenericFactory<String,Integer>
 * 其类中所有的T都会被替换成String,所有的E都会被替换成Integer
 * 
 * @author 学霸联盟 - 赵灿
 */
public class GenericFactory<T> {
	/**
	 * 声明一个返回值类型为T[](T类型的数组),参数为Class类型对象的方法
	 * 该方法用于获取工厂的产品
	 */
	public T[] getProduct(Class<T> cls){
		//创建一个长度为2,T类型的数组t;初学的同学知道以下代码的作用即可
		T[] t = (T[]) Array.newInstance(cls, 2);
		try {
			//创建类型T的对象;等价于 t = new T();
			t[0] = cls.newInstance();
			t[1] = cls.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		//返回对象t
		return t;
	}
}
package generic;
/**
 * 泛型测试类GenericTest
 * 用于测试和对比两种工厂的使用
 * @author 学霸联盟 - 赵灿
 */
public class GenericTest {
	public static void main(String[] args) {
		//创建普通工厂对象f
		Factory f = new Factory();
		//通过工厂f的getProduct方法获取的产品数组是Object类型的数组
//所以这个数组中可能存储着多种产品
		Object[] products = f.getProduct(Product.手机);
		//当从数组中取出产品时是Object类型的,需要强制类型转换
		Phone fp = (Phone)products[0];
		//使用手机对象fp调用拨打电话的方法call
		fp.call();
		/*
		 * 我们知道此时下标为1处的产品是电脑
		 * 如果使用者不知道产品数组中存储的是什么类型的产品时,依然将其强制转换成手机类型
		 * Phone fp = (Phone)products[1];这时就会出现类型转换异常
		 */
		Computer fc = (Computer)products[1];
		fc.coding();
		System.out.println("--------------");

		/*
		 * 创建泛型工厂对象phoneFactory,泛型工厂的参数T位置传入Phone
		 * 那么工厂phoneFactory变只能生产手机,不能再生产电脑
		 * 如果想要生产电脑则需要,另外创建生产电脑的工厂
		 */
		GenericFactory<Phone> phoneFactory = new GenericFactory<Phone>();
		//通过泛型工厂phoneFactory生产手机,参数只能传入Phone.class
		Phone[] phone = phoneFactory.getProduct(Phone.class);
		phone[0].call();
		//创建电脑工厂,只能生产电脑
		GenericFactory<Computer> computerFactory = new GenericFactory<Computer>();
		Computer[] computer = computerFactory.getProduct(Computer.class);
		computer[0].coding();
	}
}
运行结果:
拨打电话
编写代码
--------------
拨打电话
编写代码

小结:

使用父类型数组存储子类对象
优点:可以存储任何一种子类型
缺点:从数组中获取对象,并调用子类中特有方法时,需要强制类型转换
 存在类型转换异常的风险
使用泛型数组
优点:获取对象无限强制类型转换,也就不存在类型转换异常的风险
 类型的扩展性好
缺点:创建泛型相关的实例麻烦
使用时,泛型一旦传入参数,类型就固定了,导致类型单一(例如,上面的两个泛型工厂,可以看出两个不同的类型)

泛型相当于给类型加上一个参数,类似带参数的方法,方法的形参是声明某种数据类型的变量,使用小括号将参数括起来,传入的实参是某种数据类型的值或对象,在方法内便可以使用参数变量;而类型的形参只是一个占位符,使用尖括号括起来,传入的实参为类型(类名),在类的内部便可以将占位符作为数据类型使用;这就是泛型。
泛型应用最多的是集合。

时间: 2024-08-02 09:55:46

I学霸官方免费教程三十:Java基础教程之泛型的相关文章

I学霸官方免费教程一:Java软件开发预备知识

一.     计算机系统简介 1.硬件系统:看得见,摸得着 主机:主机箱.主板.内存.硬盘.CPU(中央处理器).声卡.显卡.网卡 外设:显示器.音响 输入设备:键盘.鼠标.扫描仪 输出设备:显示器.投影仪.音响 2.软件系统 系统软件:windows.Linux.IOS.Unix.Android: 编译软件:编程语言,编译器,解释器 应用软件:除了以上的全是应用软件,比如聊天软件,网站,游戏软件等等 二.     软件简介 软件:按照特定顺序组织的计算机数据和指令的集合:其中指令是指挥计算机如

I学霸官方免费教程三十二:Java集合框架之Set集合

Set接口 Set集合是无序的.元素不可重复的结合常用集合类有HashSet和TreeSet HashSet类常用的两种List集合各有各的优点,那么有没有同时具备这两种List集合的优点的集合呢?答案是肯定的,就是Set集合. 实例: package collection.set.hashSet; import java.util.HashSet; import java.util.Iterator; /**  * 演示HashSet  * @author 学霸联盟 - 赵灿  */ publ

I学霸官方免费教程三十一:Java集合框架之List集合

集合框架 在数组的使用过程中可以看到,想要向数组中插入元素和删除元素非常麻烦,而且数组的长度是无法改变的.java为我们提供了批量存储数据更加方便的容器,就是集合.集合和数组的作用一样,都是为了使用一个变量来存储一批数据的:但集合使用起来更加方便,而且集合的长度是可以变化的. List接口 List集合可以存储有序的,可重复的数据:常用的子类是ArrayList和LinkedList两个类 ArrayList类 这是一个底层由数组实现的集合类,是对数组进行了封装. 实例: package col

Java基础教程:JDBC编程

Java基础教程:JDBC编程 快速开始 什么是JDBC JDBC 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库. JDBC API 库包含下面提到的每个任务,都是与数据库相关的常用用法. 制作到数据库的连接. 创建 SQL 或 MySQL 语句. 执行 SQL 或 MySQL 查询数据库. 查看和修改所产生的记录. 从根本上来说,JDBC 是一种规范,它提供了一套完整的接口,允许便携式访问到底层数据库,因此可以用 J

Java基础教程(25)--I/O流

??I/O流表示输入源或输出目标.流可以表示许多不同类型的源和目标,例如磁盘文件.设备.其他程序等. ??流支持许多不同类型的数据,包括字节.原始数据类型.字符和对象等.有些流只传递数据; 有些流则可以操纵和转换数据. ??无论各种流的内部是如何工作的,所有流都提供相同的简单模型:流是一系列数据.程序使用输入流从源头获取数据,一次一项: ??程序使用输出流将数据写入目的地,一次一项: ??在本文中,我们会看到流可以处理各种各样的数据,无论是基本数据还是复杂对象.先来几张IO流的全家福: ??In

Java Web 学习笔记 第三章 java基础(二)

第三章 java基础(二) 一.转义符 转义字符是"\",通过转义字符,可表示一些特殊的字符. 例如: '\n'  表示回车 '\t'   表示 制表符字符,一个制表符表示向右跳8-10个字符 '\\'   表示\ '\''   表示单引号 '\"'  表示双引号 "\u4e2d"表示unicode编码对应的字符(汉字:中). 二.布尔类型的概念和用法 boolean 类型用来表示肯定或否定两种可能. boolean 常用在分支语句.循环语句中. true

Java基础教程:面向对象编程

Java基础教程:面向对象编程 Java语言概述 Java语言特点 1.Java为纯面向对象的语言,它能够直接反映现实生活中的对象.总之,Everything is object! 2.平台无关性.Java为解释型语言,编译器会把Java代码变成"""中间代码",然后在JVM上解释执行. 3.Java提供了很多内置的类库,这些类库简化了开发人员的程序设计工作,同时缩短了项目开发时间. 4.Java语言提供了对Web应用的支持. 5.Java语言提供了较好的安全性和健

Java基础教程:面向对象编程[2]

Java基础教程:面向对象编程[2] 三大特性 封装 封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装.隐藏起来的方法.封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问. 使用封装我们可以对成员变量进行更精确的控制,同时隐藏信息,实现细节等. 方法: public class Person{ private String name; private int age; ? public int getAge(){ return age;

Java基础教程 - 组合

1. 什么是组合? 如果一个类的对象和另一个类满足"has-a"关系的话,我们就可以在一个类中,把另一个类的对象作为其对象成员. 什么是"has-a"关系,举个例子:现在有一个类LapTop.class,还有一个是Moniter.class.好显然,Laptop "has-a" Moniter,也就是说,他们是满足"has-a"关系的.这时候,我们就可以把Moniter作为Laptop的一个数据成员. class Laptop

三、Java基础知识要点合集

1.数据类型 Java的数据类型分为基本数据类型和引用数据类型. a, 基本数据类型包括:byte, boolean, char, short, int, long, float, double; b, 每个基本数据类型都有相应的引用类型,比如int  ->  Integer,char -> character. c, 查询不同类型数据的范围,方法之一是可以用基本类型对应的引用类型.比如,"int i = Integer.Size; "(i表示int型数据所占的位(bit)