Java泛型学习笔记
泛型是Java5引进的新特征,是类和接口的一种拓展机制,主要实现参数化类型机制。Java的泛型,跟C++的类模板有很多相似的地方,或者说,就是C++类模板的升级版。
泛型类
在开发过程中,我们或许要设计一个“节点”类,在过去,我们需要为int型数据定义一个类,然后再为double类型数据定义一个点类,还需要为String类设计一个类,这样,我们就需要定义好多的类,但其实,这些类有很多相同的地方,他们只是数据的类型不同而已。有了泛型类之后,我们就不需要设计那么多的类了,只需要设计一个类,然后再根据存入的数据的类型决定创建什么类型的对象。比如,例1-1
class Node<T>{
private T value;
public Node() {}
public Node(T value) {
this.value = value;
}
public T getNode() {
return value;
}
public void setNode(T value) {
this.value = value;
}
}
通过泛型类,我们可以通过一行简单的代码就可以创建各种不同类型的对象。
Node<Integer> intNode = new Node<Integer>();//创建整型节点 Node<Double> douNode = new Node<Double>();//double节点 Node<String> strNode = new Node<String>();//字符串节点
怎么样,是不是很方便了?其实不仅仅方便,还比较安全,怎么个安全法呢?
在上面的代码中,我们创建了intNode对象,它是int类型的,如果我们要调用它的setNode("test"),系统就会在编译的时候给我们报错。从而在编译阶段就保证了类型的安全。
由于编译器能够从上下文推断出泛型参数的类型,所以从Java se 7开始,在创建泛型类型时可以用菱形语法。上述创建语句可以写成
Node<Integer> intNode = new Node<>(); Node<Double> douNode = new Node<>(); Node<String> strNode = new Node<>();
按照约定,类型参数名要使用单个大写字母表示,常用的类型参数名有E(表示元素)、K(便是键)、T(表示类型)、N(表示数字)、V(表示值)等。泛型可能有多个类型参数,但是在类或者接口的声明中,每个参数名必须时唯一的。
好了,现在我们已经认识了泛型类。下面,让我们来看看泛型接口。
这是Entry接口
public interface Entry<K, V>{
public K getKey();
public V getValue();
}
class Pair<K, V> implements Entry<K, V>{
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public void setKey(K key) {
this.key = key;
}
public void setValue(V value) {
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
看到这,也就基本了解Java泛型类是什么了东西了。下面,我们来看看一个例子。
class Point<T> {
T x;
T y;
public Point() {}
public Point(T x, T y) {
this.x = x;
this.y = y;
}
public T getX() {
return x;
}
public T getY() {
return y;
}
public void setX(T x) {
this.x = x;
}
public void setY(T y) {
this.y = y;
}
public void translate(T x, T y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "(" + x +", " + y + ")";
}
}
public class test11_01 {
public static void main(String[] args) {
Point<Integer> intPoint = new Point<Integer>(3, 5);
System.out.println(intPoint);
Point<Double> doublePoint = new Point<Double>(3.2, 5.5);
System.out.println(doublePoint);
Point<String> strPoint = new Point(3.2, 5.5);//这里用String作为类型来创建了一个泛型类对象,但实际上我们日常使用中的并不怎么使用非数字的坐标
System.out.println(strPoint);
}
}
这个程序没有报错,相反,还可以运行。运行结果如下:
(3, 5) (3.2, 5.5) (3.2, 5.5)
但是,如果我们在最后加上那么一句的话
System.out.println(strPoint.getX());
结果就是下面这个样子
(3, 5) (3.2, 5.5) (3.2, 5.5) Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String at demo.test11_01.main(test11_01.java:79)
也就是说,在编译的时候,没有报错,但是在运行的时候发生了错误,这就存在了安全隐患。那要怎样才能解决呢?
如果我们可以规定,类型参数只能数Number类型,那么在创建泛型类的时候传入的是String类型的时候,就会报错吧。那么,我们要怎么样规定泛型类参数呢?这就要介绍到Java中的有界类型参数了。有界类型参数分为上界,和下界。上界用extends来指定,下界用super来指定。比如上述的二维坐标类
将
class Point<T>
/*改成*/
class Point<T extends Number>
就可以在编译的时候就阻止了String类型作为参数来创建对象。
我们再来看一个例子。假如有以下代码:
List<Object> list1 = new ArrayList<Object>(); List<String> list2 = new ArrayList<String>();
在这个例子中,尽管String类是Object的一个字类,但是,List<Object> 和List<Object>却没有一点关系,如果调用下面的方法的话,会发生编译错误
public static void printList(List<Object> list) {
for(Object element : list)
System.out.println(element);
}
这时候,我们就需要用到通配符(?)将上诉代码改写成
public static void printList(List<?> list) {
for(Object element : list)
System.out.println(element);
}
再调用这个静态方法的时候,就不会报错了。使用通配符,表示该方法可以接受的元素是任何类型的List对象。
一般来说,类和方法总是关系紧密的,既然类有泛型类,那么泛型方法,也是存在的。
泛型方法
泛型方法,就是带有类型参数的方法,类的成员和构造方法都可以定义为泛型方法。泛型方法的定义可以是静态的,也可以是非静态的。
比如:
public static <T> void swap(T[] arrary, int i, int j) {
T temp = arrary[i];
arrary[i] = arrary[j];
arrary[j] = temp;
}
Java泛型学习笔记的更多相关文章
- Java泛型学习笔记 - (七)浅析泛型中通配符的使用
一.基本概念:在学习Java泛型的过程中, 通配符是较难理解的一部分. 主要有以下三类:1. 无边界的通配符(Unbounded Wildcards), 就是<?>, 比如List< ...
- Java泛型学习笔记--Java泛型和C#泛型比较学习(一)
总结Java的泛型前,先简单的介绍下C#的泛型,通过对比,比较学习Java泛型的目的和设计意图.C#泛型是C#语言2.0和通用语言运行时(CLR)同时支持的一个特性(这一点是导致C#泛型和Java泛型 ...
- Java泛型学习笔记 - (六)泛型的继承
在学习继承的时候, 我们已经知道可以将一个子类的对象赋值给其父类的对象, 也就是父类引用指向子类对象, 如: Object obj = new Integer(10); 这其实就是面向对象编程中的is ...
- Java泛型学习笔记 - (三)泛型方法
泛型方法其实和泛型类差不多, 就是把泛型定义在方法上, 格式大概就是: public <类型参数> 返回类型 方法名(泛型类型 变量名) {...}泛型方法又分为动态方法和静态方法,:1. ...
- Java泛型学习笔记 - (二)泛型类
1. 我们先写一个没有泛型的类Box: public class Box { private Object obj; public Box() {} public Object getObj() { ...
- 【09-03】java泛型学习笔记
静态方法的泛型 /** * @description 静态方法的泛型无法使用类定义的泛型,因为类在实例化时才确定具体的泛型类,因此静态方法要使用泛型需要使用泛型方法的方式 */ public clas ...
- Java泛型学习笔记 - (五)泛型接口
所谓泛型接口, 类似于泛型类, 就是将泛型定义在接口上, 其格式如下: public interface 接口名<类型参数>如: interface Inter<T> { pu ...
- Java泛型学习笔记 - (四)有界类型参数
1. 当我们希望对泛型的类型参数的类型进行限制的时候(好拗口), 我们就应该使用有界类型参数(Bounded Type Parameters). 有界类型参数使用extends关键字后面接上边界类型来 ...
- Java泛型学习笔记 - (一)泛型的介绍
一.什么是泛型:泛型的作用是用来规定一个类, 接口或方法所能接受的数据的类型. 就像在声明方法时指定参数一样, 我们在声明一个类, 接口或方法时, 也可以指定其"类型参数", 也就 ...
随机推荐
- C#自带缓存方案
/// <summary> /// 获取数据缓存 /// </summary> /// <param name="CacheKey">键< ...
- ADO 缓存更新
if (ADOQuery1->UpdateStatus() == usUnmodified) return; ADOQuery1->UpdateBatch(arAll); Update ...
- warning LNK4099: PDB 'vc100.pdb' was not found... 解决方案
使用VS2010在编译得代码工程的时候,原本在debug下是没有问题,但是在release下编译始终会报: “warning LNK4099: PDB 'vc100.pdb' was not foun ...
- 通过nginx + lua来统计nginx上的监控网络请求和性能
介绍 以前我们为nginx做统计,都是通过对日志的分析来完成.比较麻烦,现在基于ngx_lua插件,开发了实时统计站点状态的脚本,解放生产力. 项目主页: https://github.com/sky ...
- OpenCV学习笔记 - Video Analysis - 录制视频
录制视频 使用自带摄像头录制一段5s的短视频 error & solution fourcc1 = cv2.CV_FOURCC(', 'v') 在实践过程中,运行这一行时报错: 原因分析 在o ...
- centos 使用windows7 存储
1. 在Windows7上创建一个带密码的用户,如disk 2. 创建一个文件夹,如 D:\centos-disk2 3. 选中此文件夹,点击上方的 共享 -> 特定用户, 添加disk用户, ...
- 【HDU5992】Finding Hotels 【KD树】
题意 给出n个酒店的坐标和价格,然后m个查询,每个查询给出一个人的坐标和能承受的最大价格,然后找出在他价格承受范围以内,距离他最近的宾馆,如果有多个,那么输出第一个 分析 kd树的模板题 #inclu ...
- js 滚动条滚动到底部触发事件
一.前言 在开发项目时,常常需要展示大量数据.如果全部显示出来,数据相对少时,看不出来什么不同,如果数据很多时,一次请求全部显示,这就相当可怕了. 面对这种问题,PC里使用了分页效果,将数据分成一页页 ...
- IDEA07 快捷键统计插件之Key Promoter X
1 官方介绍 该插件会统计你鼠标操作的次数,然后在一个窗口中展示出来 https://plugins.jetbrains.com/plugin/9792-key-promoter-x 2 下载.安装. ...
- 使用Log4J监控系统日志邮件警报
使用Log4J监控系统日志邮件警报 前言 在系统上线后,有时候遇到系统故障,这时候就可以登录服务器查看系统日志来排查问题.但是需要登录服务器,下载查找相关异常日志比较麻烦.而且没有监控的话,也无法实时 ...