🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 泛型 [TOC] ## 简单应用 1、不使用泛型的缺点:需要强制转换;可向集合中添加任意类型的对象,存在风险 2、泛型的使用:在接口/类名后的尖括号内加上类型,如 List list=new ArrayList(); 同时,变量声明时的泛型类和其实现类时的泛型类必须相同,即“=”前后的尖括号中的类型需要一致 ~~~ class Animal{} class Cat extends Animal {} list<Animal> list = new ArrayList<Cat>(); 这样是不允许的。变量声明的类型必须匹配传递给实际对象的类型 ~~~ ## 为什么要使用泛型 在之前学过的集合框架中,List和Map都使用了泛型技术来确认其内容的数据类型。 如果不使用泛型,在程序运行阶段,会带来数据类型转型的错误风险。 ~~~ List<String> list = new ArrayList<String>(); list.add("tom"); for (int i = 0; i < list.size(); i++) { String obj = list.get(i); System.out.println(obj); } List list2 = new ArrayList(); list2.add("helen"); list2.add(2); // 自动装箱成Integer list2.add(true); // 自动装箱成Boolean for (int i = 0; i < list2.size(); i++) { String obj = (String)list2.get(i); // 此处是有风险的 } ~~~ 在Java中,使用变量之前,必须要先定义变量的数据类型,存在一种特殊的现象,就是多态(数据类型是父类,实现对象是子类),变量赋值不一定要完全和数据类型一致,可以赋予子类对象给它。 ~~~ public class Client2 { public static void main(String[] args) { Point point = new Point(); point.x = "东经102°"; point.y = "北纬32°"; point.x = 102; point.y = 32; String s = (String) point.x; point.print(); } } class Point { Object x; Object y; public void print() { System.out.println(x + "" + y); } } ~~~ >[danger] 向下转型会带来数据风险的(ClassCastException) ## 泛型使用 **泛型作为方法参数** >[info] 案例: > 定义一个抽象类Goods,包含抽象方法sell(); > 分别定义各类商品Book,Clothes和Shoes继承Goods,并实现sell()方法,输出一句话,如sell books > 定义一个商品销售类GoodsSeller,模拟销售,包括方法:public void sellGoods(List goods),循环调用list对象的sell() 方法 ~~~ public abstract class Goods { public abstract void sells(); } public class Books extends Goods{ @Override public void sells() { System.out.println("sell books"); } } public class Clothes extends Goods { @Override public void sells() { System.out.println("sell clothes"); } } public class Shoes extends Goods { @Override public void sells() { System.out.println("sell shoes"); } } public class GoodsSeller { //代表只要goods参数保存的元素是Goods或者Goods的子类,都可以 public void sellGoods(List<? extends Goods> goods) { //调用集合中的sell方法 for(int i = 0; i < goods.size(); i++) { Goods g = goods.get(i); g.sells(); } } } public class Test { public static void main(String[] args) { //定义books相关的list List<Books> bookLst = new ArrayList<Books>(); bookLst.add(new Books()); bookLst.add(new Books()); //定义Shoes相关的list List<Shoes> shoesLst = new ArrayList<Shoes>(); shoesLst.add(new Shoes()); shoesLst.add(new Shoes()); //定义Clothes相关的list List<Clothes> clothesLst = new ArrayList<Clothes>(); clothesLst.add(new Clothes()); clothesLst.add(new Clothes()); GoodsSeller gdSeller = new GoodsSeller(); gdSeller.sellGoods(bookLst); } } ~~~ **自定义泛型类** ~~~ public class Demo { public static void main(String[] args) { Point<Integer, Integer> p = new Point<Integer, Integer>(); p3.x = 1; p3.x = 2; } } public class Point<T1, T2> { T1 x; T2 y; } ~~~ >[warning] 类的泛型在className之后定义,只有定义的泛型类型才能在类中使用。 即我们定义只有先定义类名后的泛型标志符的时候,才能使该泛型类使用泛型定义方法和成员变量。 **自定义泛型方法** >[success] 泛型方法不一定要写在泛型类中 ~~~ /** * 定义泛型方法 **/ public class GenericMethod { //定义泛型方法的时候需要将泛型放在访问修饰符和返回值中间 public <T extends Number> void print(T t) { System.out.println(t.toString()); } public static void main(String[] args) { GenericMethod gm = new GenericMethod(); //可以通过泛型方法实现一个方法传递不同的参数 //gm.print("123");规定泛型的继承限定之后,该行语句就是错误的了 gm.print(123); gm.print(123f); } } ~~~ >[warning] 泛型一般使用于框架设计,在实际的应用开发中较少运行 ## Java泛型中的标记符含义: E - Element (在集合中使用,因为集合中存放的是元素) T - Type(Java 类) K - Key(键) V - Value(值) N - Number(数值类型) ? - 表示不确定的java类型 `<K,V>`就是代表键值对的泛型