程序笔记   发布时间:2022-07-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了一文学懂Java泛型,详细而全面,值得收藏~大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

概述

作为一个面向对象的编程语言࿰c;Java可以通过实现一些类࿰c;作为我们各种需求的一个模板࿰c;便我们的使用。但有时候࿰c;这个类的范围可能比我们想要的范围要大࿰c;我们只想限定于满足类的某些对象࿰c;那这样的情况下࿰c;泛型的概念就被提出来了(非官方解释࿰c;便理解)。

举个例子:比如我们我们生活中的车࿰c;它可以作为一个类࿰c;但是车其实又有很多种࿰c;包括货车࿰c;轿车࿰c;大巴车等等࿰c;而其中的轿车外观差不多࿰c;但是又属于不同的品牌࿰c;这些品牌有很多不一样的地方࿰c;这里我们可以把轿车的品牌看作是泛型(类似于标签)

通过上面的解释࿰c;泛型的概念就比较清晰了࿰c;就是一种“类型参数”࿰c;所谓类型参数可以理解为将类型由原来的具体的类型进行参数化࿰c;类似于方法中的变量参数࿰c;此时类型也定义成参数形式(可以称之为类型形参)࿰c;然后在使用/调用时传入具体的类型(类型实参)。

泛型的优点࿰c;不仅仅是上面提到的࿰c;其还有下面的优点::

  • 类型安全: 提高Java 程序的类型安全(泛型的主要目标)。 通过知道使用泛型定义的变量的类型限制࿰c;编译器可以验证类型假设。
  • 消除强制类型转换:消除源代码中的许多强制类型转换。 这使得代码的可读性更高了࿰c;并且还减少了错误
  • @H_607_20@

    上面说到了泛型在类中的使用࿰c;其实泛型的使用远不止于此࿰c;其还可以在在接口、方法中使用。下面就对这些分别进行介绍

    泛型类

    所谓泛型类就是把当我们在声明类时࿰c;类中的有些成员的类型并不是确定࿰c;然后我们可以把泛型定义在类上࿰c;当使用该类的时候࿰c;再把不确定成员的类型明确下来。

    语法格式

    【修饰符】 class 类名<类型变量列表>{
    	//类体
    }
    

    注: <类型变量列表>:可以是一个或多个类型变量࿰c;一般都是使用单个的大写字母表示。例如:、<K,V>等。

    <类型变量列表>中的类型变量不能用于静态成员上。

    泛型类的使用

    使用这种类似于参数化类型的类时࿰c;在创建类的对象时候࿰c;我们需要注意

    • 指定类型变量对应的实际类型参数
    • 实际类型参数必须是引用数据类型࿰c;不能是基本数据类型
    • @H_607_20@

      注:指定泛型实参时࿰c;必须左右两边一致࿰c;不存在多态现象(右边的可以省略不写)

      代码示例

      /*
          泛型类的声明与使用
       */
      
      public class Demo1 {
          public static void @H_229_87@main(@R_801_10495@ng[] args) {
      
              //泛型类的使用(<T>里面只能是引用类型)
              student<Double> student1 = new student<>("学生1",99.5);
              student<@R_801_10495@ng> student2 = new student<>("学生2","优秀");
              student<Character> student3 = new student<>("学生3",'A');
      
      		//输出结果
      	    System.out.println(student1);
              System.out.println(student2);
              System.out.println(student3);
          }
      }
      
      //泛型类的声明
      class student<T> { //<T>这个就是泛型类的类型参数
          private @R_801_10495@ng name;
          private T score; //使用泛型࿰c;定义分数(分数可能有double类型(99.5)、字符串类型(优秀)、字符类型(‘a’)等)
      
          //构造方法
          public student() {
          }
      
          public student(@R_801_10495@ng name, T score) {
              this.name = name;
              this.score = score;
          }
      
          @Override
          public @R_801_10495@ng to@R_801_10495@ng() {
              return "student{" +
                      "name='" + name + ''' +
                      ", score=" + score +
                      '}';
          }
      
      }
      

      泛型接口

      泛型接口和泛型类关系࿰c;就像接口和类的关系一样。 这里不多说。

      语法格式

      【修饰符】 interface 接口名<类型变量列表>{
           
      }
      

      注: <类型变量列表>:可以是一个或多个类型变量࿰c;一般都是使用单个的大写字母表示。例如:、<K,V>等。

      <类型变量列表>中的类型变量不能用于静态成员上。

      泛型接口的使用

      使用这种类似于参数化类型的接口时࿰c;我们需要注意

      • 指定类型变量对应的实际类型参数
      • 实际类型参数必须是引用数据类型࿰c;不能是基本数据类型
      • @H_607_20@

        代码示例

        /*
            泛型接口的声明与使用
         */
        
        public class Demo1 {
            public static void @H_229_87@main(@R_801_10495@ng[] args) {
        
                //泛型类的使用(<T>里面只能是引用类型)
                student<Double> student1 = new student<>("学生1",99.5);
        
                //使用泛型接口
                student1.print("学生1",99.5);
            }
        }
        
        //泛型类的声明
        class student<T> implements Print<@R_801_10495@ng,T>{ //<T>这个就是泛型类的࿰c;后面<@R_801_10495@ng,T>是接口࿰c;多个类型变量
            private @R_801_10495@ng name;
            private T score; //使用泛型
            //构造方法
            public student() {
            }
        
            public student(@R_801_10495@ng name, T score) {
                this.name = name;
                this.score = score;
            }
        
        
        
            //重写接口的方法
            @Override
            public void print(@R_801_10495@ng s, T t) {
                System.out.println("学生姓名:"+ this.name);
                System.out.println("学生成绩:"+ this.score);
            }
        }
        
        //泛型接口的声明
        interface Print <T,V>{
            //定义一个打印函数࿰c;可以打印学生姓名和成绩
            public void print(T t, V v);
        
        }
        

        类型变量的上限和下限

        前面说到࿰c;我们可以使用泛型类型参数࿰c;这样等我们进行实际使用的时候c;我们可以任意使用类型࿰c;但如果想只使用某一系列的类型࿰c;泛型也是可以实现的。这就是我们说的类型变量的上限和类型变量的下限。下面进行分别介绍。

        类型变量的上限

        如果泛型类定义了类型变量的上限࿰c;那么该泛型类实际的类型只能是该上限类型或者其子类类型。

        语法格式

        泛型类和泛型方法的用法是一样的࿰c;后面都不再做区分。

        <类型变量  extends 上限1 & 上限2> //上限可以有多个
        

        注:如果多个上限中有类有接口࿰c;那么只能有一个类࿰c;而且必须写在最左边。接口的话࿰c;可以多个。 如果在声明<类型变量>时没有指定上限࿰c;默认上限是java.lang.object。

        代码示例

        /*
            类型变量的上限
         */
        
        public class Demo2 {
        
            public static void @H_229_87@main(@R_801_10495@ng[] args) {
                Test<Double> test1 = new Test<>(77.5); //double类
        //        Test<@R_801_10495@ng> test2 = new Test<@R_801_10495@ng>(); 不是数字类的子类
                Test<Integer> test3 = new Test<>(18);
        
                test1.print(77.5);
                test3.print(18);
            }
        }
        
        class Test<T extends number >{ //数字类上限࿰c;只能使用数字类及其子类
            private T num;
        
            public Test() {
            }
        
            public Test(T num) {
                this.num = num;
            }
        
            public void print(T num){ //测试方法
                System.out.println(num);
            }
        }
        

        类型变量的下限

        如果泛型类定义了类型变量的下限࿰c;那么该泛型类实际的类型只能是该下限类型或者其父类类型。

        语法格式

        <?  super E > // ? 代表接收E类型或者E的父类型的元素
        

        ? 是泛型类中的通配符(下面会讲到࿰c;可以先看下面的再回来看这个)

        代码示例

        /*
            <? super 下限>
         */
        
        public class Demo5 {
            public static void @H_229_87@main(@R_801_10495@ng[] args){
                C<@R_801_10495@ng> c=new C<>();
                c.setT("<? super 下限>");
                fun1(c);
        
            }
        
         	  //测试函数࿰c;泛型类使用了下限
            public static void fun1(C<? super @R_801_10495@ng> c){ 	 //接受的数据类型只能为@R_801_10495@ng、Object
           
                System.out.println(c.getT()); //输入测试
            }
        }
        
        class C<T>{
        
            private T t;
        
            public T getT() {
                return t;
            }
            public void setT(T t) {
                this.t = t;
            }
        }
        
        

        泛型方法

        鉴于某个方法定义时࿰c;想要自己定义类型变量或者在某个静态方法中定义类型变量的需求࿰c;JDK还提供了泛型方法的支持。即可以在某个方法定义时࿰c;自定以<类型变量>

        注:前面说到类和接口上的类型形参是不能用于静态方法

        语法格式

        【修饰符】 <类型变量列表> 返回值类型 方法名(【形参列表】)throws 异常列表】{
            //方法体
        }
        

        注:- <类型变量列表>:可以是一个或多个类型变量࿰c;一般都是使用单个的大写字母表示。例如: < T >、<K,V>等。 <类型变量>同样也可以指定上限

        代码示例

        /*
            泛型方法
         */
        
        public class Demo3 {
            public static void @H_229_87@main(@R_801_10495@ng[] args) {
                Test1 test = new Test1(); //创建测试对象
        
                test.print(12); //测试
                test.print(12.5); //测试
        
            }
        }
        
        class Test1{
        
            public <T extends number> void print(T t){ //泛型方法࿰c;可以设置上限
                System.out.println("这是一个泛型方法࿰c;测试类型:" + t);
            }
        }
        

        泛型擦除

        泛型擦除只是在编译阶段才会有的࿰c;在实际运行阶段类型已经确定了࿰c;这个时候就没有泛型的概念了(JVM并不知道泛型的存在)。这个从有泛型信息到没有泛型信息的过程称之为“泛型擦除”。

        其擦除规则如下:

        • 若泛型类型没有指定具体类型࿰c;用Object作为原始类型;
        • 若有限定类型< T exnteds XClass >࿰c;使用XClass作为原始类型;
        • 若有多个限定< T exnteds XClass1 & XClass2 >࿰c;使用第一个边界类型XClass1作为原始类型;
        • @H_607_20@

          类型通配符

          通配符的意思是可以指代很多类型。这个主要使用在当我们在声明方法时࿰c;不确定该泛型实际类型的情况。类型通配符有三种:

          • <?> 任意类型
          • <? extends 上限>
          • <? super E>
          • @H_607_20@

            下面对这三种通配符分别进行介绍

            <?> 任意类型

            当泛型使用这种 类型通配符的时候࿰c;表示可以使用任意类型

            代码示例

            /*
                类型通配符
             */
            
            public class Demo4 {
            
                public static void @H_229_87@main(@R_801_10495@ng[] args) {
                    // 语文老师使用时:
                    studenTinfo<@R_801_10495@ng> stu1 = new studenTinfo<@R_801_10495@ng>("张三", "良好");
            
                    // 数学老师使用时:
                    studenTinfo<Double> stu2 = new studenTinfo<Double>("张三", 90.5);
            
                    // 英语老师使用时:
                    studenTinfo<Character> stu3 = new studenTinfo<Character>("张三", 'C');
            
                    studenTinfo<?>[] arr = new studenTinfo[3]; //使用通配符
                    arr[0] = stu1;
                    arr[1] = stu2;
                    arr[2] = stu3;
            
                    studenTinfoPrint.print(arr); //打印输出结果
                }
            
            }
            
            
            //学生类是一个参数化的泛型类
            class studenTinfo<T>{
                private @R_801_10495@ng name;
                private T score;
            
                public studenTinfo() {
                    super();
                }
                public studenTinfo(@R_801_10495@ng name, T score) {
                    super();
                    this.name = name;
                    this.score = score;
                }
                @Override
                public @R_801_10495@ng to@R_801_10495@ng() {
                    return "姓名:" + name + ", 成绩:" + score;
                }
            }
            
            //学生信息打印类
            class studenTinfoPrint {
                //泛型方法࿰c;使用通配符
                public static void print(studenTinfo<?>[] arr) {
                    for (int i = 0; i < arr.length; i++) {
                        System.out.println(arr[i]);
                    }
                }
            }
            
            

            <? extends 上限>

            ? 代表接收E类型或者E的子类型的元素

            代码示例

            可参上面的类型变量的上限代码

            <? super E>

            ? 代表接收E类型或者E的父类型的元素

            代码示例

            可参上面的类型变量的下限代码

大佬总结

以上是大佬教程为你收集整理的一文学懂Java泛型,详细而全面,值得收藏~全部内容,希望文章能够帮你解决一文学懂Java泛型,详细而全面,值得收藏~所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。