泛型「generic」讲解
创始人
2024-01-30 19:14:08
0

标题

  • 1. 泛型语法
    • 1.1 泛型的引出
    • 1.2 泛型介绍
    • 1.3 泛型语法
    • 1.4 泛型使用细节
    • 1.5 练习题
  • 2.自定义泛型
    • 2.1自定义泛型-类
    • 2.2自定义泛型-接口
    • 2.3自定义泛型-方法
    • 2.4练习题
  • 3.范型继承和通配符
    • 3.1JUnit单元测试框架
    • 3.2练习题

1. 泛型语法

1.1 泛型的引出

  1. 传统方法不能对加入到集合中的数据类型进行约束;
  2. 对集合遍历的时候需要进行类型转换,效率低;
public class Generic01 {public static void main(String[] args){ArrayList arrayList = new ArrayList();arrayList.add(new Dog("scott",4));arrayList.add(new Dog("jack",5));arrayList.add(new Dog("mary",6));for(Object o : arrayList) {Dog dog = (Dog) o;//获取对象的名字System.out.println(dog.getName());}}
}
class Dog {private String name;private int age;public Dog(String name, int age) {this.name = name;this.age = age;}public void setName(String name) {this.name = name;}public String getName() {return name;}public void setAge(int age) {this.age = age;}public int getAge() {return age;}
}
  1. 引出:new ArrayList(),表示存放到ArrayList 集合中的元素是Dog类型
  2. 优点
    • 如果编译器发现添加的类型不满足要求,就会报错,即编译时编译器会检查添加元素的类型,提高安全性;
    • 遍历时,可以直接取出Dog类型,而不是Object类型,减少了类型转换的次数;
public class Generic01 {public static void main(String[] args){ArrayList arrayList = new ArrayList();arrayList.add(new Dog("scott",4));arrayList.add(new Dog("jack",5));arrayList.add(new Dog("mary",6));//arrayList.add(new Cat("招财猫",3));for(Dog dog : arrayList) {System.out.println(dog.getName());}}
}

不使用泛型:放入到ArrayList会先转成Object,在取出时,再转换成Dog;
使用泛型:放入和取出时,不需要类型转换;

不使用泛型使用泛型
放入到ArrayList会先转成Object,在取出时,再转换成Dog;放入和取出时,不需要类型转换;

1.2 泛型介绍

  1. 泛型是可以表示数据类型的一种数据类型;
  2. 泛型又称为参数化类型,是jdk5.0出现的新特性,可以解决数据类型的安全性问题;
  3. 在类声明或者实例化的时候只需要指定需要的具体类型即可;
  4. Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException的异常;同时,代码更简洁、健壮。
  5. public class ArrayList ,相当于把Dog赋给了E,Dog->E
  6. 泛型的作用是: 可以在类声明时通过一个标识符表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。
    - 参数的类型
    - 类中方法返回值的类型
    - 属性的类型
泛型Generic
参数的类型$1600
类中方法返回值的类型$12
属性的类型$1
  1. 在这里,E的类型一定要清楚的知道,可以通过getClass()方法得到;
  2. 注意:E具体的数据类型在定义Person对象时指定,即在编译期间就已确定类型;
    在这里插入图片描述

1.3 泛型语法

  1. interface 接口 {} 和 class 类{}
  • 说明:
    • T、K、V不代表值,而是表示类型;
    • 任意字母都可以,常用T表示,T是Type的缩写
  1. 泛型的实例化:要在类名后面指定类型参数的值(类型),如:
    • (1)List stringList = new ArrayList<\String>();
    • (2)Interator<\Dog> iterator = dog.iterator();
      在这里插入图片描述
      在这里插入图片描述

1.4 泛型使用细节

  1. interface List {}, public class HashSet {};
    T,E只能是引用类型,不能用基本数据类型;(Type argument cannot be of primitive type)
    在这里插入图片描述
  2. 在给泛型指定具体类型后,可以传入该类型或其子类类型;
    在这里插入图片描述
  3. 泛型的简写形式:省略构造器处的泛型表示,编译器会进行类型推断;
    List list = new ArrayList<>();
  4. 如果没有指定泛型,默认泛型是Object;
    Map hashMap = new HashMap();
    等价于
    Map hashMap = new HashMap<>();
    在这里插入图片描述
    在这里插入图片描述

1.5 练习题

在这里插入图片描述
改进后:封装后代码复用性更高;
在这里插入图片描述
在这里插入图片描述

2.自定义泛型

2.1自定义泛型-类

  1. 基本语法:class 类名 {} 可以有多个泛型
  2. 普通成员可以使用泛型(属性、方法);
  3. 使用泛型的数组不能初始化;
  4. 静态成员中不能使用类的泛型;
  5. 泛型类的类型,是在创建对象时确定的;(因为在创建对象时,需要指定类型)
  6. 如果在创建对象时,没有指定类型,默认为Object;
public class CustomGeneric {public static void main(String[] args) {//T是Double,R是String,M是IntegerTiger tiger = new Tiger<>("john~~");tiger.setT(3.2);//OKSystem.out.println(tiger);Tiger tiger1 = new Tiger("john");//tiger.setT("yy");因为T是Object,"yy"是 Object子类,类型不对}
}
//1.Tiger后面有泛型,所以我们把Tiger 称为自定义泛型类
//2.T, R, M 泛型的标识符,一般是单个大写字母
//3.泛型的标识符可以有多个
//4.普通成员可以使用泛型 (属性、方法)
//5.使用泛型的数组,不能初始化
class Tiger {String name;T t;//属性使用到泛型M m;R r;public Tiger(String name) {this.name = name;}//Type parameter 'T' cannot be instantiated directly//T[] ts = new T[8];类型不能确定,无法分配空间,因为数组在new的时候不能确定T的类型,就无法在内存开辟空间public Tiger(T t, M m, R r) {//构造器使用泛型this.t = t;this.m = m;this.r = r;}//因为静态是和类相关的,在类加载时,对象还没有创建//所以,如果静态方法和静态属性使用了泛型,JVM就无法完成初始化/*static R r2;public static void m1(M m) {//cannot be referenced from a static context}*///方法使用泛型public String getName() {return name;}public void setName(String name) {this.name = name;}public T getT() {return t;}public void setT(T t) {this.t = t;}public M getM() {return m;}public void setM(M m) {this.m = m;}public R getR() {//返回类型可以使用泛型return r;}public void setR(R r) {//方法使用到泛型this.r = r;}
}

2.2自定义泛型-接口

基本语法:interface 接口名 {}

  1. 接口中静态成员也不能使用泛型;(和泛型类规定一样)
  2. 泛型接口的类型,在继承接口或者实现接口时确定;
  3. 如果没有指定类型,默认为Object;(不规范,建议指定
  4. 方法参数列表中的泛型直接给值,类定义时的泛型给类型;
  5. /*** 泛型接口使用说明* 1.接口中,静态成员不能使用泛型* 2.泛型接口的类型是在继承接口或者实现接口时实现的*///1.在继承接口时,指定泛型接口的类型
    interface IA extends IUsb {}
    //当我们去实现IA接口时,因为IA在继承IUsb接口时,指定了U为String,R为Double
    // 因此在实现IUsb接口方法时,使用String替换U,Double替换R
    class AA implements IA {@Overridepublic Double get(String s) {return null;}@Overridepublic void hi(Double aDouble) {}@Overridepublic void run(Double r1, Double r2, String u1, String u2) {}
    }
    //2.实现接口时,直接指定泛型接口的类型
    //给U指定了Integer, 给R指定了Float
    //所以当实现IUsb接口方法时,会使用Integer替换U,Float替换R
    class BB implements IUsb {@Overridepublic Float get(Integer integer) {return null;}@Overridepublic void hi(Float aFloat) {}@Overridepublic void run(Float r1, Float r2, Integer u1, Integer u2) {}
    }//3.没有指定泛型,就默认为Object
    //等价于class CC implements IUsb {}, 但是不规范
    class CC implements IUsb {@Overridepublic Object get(Object o) {return null;}@Overridepublic void hi(Object o) {}@Overridepublic void run(Object r1, Object r2, Object u1, Object u2) {}}
    interface IUsb {//U=Integer, R=Float//接口中普通方法,可以使用泛型R get(U u);int n = 10;//U name = "3e";静态成员不能使用泛型void hi(R r);void run(R r1, R r2, U u1, U u2);//在jdk8以后,可以在接口中使用默认方法,在默认方法中可以使用泛型default R method(U u) {return null;}
    }
    

    2.3自定义泛型-方法

    基本语法:修饰符[空格] 返回类型 方法名(参数列表) {}

    1. 泛型方法,可以定义在普通类中,也可以定义在泛型类中;
    2. 当泛型方法被调用时,泛型类型就会确定,否则调用不起来;
    3. public void ear(E e) {},修饰符后面没有 , 那么eat方法就不是泛型方法,只是使用了泛型;
    4. 泛型方法可以使用类声明的泛型,也可以使用自己声明的泛型;
    public class CustomMethodGeneric_ {public static void main(String[] args) {Car car = new Car();//2. 当泛型方法被调用时,泛型类型就会确定,否则调用不起来;car.fly("宝马",1200);//当调用方法时,传入参数,编译器就会确定类型System.out.println("===========");car.fly(2.2,1200);//当调用方法时,传入参数,编译器就会确定类型System.out.println("===========");//T:Sring, R:ArrayListFish fish = new Fish<>();//K:Floatfish.hello(new ArrayList(), 2.1f);}
    }
    //1.泛型方法,可以定义在普通类中
    class Car {//普通类public void run() {//普通方法}//说明:泛型方法//  就是泛型// 提供给fly方法使用的public  void fly(T t, R r) {//泛型方法System.out.println(t.getClass());//StringSystem.out.println(r.getClass());//Integer}
    }
    //2.泛型方法,也可以定义在泛型类中
    class Fish {//泛型类public void run() {//普通方法}public  void fly(U u, M m) {//泛型方法}//说明//  hi()方法不是一个泛型方法//  只是hi()方法使用了类声明的泛型public void hi(T e) {}//泛型方法,可以使用类声明的泛型,也可以使用自己声明的泛型public  void hello(R r, K k) {System.out.println(r.getClass());//ArrayListSystem.out.println(k.getClass());//Float}
    }
    

    2.4练习题

    public class CustomMethodGenericExercise {public static void main(String[] args) {//T:String, R:Integer, M:DoubleApple apple = new Apple<>();apple.fly(10);//泛型都是引用类型,所以10自动装箱,输出:Integerapple.fly(new Dog());//输出:Dog}
    }class Apple {public  void fly(E e) {//.getClass():显示包名+类名; //.getClass().getSimpleName():只显示类名System.out.println(e.getClass().getSimpleName());}//public void eat(U u) {} //错误,U没有声明public  void eat(U u) {} //改正public void run(M m) {}}
    class Dog {}
    

    3.范型继承和通配符

    1. 泛型不具备继承性;
      List list = new ArrayList ();//这样写是错误的
    2. 通配符起到约束作用;
    3. 通配符作用
      List c表示可以接收任意范型类型
      List<? extends A> c表示可以接收A类或者A类的子类,规定泛型上限
      List c表示可以接收A类或者A类的父类(不限于直接父类),规定泛型下限
      @SuppressWarnings({"all"})
      public class GenericExtends {public static void main(String[] args) {//范型没有继承性//List list = new ArrayList();//举例说明下面三个方法的使用;List list1 = new ArrayList<>();List list2 = new ArrayList<>();List list3 = new ArrayList<>();List list4 = new ArrayList<>();List list5 = new ArrayList<>();//1.如果是 List c, 可以接收任意的范型类型printCollection1(list1);printCollection1(list2);printCollection1(list3);printCollection1(list4);printCollection1(list5);//2.如果是 List c, 可以接收AA或者AA的子类//printCollection2(list1);//printCollection2(list2);printCollection2(list3);printCollection2(list4);printCollection2(list5);//3.如果是 List c, 可以接收AA,AA的父类但不限于直接父类printCollection3(list1);//正确//printCollection3(list2);printCollection3(list3);//printCollection3(list4);//printCollection3(list5);}public static void printCollection1(List c) {for (Object object : c) {//通配符,取出时就是ObjectSystem.out.println(object);}}public static void printCollection2(List c) {for (AA object : c) {System.out.println(object);}}//List 表示任意范型类型都可以接收//List 表示的是上限,可以接收 AA或AA的子类//List 表示的是下线,可以接收 AA或者AA的父类,不限于直接父类public static void printCollection3(List c) {for (Object object : c) {System.out.println(object);}}
      }
      class AA {}
      class BB extends AA {}
      class CC extends BB {}
       
      

      3.1JUnit单元测试框架

      shortcuts: Alt+Enter/option+Enter
      可以直接运行一个方法,JUnit测试框架;
      在这里插入图片描述

      public class JUnit_ {public static void main(String[] args) {//new JUnit_().m1();//new JUnit_().m2();}@Testpublic void m1() {System.out.println("m1()方法");}@Testpublic void m2() {System.out.println("m2()方法");}
      }
      

      3.2练习题

      public class Homework01 {public static void main(String[] args) {}@Testpublic void test() {//这里我们给泛型T指定的类型是UserDAO userDAO = new DAO<>();userDAO.save("No1", new User(1, 22));userDAO.save("No2", new User(2, 23));userDAO.save("No3", new User(3, 23));List list = userDAO.list();userDAO.update("No3", new User(3, 18));list = userDAO.list();userDAO.delete("No3");list = userDAO.list();User user = userDAO.get("No2");System.out.println(list);System.out.println(user.getAge());}
      }class DAO {private Map map = new HashMap<>();public void save(String id, T entity) {map.put(id, entity);}public T get(String id) {return map.get(id);}public void update(String id, T entity) {map.put(id, entity);}public List list() {List arrayList = new ArrayList<>();Set keySet = map.keySet();Iterator iterator = keySet.iterator();while (iterator.hasNext()) {String key = iterator.next();arrayList.add(get(key));}return arrayList;}public void delete(String id) {map.remove(id);}
      }
      class User {private int id;private int age;public User(int id, int age) {this.id = id;this.age = age;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "\nUser{" +"id=" + id +", age=" + age +'}';}
      }
      

      相关内容

      热门资讯

      【光明网评】聆听新年贺词,凝聚...   时间的指针即将划过公历年的最后一刻,此时,一个温暖有力的声音通过网络、荧屏、电波传遍祖国各地。2...
      方圆之间 蔚为大观(文化中国... 龙岩市永定区高北土楼群。 吴宇梁摄漳州市南靖县田螺坑土楼群。 马睿姗绘漳州市南靖县鼎和楼内景。 黄长...
      新疆这趟慢火车为何深受老百姓喜...   中新网新疆和田12月30日电 临近新年,在新疆和田火车站,7556次慢火车缓缓驶进站台,车门一开...
      视频丨“两山”理念下 新疆沙生...   在“两山”理念的科学指引下,中国之美日新月异。2024年11月28日,全长3046公里的世界第二...
      2025年哪些“中国事”让俄罗...   回望2025年,俄罗斯民众如何看待中俄关系的发展?面向2026年,他们又有怎样的期待与展望?新年...
      我国经济景气水平总体回升   本报北京12月31日电 国家统计局服务业调查中心和中国物流与采购联合会31日发布的数据显示,12...
      全球最大“华龙一号”核电基地 ...   1月1日,全球最大的“华龙一号”核电基地漳州核电2号机组正式投入商业运行,标志着漳州核电一期工程...
      “AI魔改”四大名著、历史题材...   为整治“AI魔改”视频传播乱象,国家广播电视总局自2026年1月1日起,在全国范围内开展为期一个...
      马克龙新年致辞:将干到任期“最...   新华社巴黎12月31日电 法国总统马克龙12月31日晚向法国民众发表新年致辞时说,即将到来的一年...
      万人说新疆|高山向导   随着近几年登山运动的兴起,新疆成为了许多攀登者的聚集地。普琼次旺出生于西藏日喀则,从小在珠峰下长...