java泛型介绍
一、泛型初衷
Java集合不会知道我们需要用它来保存什么类型的对象,所以他们把集合设计成能保存任何类型的对象,只要就具有很好的通用性。但这样做也带来两个问题:
二、在集合中使用泛型
在集合中使用泛型后带来如下优势
–程序再也不能“不小心”把其他对象“丢进”strList集合中;
- import java.util.*;
- public class ListErr
- {
- public static void main(String[] args)
- {
- // 创建一个只想保存字符串的List集合
- List strList = new ArrayList();
- strList.add("疯狂Java讲义");
- strList.add("疯狂Android讲义");
- // "不小心"把一个Integer对象"丢进"了集合
- strList.add(5); // ①
- strList.forEach(str -> System.out.println(((String)str).length())); // ②
- }
- }
- ①"不小心"把一个Integer对象"丢进"了集合
- ②引发ClassCastException异常。
三、什么是泛型
所谓泛型:就是允许在定义类、接口指定类型形参,这个类型形参在将在声明变量、创建对象时确定(即传入实际的类型参数,也可称为类型实参)。
四、泛型的“菱形”语法 <>
如下代码:
- List<String> books = new ArrayList<String>();
- Map<String,Integer> books = new ArrayList<String,Integer>();
在java 7 以前,<>中的粗体字代码都是必须的,但是现在可以不带粗体字代码。Java自动推断出ArrayList的<>里应该是String还是String,Integer。
现在改为:
- List<String> books = new ArrayList<>();
- Map<String,Integer> books = new ArrayList<>();
第一段和第二段代码是完全等价的。
泛型的简单应用:
- import java.util.*;
- public class DiamondTest
- {
- public static void main(String[] args)
- {
- // Java自动推断出ArrayList的<>里应该是String
- List<String> books = new ArrayList<>();
- books.add("疯狂Java讲义");
- books.add("疯狂Android讲义");
- // 遍历books集合,集合元素就是String类型
- books.forEach(ele -> System.out.println(ele.length()));
- // Java自动推断出HashMap的<>里应该是String , List<String>
- Map<String , List<String>> schoolsInfo = new HashMap<>();
- // Java自动推断出ArrayList的<>里应该是String
- List<String> schools = new ArrayList<>();
- schools.add("斜月三星洞");
- schools.add("西天取经路");
- schoolsInfo.put("孙悟空" , schools);
- // 遍历Map时,Map的key是String类型,value是List<String>类型
- schoolsInfo.forEach((key , value) -> System.out.println(key + "-->" + value));
- }
- }
五、深入泛型
1.定义泛型接口、类
定义Apple类时使用了泛型声明
- // 定义Apple类时使用了泛型声明
- public class Apple<T>
- {
- // 使用T类型形参定义实例变量
- private T info;
- public Apple(){}
- // 下面方法中使用T类型形参来定义构造器
- public Apple(T info)
- {
- this.info = info;
- }
- public void setInfo(T info)
- {
- this.info = info;
- }
- public T getInfo()
- {
- return this.info;
- }
- public static void main(String[] args)
- {
- // 由于传给T形参的是String,所以构造器参数只能是String
- Apple<String> a1 = new Apple<>("苹果");
- System.out.println(a1.getInfo());
- // 由于传给T形参的是Double,所以构造器参数只能是Double或double
- Apple<Double> a2 = new Apple<>(5.67);
- System.out.println(a2.getInfo());
- }
- }
2.从泛型派生子类
A1继承泛型类:
- //使用泛型类时,为T形参传入String类类型
- public class A1 extends Apple<String>{}//正确
- //使用泛型类时,没有为T形参传入实际类型参数,这会产生警告:泛型检查警告,使用了未经检查或不安全的操作
- public class A1 extends Apple{}//正确
- //apple类不能跟类型形参
- public class A1 extends Apple<T>{}//错误
继承Apple类,T被String代替。子类会继承到String getInfo()和void setInfo()两个方法。
- public class A1 extends Apple<String>
- {
- // 正确重写了父类的方法,返回值
- // 与父类Apple<String>的返回值完全相同
- public String getInfo()
- {
- return "子类" + super.getInfo();
- }
- /*
- // 下面方法是错误的,重写父类方法时返回值类型不一致。从父类继承的应该是public String getinfo()
- public Object getInfo()
- {
- return "子类";
- }
- */
- }
正确写法如下:
- public class A2 extends Apple
- {
- // 重写父类的方法
- public String getInfo()
- {
- // super.getInfo()方法返回值是Object类型,
- // 所以加toString()才返回String类型
- return super.getInfo().toString();
- }
- }
3.并不存在泛型类
六、类型通配符
- public void test(List<Object> c)
- {
- for(int i=0;i<c.size();i++)
{
Syso(c.get(i));
}- }
这段代码看上去没有任何问题,方法的声明也没有任何问题。但是问题在于:调用该方法传入的实际参数的值。例如:
- //创建一个List<String>对象
- List<String> strList = new ArrayList<>();
//将strList作为参数调用test
test(strList);
编译上面的程序,发生错误。
- 无法将Test中的test(java.util.list<java.lang.Object>)应用于java.util.list<java.lang.String>
这说明List<String>对象不能被当成List<Object>对象使用,也就是说:List<String>类并不是List<Object>类的子类。
此外,数组和泛型有所不同:假设Foo是Bar的一个子类型(子类或者子接口),那么Foo[]依然是Bar[]的自类型;但G<Foo>不是G<Bar>的子类型。
七、?的用法
为了表示各种泛型List的父类,我们需要使用类型通配符,类型通配符是一个问号(?),将一个问号作为类型实参传给List集合,写作:List<?>(意思是未知类型元素的List)。这个问号(?)被称为通配符,它的元素类型可以匹配任何类型。
在“六”中的程序,将
- public void test(List<Object> c)
- {
- for(int i=0;i<c.size();i++)
- {
- Syso(c.get(i));
- }
- }
改为:
- public void test(List<?> c)
- {
- for(int i=0;i<c.size();i++)
- {
- Syso(c.get(i));
- }
- }
再次编译就没有了错误。
这里的?可谓什么都可以表示,是不是给它的权力太大了!! 当然我们有自己的解决办法:设定类型通配符的上限
我们需要一种泛型表示方法,它可以表示所有Shape泛型List的父类,为了满足这种需求,Java泛型提供了被限制的泛型通配符。被限制的泛型通配符的如下表示:List<?
extends Shape>
- // 定义一个抽象类Shape
- public abstract class Shape
- {
- public abstract void draw(Canvas c);
- }
- / 定义Shape的子类Circle
- public class Circle extends Shape
- {
- // 实现画图方法,以打印字符串来模拟画图方法实现
- public void draw(Canvas c)
- {
- System.out.println("在画布" + c + "上画一个圆");
- }
- }
- // 定义Shape的子类Rectangle
- public class Rectangle extends Shape
- {
- // 实现画图方法,以打印字符串来模拟画图方法实现
- public void draw(Canvas c)
- {
- System.out.println("把一个矩形画在画布" + c + "上");
- }
- }
上面定义了三个形状类,Sharp抽象父类,Circle类和Rectangle类继承了抽象类Sharp。
下面定义一个Canvas类,该画布类不同的形状。
- import java.util.*;
- public class Canvas
- {
- // 同时在画布上绘制多个形状
- public void drawAll(List< Shape> shapes)
- {
- for (Shape s : shapes)
- {
- s.draw(this);
- }
- }
- public static void main(String[] args)
- {
- List<Circle> circleList = new ArrayList<Circle>();
- Canvas c = new Canvas();
- // 由于List<Circle>并不是List<Shape>的子类型,
- // 所以下面代码引发编译错误
- c.drawAll(circleList);
- }
- }
修改如下:
- import java.util.*;
- public class Canvas
- {
- // 同时在画布上绘制多个形状,使用被限制的泛型通配符
- public void drawAll(List<? extends Shape> shapes)
- {
- for (Shape s : shapes)
- {
- s.draw(this);
- }
- }
- public static void main(String[] args)
- {
- List<Circle> circleList = new ArrayList<Circle>();
- Canvas c = new Canvas();
- // 由于List<Circle>并不是List<Shape>的子类型,但是使用了通配符
- // 所以下面代码正确
- c.drawAll(circleList);
- }
- }
这段代码就没有了错误。
- public class Apple<T extends Number>
- {
- T col;
- public static void main(String[] args)
- {
- Apple<Integer> ai = new Apple<>();
- Apple<Double> ad = new Apple<>();
- // 下面代码将引起编译异常,下面代码试图把String类型传给T形参
- // 但String不是Number的子类型,所以引发编译错误
- Apple<String> as = new Apple<>(); // ①
- }
- }
八、泛型方法
如果定义类、接口是没有使用类型形参,但定义方法时想自己定义类型形参,这也是可以的,JDK1.5还提供了泛型方法的支持。
九、泛型方法与类型通配符的区别
TreeSet(Comparator<? super E> c)
……待续
java泛型介绍的更多相关文章
- Java泛型介绍!!!
Java总结篇系列:Java泛型 转自:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下 ...
- Java 泛型 介绍
为什么需要泛型? public class GenericTest { public static void main(String[] args) { List list = new ArrayLi ...
- Java泛型介绍——HashMap总结
今天在编程中,需要使用到Hashmap来存储和传递数据,发现自己学习Java这么久,实际上对泛型依旧知之甚少,搜索整理了一下HashMap的使用. HashMap的声明初始化,因为泛型的原因,起两个参 ...
- java泛型探索——介绍篇
1. 泛型出现前后代码对比 先来看看泛型出现前,代码是这么写的: List words = new ArrayList(); words.add("Hello "); words. ...
- java泛型(一)、泛型的基本介绍和使用
现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用.泛型在java中,是一个十分重要的特性,所以要好好的研究下. 泛 型的定义:泛型是JDK 1.5的一 ...
- Java泛型一:基本介绍和使用
原文地址http://blog.csdn.net/lonelyroamer/article/details/7864531 现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就 ...
- java泛型 7 泛型的基本介绍和使用
现在开始深入学习Java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用.泛型在java中,是一个十分重要的特性,所以要好好的研究下. 一.泛型的基本概念 泛型的定义:泛型是 ...
- Java泛型的历史
为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...
- java泛型基础
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法. Ja ...
随机推荐
- POJ2828 Buy Tickets [树状数组,二分答案]
题目传送门 Buy Tickets Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 22611 Accepted: 110 ...
- 最正确的React事件绑定方式
参考这篇文章:Choosing the Best Approach for React Event Handlers 1.function.bind()方式 2.inline arrow functi ...
- hibernate对象关系映射的配置
一对一主键关联单双向 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-m ...
- Python安装scrapy提示 error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools&quo ...
- sed 插入和替换
sed -i '/参考行/i\插入内容' *.ksh sed -i 's,原内容,替换后内容,g' *.ksh
- 通过myEclipse创建hibernate的实体类
今天有个新项目中需要使用到hibernate,刚好数据库表已经创建完毕,就顺便来总结一下通过myEclipse创建hibernate的实体类. 1..在myEclipse中选择MyEclipse Da ...
- 【BZOJ 1053】 1053: [HAOI2007]反素数ant (反素数)
1053: [HAOI2007]反素数ant Description 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4.如果某个正整数x满足:g(x)>g(i) 0&l ...
- windows上同时安装两个版本的mysql数据库
一.先停止之前安装的低版本mysql服务 二.将其他电脑上安装好的mysql拷贝过来 三.拷贝过来之后,进入该文件夹,删除掉data目录,然后打开my.ini,进行修改端口号,端口号改为3307,ba ...
- CodeForces - 1000D Yet Another Problem On a Subsequence
题面在这里! 好智障的一个dp啊,一段开头的数字相当于下面要跟多少个数,直接滚动数组dp就行了... #include<bits/stdc++.h> #define ll long lon ...
- Call to undefined function imageftbbox()
mac自带的php的验证码出现问题,搜索了一下Call to undefined function imageftbbox(),然后根据这个网站https://php-osx.liip.ch/本剧本机 ...