定义类、接口、方法时,同时声明了一个或者多个类型变量(如:<E>) ,称为泛型类、泛型接口,泛型方法、它们统称为泛型。
作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的异常。
1.泛型类:
定义类的同时定义了泛型的类就是泛型类
泛型类的格式:
作用: 在编译阶段可以指定能操作的数据的类型
原理: 把出现泛型变量的地方全部替换成传输的真实数据类型。
代码演示1:
package com.itheima.day06.teacher.c_generics;import java.util.ArrayList;
/**集合用泛型的意义集合是存储对象的容器。一般来说存储的同种类型的对象。泛型:未知的类型 定义的时候不知道具体的类型。定义集合的时候,是不知道具体的集合对象存储什么类型对象的。所以集合采用泛型 来表示 未知的类型。你可以将泛型理解成一个占位符。使用集合的时候就需要确定 集合存储什么具体的类型了。确定之后 所有用到泛型的位置都会变成 具体的类型泛型 在定义不确定,在使用的时候必须确定。*/
public class GenericsDemo01 {public static void main(String[] args) {//这里是没用泛型一个类型定义一个集合ArrayList<String> list = new ArrayList<>();list.add("aaa");// list.add(12); //泛型限定传输的类型ArrayList<Integer> list2 = new ArrayList<>();list2.add(12);ArrayList list3 = new ArrayList();// Objectlist3.add("aaa");list3.add(123);list3.add("123");for (int i = 0; i < list3.size(); i++) {Object o = list3.get(i);String s = (String) o;}}
}--------------
package com.itheima.day06.teacher.c_generics;/**这里是用泛型之后
*/
public class NBA<MVP>{ //泛型定义在类上//作用 在类中 都可以去使用这个未知的类型private MVP mvp ;//MVP泛型类型 定义的时候不具体public MVP getMvp(){//可以当成返回值类return mvp;}public void setMvp(MVP mvp) {//可以作为参数类型this.mvp = mvp;}
}------
package com.itheima.day06.teacher.c_generics;/*** 测试类*/
public class Demo01 {public static void main(String[] args) {//创建一个NBA对象NBA<String> nba = new NBA<>();nba.setMvp("恩比德");String mvp = nba.getMvp();System.out.println(mvp);NBA<Integer> nba2 = new NBA<>();nba2.setMvp(77);System.out.println(nba2.getMvp());}
}-----------
代码演示2:
package com.itheima.day06.teacher.d_generics;/*泛型只能是引用类型*/public class MyArrayList<E>{//定义底层数组变量private Object[] array = new Object[10];//定义初始容量//定义一个数组的初始索引private int index = 0;/*添加元素 add(E )*/public void add(E e){array[index] = e;index++;}/*根据索引获取元素*/public E get(int index){return (E)array[index];}
}-------------
package com.itheima.day06.teacher.d_generics;/*** 测试类*/
public class Demo {public static void main(String[] args) {MyArrayList<String> list = new MyArrayList<>();list.add("霍霍霍");list.add("魁魁魁");String s = list.get(0);System.out.println(s);}
}
2.泛型接口
使用了泛型定义的接口就是泛型接口
格式:修饰符 interface 接口名称<泛型变量>{}
作用:泛型接口可以让实现类选择当前功能需要操作的数据类型
原理:实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作。
代码演示:
package com.itheima.day06.teacher.e_generics;
/**泛型接口
*/
public interface MyHoliday<X>{//泛型定义在接口 规范方法的使用void eat(X x);
}-------------
package com.itheima.day06.teacher.e_generics;public class Student implements MyHoliday<String>{@Overridepublic void eat(String s) {System.out.println("吃烧烤...吃棒棒糖 bulubiu");}
}------------
package com.itheima.day06.teacher.e_generics;import java.util.Comparator;
/**泛型类也可以实现泛型接口
*/
public class Teacher<X> implements MyHoliday<X>{@Overridepublic void eat(X x) {}
}
3.泛型方法
定义方法时同时定义了泛型的方法就是泛型方法
格式:
作用:方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性。
代码演示:
package com.itheima.day06.teacher.f_generics;
/**泛型方法
*/
public class GenericsDemo {public static void main(String[] args) {String aaa = test("aaa");Integer test = test(12);Double test1 = test(1.23);}public static <T> T test(T t){return t;}
}---------------
package com.itheima.day06.teacher.f_generics;
/**泛型类里定义泛型方法
*/
public class Sugar<E> {private E e;public E getE(){return e;}public <T> void show(T t){//泛型定义在方法上}}
4.泛型通配符、上下限
? 可以在“使用泛型”的时候代表一切类型。
E T K V 是在定义泛型的时候使用的。
泛型的上下限:
1. ? extends Car: ?必须是Car或者其子类 泛型上限
2. ? super Car : ?必须是Car或者其父类 泛型下限
代码演示:
package com.itheima.day06.teacher.f_generics;import java.util.ArrayList;/*定义几个类*/
class Car extends Object {
}class BENZ extends Car {
}class ThreeBengZi extends Car {
}public class Test {public static void main(String[] args) {ArrayList<BENZ> list1 = new ArrayList<>();ArrayList<ThreeBengZi> list2 = new ArrayList<>();ArrayList<Car> list3 = new ArrayList<>();ArrayList<Object> list4 = new ArrayList<>();test1(list1);test1(list2);test1(list3);test1(list4);test2(list1);test2(list2);test2(list3);test2(list4);System.out.println("===================");System.out.println("= 只能车及其子类 可以接收========");test3(list1);// ArrayList<BENZ> list1 = new ArrayList<>();test3(list2);// ArrayList<ThreeBengZi> list2 = new ArrayList<>();test3(list3);// ArrayList<Car> list3 = new ArrayList<>();// ArrayList<Car> list3 = new ArrayList<Car>();// 如果类型有泛型 类型<泛型> 整体是一个类型!!// List<Car> ArrayList<Car>
// test3(list4);// <? extends Car> 泛型的类型是Car或及其子类!// <? super Car> 泛型的类型是Car或及其父类!System.out.println("= 只能车及其父类 可以接收========");
// test4(list1);
// test4(list2);test4(list3);test4(list4);}/*设计一个方法 可以接收 各种各样的集合*/public static <T> void test1(ArrayList<T> list) {System.out.println("测试");}/*? 通配符接收带有泛型集合*/public static void test2(ArrayList<?> list) {System.out.println("测试");}public static void test3(ArrayList<? extends Car> list) {System.out.println("限制泛型的类型!!!!!");}public static void test4(ArrayList<? super Car> list) {System.out.println("限制泛型的类型!!!!!");}
}
最后注意事项:
泛型的注意事项:擦除问题、基本数据类型问题
1.泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。(大白话就是执行后生成的class文件,不在是你定义的字母,而是你传入的实际类型)
2.泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。