1 泛型简介
- 所谓泛型,就是标签,比如中药店的标签, 就是允许在定义类、 接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。 这个类型参数将在使用时(例如,继承或实现这个接口, 用这个类型声明变量、 创建对象时) 确定(即传入实际的类型参数, 也称为类型实参
- 从JDK1.5以后, Java引入了“参数化类型( Parameterized type) ” 的概念,允许我们在创建集合时再指定集合元素的类型, 正如: List, 这表明该List只能保存字符串类型的对象。
- JDK1.5改写了集合框架中的全部接口和类, 为这些接口、 类增加了泛型支持,从而可以在声明集合变量、 创建集合对象时传入类型实参。
- 集合没有泛型时:读取出数据需要强制类型转换,有可能抛出ClassCastException
- 集合中使用泛型:可以避免强转,避免抛出ClassCastException
1.1 List使用泛型
public class ListTest {
/**
* 没有泛型
*/
@Test
public void test1() {
List list = new ArrayList();
list.add(123); //存入 int 装箱 Integer
String str = (String) list.get(0); //ClassCastException
}
/**
* 使用泛型
*/
public void test2() {
// List<String> list = new ArrayList<String>(); //jkd1.5
List<String> list = new ArrayList<>(); //jkd1.5
list.add("123"); //因为泛型,只能存String;
String str = list.get(0); //泛型的主要作用:避免强制类型转换
}
/**
* 泛型List循环
*/
@Test
public void test3() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
//迭代器循环
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
Integer i = it.next();
System.out.println(i);
}
//增强for循环
for (Integer i : list) {
System.out.println(i);
}
}
}
1.2 Map使用泛型
public class MapTest {
@Test
public void test1() {
Map map = new HashMap();
map.put("a", 111);
map.put(222, "b");
map.put(new Date(), "ccc");
Set set = map.entrySet();
//EntrySet
for (Object obj : set) {
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + " " + entry.getValue());
}
System.out.println("------------");
//keySet
Set keys = map.keySet();
for (Object obj : keys) {
System.out.println(obj + " " + map.get(obj));
}
}
@Test
public void test2() {
// Map<String, Integer> map = new HashMap<String, Integer>();
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("a", 1);
map.put("b", 1);
map.put("c", 1);
map.put("d", 1);
map.put("e", 1);
map.put("f", 1);
map.put("g", 1);
map.put("h", 1);
//EntySet
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
System.out.println("--------------");
//keySet
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
System.out.println("key = " + key + "value =" + map.get(key));
}
}
}
2 自定义泛型
2.1 泛型类
在类声明式使用泛型约束这个类使用的泛华类型
1 语法
//格式
public class 类名 <泛型类型1,...> {
}
2 案例演示
public class GenericsCls<T1, T2> {
public void f1(T1 arg1, T2 arg2) {
System.out.println(arg1);
System.out.println(arg2);
}
private T1 t1;
private T2 t2;
public T1 getT1() {
return t1;
}
public void setT1(T1 t1) {
this.t1 = t1;
}
public T2 getT2() {
return t2;
}
public void setT2(T2 t2) {
this.t2 = t2;
}
}
测试类
public class Test {
public static void main(String[] args) {
GenericsCls<String, Date> bean = new GenericsCls<>();
bean.f1("abc", new Date());
bean.setT1("t1 = 1");
bean.setT2(new Date());
System.out.println(bean.getT1());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(sdf.format(bean.getT2()));
GenericsCls<String, Clz> bean2 = new GenericsCls<>();
bean2.f1("aaaa", new Clz());
}
}
class Clz {
@Override
public String toString() {
return "Clz{}";
}
}
2.2 泛型方法
1 语法
//格式
public <泛型类型...> 返回类型 方法名(泛型类型 变量名) {
}
2 案例演示
public class GenericsMethod {
/**
* 泛型方法
* @param bean
* @param arg
* @return
* @param <T1>
* @param <T2>
*/
public static <T1, T2> T1 f1(T1 bean, T2 arg) {
System.out.println(arg);
return bean;
}
public static void main(String[] args) {
String str = f1("abc", new Date());
Date date = f1(new Date(), "cba");
Integer i = f1(123, "aaa");
}
}
2.3 泛型接口
1 语法
public interface GenricsInterface<T>{
}
//实现类
public class Clazz implements GenricsInterface<String> {
}
2 案例演示
接口
public interface GenericsInterface<T> {
public T getValue();
}
接口实现类
public class IntegerImpl implements GenericsInterface<Integer> {
@Override
public Integer getValue() {
return 123456;
}
}
public class StringImpl implements GenericsInterface<String> {
@Override
public String getValue() {
return "hello generics interface";
}
}
测试类
public class Test {
public static void main(String[] args) {
GenericsInterface<String> g1 = new StringImpl();
System.out.println(g1.getValue());
GenericsInterface<Integer> g2 = new IntegerImpl();
System.out.println(g2.getValue());
}
}
3 泛型通配符
3.1 通配符的上边界
<? extends T>,在类型参数中使用 extends 表示这个泛型中的参数必须是 T 或者 T 的子类
例:
<? extends Father>: 泛型中的参数必须是Father和father的子类
public class Test {
public static void f1(List<? extends Father> list) {
}
public static void main(String[] args) {
List<GrandFather> grandFatherList = new ArrayList<>();
List<Father> fatherList = new ArrayList<>();
List<Mother> motherList = new ArrayList<>();
List<Son> sonList = new ArrayList<>();
List<Daughter> daughterList = new ArrayList<>();
f1(sonList);
f1(daughterList);
f1(fatherList);
// f1(motherList);//? extend Father:表示对象边界是Father和Father的子类
// f1(motherList);
}
class GrandFather {
}
class Father extends GrandFather {
}
class Mother {
Father father;
}
class Daughter extends Father {
}
class Son extends Father {
}
}
3.2 通配符的下边界
例:
<? super Father>: 泛型中的参数必须是Father和father的父类
public class Test2 {
public static void f1(List<? super Father> list) {
}
public static void main(String[] args) {
List<GrandFather> grandFatherList = new ArrayList<>();
List<Father> fatherList = new ArrayList<>();
List<Mother> motherList = new ArrayList<>();
List<Son> sonList = new ArrayList<>();
List<Daughter> daughterList = new ArrayList<>();
// f1(sonList);
// f1(daughterList);
f1(fatherList);
f1(grandFatherList);//? super Father:表示对象边界是Father和Father的父类
// f1(motherList);
}
class GrandFather {
}
class Father extends GrandFather {
}
class Mother {
Father father;
}
class Daughter extends Father {
}
class Son extends Father {
}
}
3.3 泛型边界在接口中的应用
声明接口的泛型只能使用 < T extends Type >
public class Test2 {
class Impl1 implements GenricsInterface<Father> {
@Override
public Father getValue() {
return null;
}
}
// class Impl2 implements GenricsInterface<Mother> {
//
// @Override
// public Mother getValue() {
// return null;
// }
// }
// class Impl3 implements GenricsInterface<String> {
//
// @Override
// public String getValue() {
// return null;
// }
// }
// class Impl4 implements GenricsInterface<GrandFather> {
//
// @Override
// public GrandFather getValue() {
// return null;
// }
// }
class Impl5 implements GenricsInterface<Son> {
@Override
public Son getValue() {
return null;
}
}
class Impl6 implements GenricsInterface<Daughter> {
@Override
public Daughter getValue() {
return null;
}
}
interface GenricsInterface<T extends Father> {
public T getValue();
}
class GrandFather {
}
class Father extends GrandFather {
}
class Mother {
Father father;
}
class Daughter extends Father {
}
class Son extends Father {
}
}
3.4 无界通配符
< ? > 表示传入任意类型
public static void f2(List<?> list) {
}
public void test1() {
f2(sonList);
f2(daughterList);
f2(fatherList);
f2(grandFatherList);
f2(motherList);
f2(new ArrayList<String>());
}
4 Java的泛型擦除
Java的泛型是伪泛型,为什么说Java的泛型是伪泛型呢?因为在编译期间,所有的泛型信息都会被擦除掉,我们常称为泛型擦除。
@Test
public void test1() {
List<String> stringList = new ArrayList<String>(); //ArrayList<String>.class
stringList.add("泛型");
List<Integer> integerList = new ArrayList<Integer>(); //ArrayList.class
integerList.add(1);
System.out.println(stringList.getClass());
System.out.println(stringList.getClass() == integerList.getClass()); //true
}