java基础——泛型

打印 上一主题 下一主题

主题 914|帖子 914|积分 2742

泛型的引入

看下面这段代码:
  1. private static int add(int a, int b) {
  2.     System.out.println(a + "+" + b + "=" + (a + b));
  3.     return a + b;
  4. }
  5. private static float add(float a, float b) {
  6.     System.out.println(a + "+" + b + "=" + (a + b));
  7.     return a + b;
  8. }
  9. private static double add(double a, double b) {
  10.     System.out.println(a + "+" + b + "=" + (a + b));
  11.     return a + b;
  12. }
复制代码
如果没有泛型,要实现不同类型的加法,每种类型都需要重载一个add方法;通过泛型,我们可以复用为一个方法:
  1. private static <T extends Number> double add(T a, T b) {
  2.     System.out.println(a + "+" + b + "=" + (a.doubleValue() + b.doubleValue()));
  3.     return a.doubleValue() + b.doubleValue();
  4. }
复制代码
泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型
下面这段代码:
  1. List list = new ArrayList();
  2. list.add("xxString");
  3. list.add(100d);
  4. list.add(new Person());
复制代码
我们在使用上述list中,list中的元素都是Object类型(无法约束其中的类型),所以在取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出java.lang.ClassCastException`异常。
引入泛型,它将提供类型的约束,提供编译前的检查:
  1. List<String> list = new ArrayList<String>();
  2. // list中只能放String, 不能放其它类型的元素
复制代码
泛型的好处

1、编译时,检查添加元素的类型,提高了安全性
2、减少了类型转换的次数,提高效率
3、不再提示编译警告
介绍

1.泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题
2.在类声明或实例化时只要指定好需要的具体的类型即可。
3.Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException.异常。同时,代码更加简洁、健壮
4.泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。
代码举例:
  1. public class Generic03 {
  2.     public static void main(String[] args) {
  3.         //注意,特别强调:E具体的数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
  4.         Person<String> person = new Person<>("dfdfs");
  5.         person.show();//String
  6.         /**
  7.          * Person类相当于下面这样子
  8.          * class Person{
  9.          *     String s;//E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
  10.          *
  11.          *     public Person(String s) {//E也可以是参数类型
  12.          *         this.s = s;
  13.          *     }
  14.          *
  15.          *     public String f(){//返回类型使用E
  16.          *         return s;
  17.          *     }
  18.          *     public void show(){
  19.          *         System.out.println(s.getClass());//显示s的运行类型
  20.          *     }
  21.          * }
  22.          */
  23.         Person<Integer> person2 = new Person<>(100);
  24.         person2.show();
  25.         /**
  26.          * Person类相当于下面这样子
  27.          * class Person{
  28.          *     Integer s;//E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
  29.          *
  30.          *     public Person(Integer s) {//E也可以是参数类型
  31.          *         this.s = s;
  32.          *     }
  33.          *
  34.          *     public Integer f(){//返回类型使用E
  35.          *         return s;
  36.          *     }
  37.          *     public void show(){
  38.          *         System.out.println(s.getClass());//显示s的运行类型
  39.          *     }
  40.          * }
  41.          */
  42.     }
  43. }
  44. //泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型
  45. class Person<E>{
  46.     E s;//E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
  47.     public Person(E s) {//E也可以是参数类型
  48.         this.s = s;
  49.     }
  50.     public E f(){//返回类型使用E
  51.         return s;
  52.     }
  53.     public void show(){
  54.         System.out.println(s.getClass());//显示s的运行类型
  55.     }
  56. }
复制代码
语法

泛型的声明

interface 接口名<T,R....>{

}和class 类名{}
说明:
1)其中,T,K,V不代表值,而是表示类型
2)任意字母都可以。常用T表示,是Type的缩写
泛型的实例化

要在类名后面指定类型参数的值(类型)。如:
  1. List<String> strList = new ArrayList<String>();
  2. Iterator<Customer> iterator = customers.iterator();
复制代码
泛型使用举例

需求:
​        1.创建3个学生对象
​        2.放入到HashSet中学生对象,使用.
​        3.放入到HashMap中,要求Key 是String name,Value就是学生对象
​        4.使用两种方式遍历
  1. public class GenericExercise {
  2.     public static void main(String[] args) {
  3.         //使用泛型方式给HashSet放入3个学生对象
  4.         HashSet<Student> students = new HashSet<>();
  5.         students.add(new Student("jack",18));
  6.         students.add(new Student("tom",18));
  7.         students.add(new Student("ml",18));
  8.         //第一种遍历方式,增强for循环
  9.         for (Student student:students){
  10.             System.out.println(student);
  11.         }
  12.         //使用泛型方式给HashMap放入3个学生对象
  13.         HashMap<String, Student> hm = new HashMap<>();
  14.         hm.put("milan",new Student("milan",34));
  15.         hm.put("jack",new Student("jack",31));
  16.         hm.put("tom",new Student("tom",30));
  17.         //2.迭代器
  18.         Set<Map.Entry<String, Student>> entries = hm.entrySet();
  19.         Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
  20.         System.out.println("==========================");
  21.         while (iterator.hasNext()){
  22.             Map.Entry<String, Student> next = iterator.next();
  23.             System.out.println(next.getKey()+"-"+next.getValue());
  24.         }
  25.     }
  26. }
  27. class Student{
  28.     private String name;
  29.     private int age;
  30.     public Student(String name, int age) {
  31.         this.name = name;
  32.         this.age = age;
  33.     }
  34.     public String getName() {
  35.         return name;
  36.     }
  37.     public void setName(String name) {
  38.         this.name = name;
  39.     }
  40.     public int getAge() {
  41.         return age;
  42.     }
  43.     public void setAge(int age) {
  44.         this.age = age;
  45.     }
  46.     @Override
  47.     public String toString() {
  48.         return "Student{" +
  49.                 "name='" + name + '\'' +
  50.                 ", age=" + age +
  51.                 '}';
  52.     }
  53. }
复制代码
泛型使用注意事项

1.interface 接口名<T,R....>{

}和class 类名中T,K,V只能是引用类型。如下面:
  1. List<Integer> list = new ArrayList<Integer>();//这样写正确
  2. List<int> list = new ArrayList<int>();//这样写错误
复制代码
2.在给泛型指定具体类型后,可以传入该类型或者其子类类型
3.泛型使用形式
  1. //1.第一种方式
  2. List<Integer> list1 = new ArrayList<Integer>();
  3. //2.第二种方式
  4. List<Integer> Iist2 = new ArrayList<>();
复制代码
3.如果我们这样写List list3=new ArrayList();默认给它的泛型是  E就是Object.,等价于ArrayList arrayList = new ArrayList();
自定义泛型

自定义泛型类

语法:
  1. class 类名<T,R....>{//......表示可以有多个泛型
  2.         成员
  3. }
复制代码
注意事项:
1.普通成员可以使用泛型(属性、方法)
2.使用泛型的数组,不能初始化
3.静态方法中不能使用类的泛型
4.泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
5.如果在创建对象时,没有指定类型,默认为Object
  1. class Tiger<T,R,M>{
  2.     String name;
  3.     R r;//属性使用到泛型
  4.     M m;
  5.     T t;
  6.     T[] ts;//因为数组在new时不能确定T的类型,就无法在内存开空间
  7.     public Tiger(String name) {
  8.         this.name = name;
  9.     }
  10.     public Tiger(R r, M m, T t) {
  11.         this.r = r;
  12.         this.m = m;
  13.         this.t = t;
  14.     }
  15.     public Tiger(String name, R r, M m, T t) {//构造器使用泛型
  16.         this.name = name;
  17.         this.r = r;
  18.         this.m = m;
  19.         this.t = t;
  20.     }
  21.     //因为静态是和类相关的,在类加载时,对象还没有创建
  22.     //所以,如果静态方法和静态属性使用了泛型,JVM就无法完成初始化
  23.     //static R r2;
  24. //    public static void m1(M m){
  25. //
  26. //    }
  27.     public R getR() {//返回类型可以使用泛型
  28.         return r;
  29.     }
  30.     public void setR(R r) {//方法使用到泛型
  31.         this.r = r;
  32.     }
  33. }
复制代码
自定义泛型接口

语法:
  1. interface 接口名<T,R....>{
  2. }
复制代码
注意事项:
1.接口中,静态成员也不能使用泛型(这个和泛型类规定一样)
2.泛型接口的类型,在继承接口或者实现接口时确定
3.没有指定类型,默认为Object
  1. /**
  2. * 泛型接口使用的说明
  3. * 1.接口中,静态成员也不能使用泛型
  4. * 2.泛型接口的类型,在继承接口或者实现接口时确定
  5. * 3.没有指定类型,默认为Object
  6. */
  7. //在继承接口指定泛型接口的类型
  8. interface IA extends IUsb<String,Double>{
  9. }
  10. //当我们去实现IA接口时,因为IA在继承IUsub接口时,指定了U为String, R为Double,在实现IUsub接口的方法时,使用String替换U,是Double替换R
  11. class AA implements IA{
  12.     @Override
  13.     public Double get(String s) {
  14.         return null;
  15.     }
  16.     @Override
  17.     public void hi(Double aDouble) {
  18.     }
  19.     @Override
  20.     public void run(Double r1, Double r2, String u1, String u2) {
  21.     }
  22. }
  23. //实现接口时,直接指定泛型接口的类型
  24. //给U指定Integer给R指定了Float
  25. //所以,当我们实现IUsb方法时,会使用Integer替换U,使用Float替换R
  26. class BB implements IUsb<Integer,Float>{
  27.     @Override
  28.     public Float get(Integer integer) {
  29.         return null;
  30.     }
  31.     @Override
  32.     public void hi(Float aFloat) {
  33.     }
  34.     @Override
  35.     public void run(Float r1, Float r2, Integer u1, Integer u2) {
  36.     }
  37. }
  38. //没有指定类型,默认为Object
  39. //建议直接写成IUsb<Object,Object>
  40. class CC implements IUsb{//等价class CC implements IUsb<Object,,Object>
  41.     @Override
  42.     public Object get(Object o) {
  43.         return null;
  44.     }
  45.     @Override
  46.     public void hi(Object o) {
  47.     }
  48.     @Override
  49.     public void run(Object r1, Object r2, Object u1, Object u2) {
  50.     }
  51. }
  52. interface IUsb<U,R>{
  53.     //普通方法中,可以使用接口泛型
  54.     R get(U u);
  55.     void hi(R r);
  56.     void run(R r1,R r2,U u1,U u2);
  57.     //在jdk8中,可以在接口中,使用默认方法,也是可以使用泛型
  58.     default R method(U u){
  59.         return null;
  60.     }
  61. }
复制代码
自定义泛型方法

语法
  1. 修饰符 <T,R...>返回类型 方法名(参数列表){
  2. }
复制代码
注意事项:
1.泛型方法,可以定义在普通类中,也可以定义在泛型类中
2.当泛型方法被调用时,类型会确定
3.public void eat(E e){},修饰符后设有eat方法不是泛型方法,而是使用了泛型
  1. public class CustomMethodGeneric {
  2.     public static void main(String[] args) {
  3.         Car car = new Car();
  4.         car.fly("宝马",100);//当调用方法时,传入参数,编译器,就会确定类型
  5.         System.out.println("==================");
  6.         Fish<String, ArrayList> fish = new Fish<>();
  7.         fish.hello(new ArrayList(),11.3f);
  8.     }
  9. }
  10. //泛型方法,可以定义在普通类中,也可以定义在泛型类中
  11. class Car{//普通类
  12.     public void run(){//普通方法
  13.     }
  14.     //泛型方法
  15.     //1.<T,R>就是泛型
  16.     //2.是提供给 fly使用的
  17.     public <T,R> void fly(T t,R r){//泛型方法
  18.         System.out.println(t.getClass());
  19.         System.out.println(r.getClass());
  20.     }
  21. }
  22. class Fish<T,R>{//泛型类
  23.     public <U,M> void eat(U u,M m){//泛型方法
  24.     }
  25.     //下面的这个hi方法不是泛型方法,是hi方法使用了类声明的泛型
  26.     public void hi(T t){
  27.     }
  28.     //泛型方法,可以使用类声明的泛型,也可以使用自己声明泛型
  29.     public <K> void hello(R r,K k){
  30.         System.out.println(r.getClass());
  31.         System.out.println(k.getClass());
  32.     }
  33. }
复制代码
泛型的继承和通配符

说明:
1.泛型不具备继承性
2.:支持任意泛型类型

3.
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

钜形不锈钢水箱

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表