Java核心 --- 泛型
CoreJava 泛型
java泛型的出现避免了强制类型转换,便于代码更好的被阅读
本文的写作参照了张孝祥的泛型介绍:http://www.itcast.cn/news/dbfd20f1/f4b1/412d/9b40/c1a81b8bf1da.shtml
更多疑问请参考:http://www.vaikan.com/java-generics-quick-tutorial/
1.可以接收类型参数的类型在接受类型参数后变为泛型,但是,虽然是不同的泛型但是还是相同的类型
package com.yuki.generic;
import java.util.Vector;
/**
* 同一个类型的不同的泛型
* Vector<Integer>和Vector<Boolean>是同一个类型的不同泛型
*
* @author yuki
*
*/
public class Demo1 {
public static void main(String[] args) {
Vector<Integer> vi = new Vector<>();
Vector<Boolean> vb = new Vector<>();
vi.add(1);
vb.add(true);
boolean same = vi.getClass() == vb.getClass();
System.out.println("same = " + same);
}
}
执行结果如下:
same = true
2.可以通过反射跳过泛型的类型参数的限制
package com.yuki.generic;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* 反射调用泛型方法
*
* ArrayList<E>中的E表示的是一个类型参数或类型变量
* ArraList<Integer>称为已参数化的类型
* ArraList<Integer>中的Integer称为类型参数的实例或实际类型参数
* ArraList<Integer> 读作 ArraList type of Integer
* ArrayList 称为原始类型
*
* @author yuki
*
*/
public class Demo2 {
public static void main(String[] args) throws Exception {
// List<Integer> l = new ArrayList<Integer>();
// 下面的写法也是可以的
List<Integer> l = new ArrayList<>();
// 规定存放整数对象的序列不能存放字符串
// list.add("i am string"); // error!
Method m = l.getClass().getMethod("add", Object.class);
m.invoke(l, "abc");
System.out.println("l.get(0) = " + l.get(0));
// 不能创建参数化类型的数组,Cannot create a generic array
// List<Object>[] l2 = new ArrayList<Object>[10]; // error!
}
}
执行结果如下:
l.get(0) = abc
3.问号?可以作为泛型的通配符,发可以匹配任意类型, 但是形参上的参数引用失去了泛型的信息
package com.yuki.generic;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class Demo3 {
public static void main(String[] args) {
List<Integer> l = new ArrayList<>();
l.add(1);
l.add(2);
printCollection(l);
}
// --- 没有使用泛型 ---
// public static void printCollection(Collection collection){
// --- 泛型类型必须为Collection<Object>,不能传递类似Collection<Integer>的参数 ---
// public static void printCollection(Collection<Object> collection){
// ? 是通配符,表示可以接受任意类型
public static void printCollection(Collection<?> c){
// 不能调用与类型有关的方法
// c.add(1); // error!
final int SIZE = c.size();
int i = 0;
for(Object o : c){
System.out.println("c : " + i++ + " in " + SIZE + " -> " + o);
}
}
}
运行结果如下:
c : 0 in 2 -> 1 c : 1 in 2 -> 2
4.静态函数Class.forName返回的参数类型是Class<?>,应为传入的类名只是它的参数
package com.yuki.generic;
public class Demo4 {
public static void main(String[] args) throws Exception {
// 它返回的是Class<?>
// Class<Number> y = Class.forName("java.lang.String");
Class<?> y = Class.forName("java.lang.String");
System.out.println("y = " + y);
}
}
运行结果如下:
y = class java.lang.String
5.泛型方法的定义,它接受的参数和它的返回值会搜索继承树上最近的一个分支点
比如说,猫和狗它们的最小父类是犬科动物,而不是脊椎动物
package com.yuki.generic;
public class Demo5 {
@SuppressWarnings("unused")
public static void main(String[] args) {
Integer i = add(3, 5);
// Float n = add(3.5, 5); // error!
// Float 和 Integer 的父类是 Number
Number n = add(3.5, 5);
Object o = add(3, "abc");
}
// 在返回方法前,获取方法的类型参数
private static <T> T add(T x, T y){
System.out.println("wake up : x = " + x + ", y = " + y);
return null;
}
}
运行结果如下:
wake up : x = 3, y = 5 wake up : x = 3.5, y = 5 wake up : x = 3, y = abc
6.定义一个一个泛型的方法,int[]已经是引用类型而不是基本类型,所以不能自动封箱
package com.yuki.generic;
public class Demo6 {
public static void main(String[] args) {
String[] a = swap(new String[]{"abc", "xyz", "uvw"}, 1, 2);
StringBuilder sb = new StringBuilder();
for(String s : a){
sb.append(s + ',');
}
System.out.println(sb);
// 泛型必须是引用类型,不能使基本类型
// int[] 已经是对象了,所以不能自动封箱
// swap(new int[]{1, 2, 3, 4, 5}, 3, 4); // error!
}
/**
* 定义泛型是可以限定类型
* 限定它必须实现某接口或实现某类,用and连接
* <T extends Serializable & Cloneable>
*
* 可以抛出泛型的异常
* <T extends Exception> void methodName() throws T
*
* 声明多个泛型之间用,分割
*/
private static <T> T[] swap(T[] a, int i, int j){
T temp = a[i];
a[i] = a[j];
a[j] = temp;
return a;
}
}
运行结果如下:
abc,uvw,xyz,
7.自动类型转换的泛型方法,虽然可以不必这么麻烦的。。。
package com.yuki.generic;
public class Demo7 {
public static void main(String[] args) {
Object o = "abc";
String s = autoConvert(o);
System.out.println("s = " + s);
}
@SuppressWarnings("unchecked")
private static <T> T autoConvert(Object o){
return (T)o;
}
}
运行结果如下:
s = abc
8.当参数中有两个相同的泛型类型引用时,这里, 第一个匹配的参数类型确定方法的泛型类型
package com.yuki.generic;
import java.util.Collection;
import java.util.Date;
import java.util.Vector;
public class Demo8 {
public static void main(String[] args) {
// 正确
copy1(new Vector<String>(), new String[10]);
// Date和String取共同的最小父类
copy2(new Date[10], new String[20]);
// String不是Date的子类
// copy1(new Vector<Date>(), new String[10]); // error!
}
//
private static <T> void copy1(Collection<T> c, T[] a){
}
private static <T> void copy2(T[] c, T[] a){
}
}
9.定义泛型类,类的实例方法可以使用运行实例化的泛型类,但是,静态方法与类的实例,所以需要定义为泛型方法
程序的入口:Demo9
package com.yuki.generic;
public class Demo9 {
public static void main(String[] args) {
GenericSample<String> gs = new GenericSample<>();
// 参数类型不匹配
// gs.add(3); // error!
gs.add("hello, generic");
String s = gs.look();
System.out.println("s = " + s);
}
}
使用到的类:GenericSample
package com.yuki.generic;
// 类级别的泛型
public class GenericSample<E> {
private E e;
public void add(E e){
this.e = e;
}
public E look(){
return e;
}
// 静态方法不能使用类的实例才能使用的泛型
// public static void staticMethod(E e) { }
// 这里使用的是方法级别的泛型
public static <E> void staticMethod(E e) { }
}
运行结果如下:
s = hello, generic
10.怎样知道方法的泛型参数中可以容纳的泛型参数类型呢?
程序入口:Demo10
package com.yuki.generic;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
import java.util.Vector;
public class Demo10 {
public static void main(String[] args) throws Exception {
GenericParameter<Date> gp = new GenericParameter<>();
// 怎样知道集合中所装的实例类型
Class<?> clazz = gp.getClass();
Method method = clazz.getMethod("applyVector", Vector.class);
// Type是Class的子类,它的其中一个子接口是ParameterizedType
Type[] types = method.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType) types[0];
// 得到泛型的类型
Type t = pType.getRawType();
// 得到泛型参数的类型
Type[] ta = pType.getActualTypeArguments();
System.out.println("t = " + t);
System.out.println("ta[0] = " + ta[0]);
Method method2 = clazz.getMethod("applyList", List.class);
ParameterizedType pType2 = (ParameterizedType) method2.getGenericParameterTypes()[0];
System.out.println("rawType = " + pType2.getRawType());
System.out.println("actualTypeArguments[0] = " + pType2.getActualTypeArguments()[0]);
}
}
使用到的类:GenericParameter<E>
package com.yuki.generic;
import java.util.Date;
import java.util.List;
import java.util.Vector;
public class GenericParameter<E> {
public void applyVector(Vector<E> v){
// 我们不知道参数列表中参数的类型,
// 但是当把变量交给一个方法去使用时
// 可以知道方法所接受参数的实际类型
}
public void applyList(List<Date> v){
}
}
运行结果如下:
t = class java.util.Vector ta[0] = E rawType = interface java.util.List actualTypeArguments[0] = class java.util.Date
跟多好文请看:http://www.cnblogs.com/kodoyang/
Thanks!
Java核心 --- 泛型的更多相关文章
- java核心卷轴之泛型程序设计
本文根据<Java核心卷轴>第十二章总结而来,更加详细的内容请查看<Java核心卷轴> 1. 泛型类型只能是引用类型,不可以使用基本数据类型. 2. 类型变量含义 E : 集合 ...
- Java核心 --- 枚举
Java核心 --- 枚举 枚举把显示的变量与逻辑的数字绑定在一起在编译的时候,就会发现数据不合法也起到了使程序更加易读,规范代码的作用 一.用普通类的方式实现枚举 新建一个终态类Season,把构造 ...
- Java核心编程快速学习
Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体内容如下图所示. 反射reflect是理解Java语言工作原理的基础,Java编译器首先需要将我们编写的 ...
- Java基础学习笔记二十三 Java核心语法之反射
类加载器 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化. 加载就是指将class文件读入内存,并为之创建一个Class对象.任 ...
- Java核心编程快速入门
Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体内容如下图所示. 反射reflect是理解Java语言工作原理的基础,Java编译器首先需要将我们编写的 ...
- Java中泛型使用
Java中泛型使用 泛型作用: 泛型:集合类添加对象不用强转 反射机制:将泛型固定的类的所有方法和成员全部显示出来 核心代码: ArrayList<Ls> ff=new ArrayList ...
- Java核心编程快速学习(转载)
http://www.cnblogs.com/wanliwang01/p/java_core.html Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体 ...
- 2018.6.19 Java核心API与高级编程实践复习总结
Java 核心编程API与高级编程实践 第一章 异常 1.1 异常概述 在程序运行中,经常会出现一些意外情况,这些意外会导致程序出错或者崩溃而影响程序的正常执行,在java语言中,将这些程序意外称为异 ...
- 深入Java核心 Java中多态的实现机制(1)
在疯狂java中,多态是这样解释的: 多态:相同类型的变量,调用同一个方法时,呈现出多中不同的行为特征, 这就是多态. 加上下面的解释:(多态四小类:强制的,重载的,参数的和包含的) 同时, 还用人这 ...
随机推荐
- Android HTTPS(1)概念和简单示例
Security with HTTPS and SSL The Secure Sockets Layer (SSL)—now technically known as Transport Layer ...
- HDU 4652 Dice(期望)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4652 题意:一个m个面的筛子.两种询问:(1)平均抛多少次后使得最后n次的面完全一样:(2)平均抛多少 ...
- 《OD学hadoop》第四周0716
7.16 一.回顾 二.HDFS Federation(联盟) Hadoop 2.2.0发布新特性 很多的大公司都在使用:BAT HDFS Federation + HDFS HA架构 互相隔开,但是 ...
- UUID的具体用法
String deleteUuid = UUID.randomUUID().toString(); java.util 类 UUID java.lang.Object java.util.UUID 所 ...
- linux软件的安装,更新与卸载
Linux常见的安装为tar,zip,gz,rpm,deb,bin等.我们可以简单的分为三类. 第一:打包或压缩文件tar,zip,gz等,一般解压后即可,或者解压后运行sh文件: 第二:对应的有管理 ...
- Linux 总结1
============================= 一般 ========================================= chown -R oracle:oinstall ...
- JSON 之 SuperObject(7): 可以省略的双引号
在 JSON 中, 字符串应该在双引号中; 从上个例子才发现: 原来这个双引号可以省略, 有空格都行 当然只是在程序代码中可以省略, 对象会自动识别添加的. 即如此, 下面写法都可以: uses Su ...
- 读取Excel文件中的单元格的内容和颜色
怎样读取Excel文件中的单元格的内容和颜色 先创建一个Excel文件,在A1和A2中随意输入内容,设置A1的字体颜色为红色,A2的背景为黄色.需要 using Excel = Microsoft.O ...
- POJ3592 Instantaneous Transference tarjan +spfa
链接:http://poj.org/problem?id=3592 题意:题目大意:给定一个矩阵,西南角为出发点,每个单位都有一订价值的金矿(#默示岩石,不成达,*默示时佛门,可以达到指定单位),队# ...
- POJ 1976 A Mini Locomotive【DP】
题意:给出一列火车,可以由三个火车头拉,每个火车头最多拉m节车厢(这m节车厢需要保持连续),再给出n节车厢,每节车厢的人数,问最多能够载多少人到终点. 可以转化为三个长度相等的区间去覆盖n个数,使得这 ...