泛型
一、泛型技术的由来
泛型是从JDK 1.5开始出现的一种安全机制。之前的版本会有安全隐患出现,数据类型的问题,导致程序发生类型转换异常。所以,JDK 1.5开发出了泛型技术,解决程序中的安全问题。
二、泛型如何解决安全问题
泛型的出现,可以强制集合存储指定的数据类型,其它类型不允许存储。如果指定集合只能存储String,其他类型是存不进来的。
书写格式:通用格式 集合类<数据类型> 变量 = new 集合类<数据类型>();
- 强制集合存储指定的数据类型,如果数据类型不符号要求,编译失败
- 写泛型的时候,前后的类型一致
- JDK7新特性,泛型前后自动匹配,后面的可以不写 , 空菱形语法
三、泛型的好处
- 保证安全:将问题,由运行时期,提前到了编译时期
- 简化书写,代码量减少
- 使用泛型,避免了类型的强制转换
ArrayList<E>
源代码,E
就是一个变量而已,在这个类的方法中,写了E
,同一个变量。传递什么值,E
就就是什么值,有点类似于C/C++的模板一样。
ArrayList<String> array =new ArrayList<String>();
//源代码中的E,就全部变成了,String
迭代器接口 Iterator<E>
方法next()
返回值也是E
,如果迭代器中指定泛型是String
类型,Iterator<String>.next()
方法返回值,跟着变成了String类型
以后,如果你需要用一个类,发现类的右边写了一个尖括号<>写泛型了,指定具体的数据类型。当然,存储基本数据类型时,泛型需要写包装类。
基本数据类型 | 包装类 |
---|---|
byte | Byte |
boolean | Boolean |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
四、泛型使用的demo
/*
* 集合存储自定义对象,带泛型,迭代器获取
* Person在之前的demo里面写过
*/
import java.util.*;
import cn.itcast.collection.Person;
public class GenericDemo1 {
public static void main(String[] args) {
//ArrayList存储Person
ArrayList<Person> array = new ArrayList<Person>();
array.add(new Person("a",10));
array.add(new Person("b",11));
array.add(new Person("c",12));
//迭代器迭代集合,集合的泛型怎么写,迭代器跟随集合的泛型
Iterator<Person> it = array.iterator();
while(it.hasNext()){
//it.next()返回值,就是泛型指定的Person,不用强转了
Person p = it.next();
System.out.println(p.getName()+"..."+p.getAge());
}
}
}
五、泛型类/方法/接口
1. 泛型类和方法
- 泛型类:将泛型,定义在类上,如果类中的任何位置出现了个泛型,和类上的泛型是相同的。工厂类案例 E==定义了一个变量
- 泛型方法:跟随类的泛型走的。定义泛型不跟着类的走的.在方法的声明上,在返回值类型之前,定义泛型,这个泛型属于方法自己,不属于类上的泛型
- 静态泛型方法:不可以和类上的泛型相同,如果相同,出现静态不能访问非静态,自定义一个泛型,这个泛型只属于这个静态方法。静态方法的泛型,写在返回值类型前
import java.util.ArrayList;
/*
* 自定义泛型类,和泛型方法
*/
class Generic<QQ>{
//使用类泛型
public void show(QQ q){
System.out.println(q);
}
//函数自定义泛型<>泛型修饰符在返回类型之前
public <TT> void function(TT t){
System.out.println(t);
}
//内部静态方法,静态不能调用非静态
public static <HAHA> void method(HAHA h){
System.out.println(h);
}
}
public class GenericDemo3 {
public static void main(String[] args) {
Generic<Integer> g = new Generic<Integer>();
//show方法的参数,跟随泛型走,现在的参数类型是Integer类型
g.show(100);
//调用方法function,泛型可以任意传递
g.function('a');
//静态方法,类名调用,使用方法自定义泛型,不跟随类 ,也不允许跟随类
Generic.method("随便传");
}
}
2. 泛型接口
接口上定义泛型:
- 实现类实现接口不指定泛型
- 实现类实现接口的同时,就实现了泛型
demo:
/*
* 自定义泛型接口,实现类实现接口,不指定泛型
* 实现类实现接口的同时直接指定泛型
*/
interface Face<T>{
public abstract void show(T t);
}
//定义实现类,实现接口,同时实现泛型
class FaceImpl2 implements Face<String>{
public void show(String s ){
System.out.println(s);
}
}
//定义实现类,实现接口,不理会泛型,等待对象指定具体的数据类型
class FaceImpl<T> implements Face<T>{
public void show(T t){
System.out.println(t);
}
}
public class GenericDemo4 {
public static void main(String[] args) {
FaceImpl<String> face = new FaceImpl<String>();
FaceImpl<Integer> face1 = new FaceImpl<Integer>();
face.show("随便传");
FaceImpl2 face2 = new FaceImpl2();
face2.show("只能是字符串");
}
}
六、泛型的统配和限定
1. 泛型的通配符
传统文件系统中,通配符 * 匹配任意的文件名,或者是后缀名 del . del *.java 等等。 假设定义方法,做集合的遍历,但是要求的是遍历任意的一个Collection下的子类集合,此时就要使用通配符。泛型中,通配符号?问号,匹配所有的泛型类型,好处方便遍历集合,弊端在于不能进行强转。
demo
/*
* 泛型的通配符
*/
import java.util.*;
public class GenericDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("asfd");
list.add("adsfgsfd");
list.add("sdfgsd");
list.add("asertfd");
list.add("qwey");
method(list);
}
/*
* 定义方法,遍历集合,但是不知道集合的类型
* 使用 ? 泛型的通配符
* 缺点:只能遍历。没办法做强转
*/
public static void method(Collection<?> c){
Iterator<?> it = c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
2. 泛型的限定
泛型的限定问题,写泛型的时候,只需要确定子类,或者父类就可以使用泛型的限定,案例员工和经理,实现了限定操作,提高了安全性,避免了数据类型的强制转换
泛型上限限定 ? extends E 传递E类型 和E的子类
泛型下限限定 ? super E 传递E类型 和E的父类
七、增强for循环
直接给出demo:
package generic;
import java.util.*;
/*
* 练习增强for循环
*/
public class ForeachDemo {
public static void main(String[] args) {
method2();
}
/*
* 普通数据类型的遍历
*/
public static void method() {
int[] a = { 6, 8, 8, 9, 10, 674, 687 };
for (int i : a) {
System.out.print(i + " ");
}
System.out.println("");
char[] b = { 's', 'd', 'f', 'l', 'i' };
for (char i : b) {
System.out.print(i);
}
}
/*
* 对象数组的遍历
*/
public static void method1() {
String[] s = { "saefsadf", "saasdf", "sadfasdfsdf" };
for (String i : s) {
System.out.println(i.length());
}
}
/*
* 集合的遍历
*/
public static void method2() {
Set<String> s = new HashSet<String>();
s.add("sretgd");
s.add("dfga");
s.add("sretwrey5gd");
s.add("sresdfgrtgd");
s.add("rt78uj");
for (String i : s) {
System.out.println(i.length());
}
}
}