泛型的理解
1、什么是泛型
在定义类,接口时通过一个标识表示类中某个属性的类型或者某个方法的返回值及参数类型。这个参数类型将在使用类或者接口时(例如 继承或者实现这个接口,用这个类型声明变量,创建对象时)确定(也就是实际传入的类型)
传入什么类型,就必须用这个类型,不能用别的类型了。如果没有定就是随便用了。如下面的集合中使用泛型
2、集合中使用泛型
public class Fanxing { public static void main(String[] args) { //意思是在往集合里面放数据的时候只能放Integer类型的数据 List<Integer> list = new ArrayList<Integer>(); list.add(89); list.add(88); list.add(82); list.add(87); //这里会报错,编译直接都过不了 // list.add("tom"); } }
3、Map中使用泛型
// 意思是 key 只能是String 类型,value只能是 Integer 类型 Map<String,Integer> map = new HashMap<String,Integer>(); map.put("tom",89); map.put("jerry",89); map.put("jack",86); //这里直接编译报错 // map.put(223,"sss")
4、自定义泛型结构
包括泛型类,泛型接口,泛型方法
4.1 泛型类
当类的属性不太确定的时候,可以用泛型 用T 或者E 来标识,然后类里面就可以使用这个T了,T就是类的一个属性
public class Order<T> { String orderName; int orderId; T ordert; public Order(String orderName, int orderId, T ordert) { this.orderName = orderName; this.orderId = orderId; this.ordert = ordert; } public Order(){ } public String getOrderName() { return orderName; } public void setOrderName(String orderName) { this.orderName = orderName; } public int getOrderId() { return orderId; } public void setOrderId(int orderId) { this.orderId = orderId; } public T getOrdert() { return ordert; } public void setOrdert(T ordert) { this.ordert = ordert; } }
4.2 使用泛型类
这里使用的时候声明了T的类型是String,那么Order里面涉及到T的地方都必须是String类型,不能是别的,否则编译都报错
Order<String> order = new Order<String>(); order.setOrdert("abc"); System.out.println(order.getOrdert());
4.3 继承自定义泛型类时指定泛型的类型
一般继承自定义泛型类的时候需要指定泛型的类型,子类使用的时候就不用指定泛型的类型了
public class SubOrder extends Order<Integer>{ }
SubOrder subOrder = new SubOrder();
subOrder.setOrdert(2344);
System.out.println(subOrder.getOrdert());
4.4继承自定义泛型类时不指定泛型的类型
此时SubOrder1依然是自定义的泛型类,使用的时候需要指明泛型的类型
public class SubOrder1<T> extends Order<T> { }
SubOrder1<String> subOrder1 = new SubOrder1();
subOrder1.setOrdert("23232");
System.out.println(subOrder1.getOrdert());
5、泛型方法
5.1、范型方法使用1
泛型方法:在方法中出现了泛型结构,泛型参数和类的泛型参数没有关系,也就是说普通的类里面也可以有泛型方法,泛型方法里面的标识和当前类的泛型标识不要重
public class Order<T> { //泛型方法 参数里面的E是数组的类型,List 里面的E是,list放的数据类型,<E> 意思是告诉编译器这个E是个泛型,不加的话会认为E是个普通的类。 public <E> List<E> copyFromArrayToList(E[] arr){ List<E> list = new ArrayList<>(); for(E e : arr){ list.add(e); } return list; } } public class GenericTest1 { public static void main(String[] args) { Order<String> order = new Order<String>(); Integer[] integers = new Integer[]{12,122,455,22}; List<Integer> list = order.copyFromArrayToList(integers); System.out.println(list); } }
5.2、范型方法使用2
类的属性中使用范型
/** * 类中的方法使用自定义的函数式接口 */ public class MyDomain { public <T> T excute(MyFunction<T> myFunction){ return myFunction.getRes(); } } /** * * 自定义函数式接口 * * @param <T> */ @FunctionalInterface public interface MyFunction<T> { public T getRes(); } @RequestMapping("/getres") public boolean getres(){ MyDomain myDomain = new MyDomain(); return myDomain.excute(new MyFunction<Boolean>() { public Boolean getRes(){ return true; } }); } 类中有个一个方法,方法是范型的,并且方法的参数是带范型的自定义函数。 方法的返回值是 参数的调用自己的方法做为返回值。也就是说明了类中方法的返回值是什么根据方法参数调用自身的方法决定的
6、泛型通配符的使用
如下的代码:不管list 里面放的是什么类型的数据都可以调用show方法
public class Test2 { public static void main(String[] args) { List<Object> object1= new ArrayList<>(); List<String> obj = new ArrayList<>(); show(obj); show(object1); } public static void show(List<?> list){ Iterator<?> iterator = list.iterator(); while (iterator.hasNext()){ Object obj = iterator.next(); System.out.println(obj); } } }
7、有限制条件的通配符的使用
意思是通配符结合 extend super 来使用
public class Test3 { public static void main(String[] args) { //用的时候 list的值是Person或者子类 List<? extends Persion> list1 = null; //用的时候 list的值是Person或者父类 List<? super Persion> list2 = null; List<Persion> list3 = new ArrayList<>(); List<Student> list4 = new ArrayList<>(); List<Object> list5 = new ArrayList<>(); list1 = list3; Persion p = list1.get(0); list1 = list4; Student student = (Student)list1.get(0); list2 = list5; list2 = list3; } }
8 lamdba表达式中使用范型
这里也可以理解成在new 对象的时候指定范型
//这里需要在前面指定范型的类型,否则没有办法使用传入参数的方法。 Predicate<String> pre = (str)->{ return str.isEmpty(); }; //这里和以前的写发一样 Predicate predicate = new Predicate<String>() { @Override public boolean test(String o) { return o.isEmpty(); } };