一、泛型技术的由来

泛型是从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());
		}
	}
}