zoukankan      html  css  js  c++  java
  • javaSE(九)之泛型(Generics)

    前言

    这几天分享了怎么搭建集群,这一篇给大家介绍的是泛型,在我们的很多java底层的源代码都是有很多复杂的泛型的!那什么是泛型呢? 

    泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法

    Java语言引入泛型的好处是安全简单。在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求

    开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。

    泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。那废话不多说,我们进入正题:

    一、泛型的简介

    1.1、泛型概述

      泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type),也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型
      这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。
      泛型的类型将来传入是只能是引用类型的,不能是基本类型的

    //编译通过    List<String>    List<Action>    List<Integer>    List<Integer[]>    List<int[]>
     //编译报错    List<int>

    1.2、泛型特点

      java中的泛型只是在编辑期间起作用的,在运行时会把泛型信息擦除的

            只是在编译期间启动类型安全检查的作用,运行时不起作用

            例如:List<String> list = new ArrayList<String>();

            虽然指定了泛型为String,但是在运行时候依然是可以向该list中存放其他类型数据的。(比如使用反射的方法)

    二、泛型类

    一个泛型类就是具有一个或多个类型变量(把类型参数化)的类
    定义一个泛型类十分简单,只需要在类名后面加上<>,再在里面加上类型参数.

    注:类型变量使用大写形式,且比较短,这是很常见的。在JDK中,使用变量E表示集合的元素类型,K和V分别表示关键字与值的类型。(需要时还可以用其他的字母,也可以是一个或多个字母)

    举例1:

            这里的T是根据将来用户使用Point类的时候所传的类型来定

    public class Point<T> {
                private T x;
                private T y;
                public T getX() {
                    return x;
                }
                public void setX(T x) {
                    this.x = x;
                }
                public T getY() {
                    return y;
                }
                public void setY(T y) {
                    this.y = y;
                }
            }         

      当我们创建一个对象为:Point<Double> p = new Point<Double>(); ,这里的T就代表的是double。

    举例2:

         这里的T和S是根据将来用户使用Point类的时候所传的类型来定

    public class Point<T,S> {
                private T x;
                private S y;
                public T getX() {
                    return x;
                }
                public void setX(T x) {
                    this.x = x;
                }
                public S getY() {
                    return y;
                }
                public void setY(S y) {
                    this.y = y;
                }
            } 

       当我们创建一个对象为:Point<String,Integer> p = new Point<String,Integer>();  ,这个的T是String,S是Integer类型的。

    三、泛型接口

    一个泛型接口就是具有一个或多个类型变量的接口。   

    举例: 

    public interface Action<T,U>{  
                void doSomeThing(T t,U u);  
            }  
    
            public class ActionTest implements Action<String,Date>{  
                public void doSomeThing(String str,Date date) {  
                    System.out.println(str);  
                    System.out.println(date);  
                }  
            }            

    四、泛型方法

    泛型方法就是在方法上直接声明泛型

    public class Test{
                public <T> void run1(T t){
                
                }
    
                public <T> T run2(T t){
                    return t;
                }
    
                public <T,S> void run3(T t,S s){
            
                }
            }

    五、通配符

      泛型增加了java中类型的复杂性,例如List<String>、List<Integer>、List<Object>等这些都是不同的类型。

    //编译报错
            //虽然 List list = new ArrayList(); 是正确的
            //虽然 Object是String的父类型
            //但是下面代码编译时报错的,因为使用了泛型
            List<Object> list = new ArrayList<String>(); 

      泛型中?是通配符,它可以表示所有泛型的父类型,集合元素可以是任意类型,这种没有意义,一般是方法中,只是为了说明用法。
          List<?> list = new ArrayList<任意>();

    //这时list可以指向任何泛型的List类型集合对象
            public void test(List<?> list){
                //编译报错,因为我们并不知道?到底代表什么类型
                list.add(1);
    //编译通过 for(Object o:list){ System.out.println(o); } }

       注:通配符?只能用在泛型变量声明的时候

    六、泛型中的extends和super关键字

    在泛型中可以使用extends和super关键字来表示将来用户所传的泛型参数的上限和下限

    6.1、extends关键字的使用

            举例1:在声明泛型类和泛型接口时使用extends

    public class Point<T extends Number> {
                private T x;
                private T y;
            }
    
            public class Point<T extends Number,S> {
                private T x;
                private S y;
            }
    
            public interface Action<T extends Person> {
                public void doSomeThing(T t);
            }
            
            例如:在声明泛型方法时使用extends
            public <T extends Action> void run(T t){
            
            }         

      举例2:在声明泛型方法时使用extends

    public <T extends Action> void run(T t){
            }        

      举例3:在声明泛型类型变量时使用extends

    List<? extends Number> list = new ArrayList<Integer>();
            List<? extends Number> list = new ArrayList<Long>();
            List<? extends Number> list = new ArrayList<Double>();
            //编译报错
            List<? extends Number> list = new ArrayList<String>();
            
            例如:
            public void test(List<? extends Number> list){
            
            }     

    6.2、super关键字的使用

      举例1:   

    //编译报错
            //声明泛型类或泛型接口时不能使用super
            public class Point<T super Number> {
        
            }
            public interface Action<T super Number> {
        
            }
    
            //编译报错
            //声明泛型方法时不能使用super
            public <T super Action> void run2(T t){
            
            }     

      举例2:在声明泛型类型变量时使用super

    //编译通过
            List<? super Number> list1 = new ArrayList<Object>();
            List<? super Student> list2 = new ArrayList<Object>();
            List<? super Student> list3 = new ArrayList<Person>();
    
            //编译通过
            public void test(List<? super Number> list){
            
            }
            
            //编译通过
            public void test(List<? super Student> list){
            
            }

    总结:

      ArrayList<T> al=new ArrayList<T>();指定集合元素只能是T类型
      ArrayList<?> al=new ArrayList<?>();集合元素可以是任意类型,这种没有意义,一般是方法中,只是为了说明用法
      ArrayList<? extends E> al=new ArrayList<? extends E>();
      泛型的限定:
        ? extends E:接收E类型或者E的子类型。
        ?super E:接收E类型或者E的父类型。

    七、泛型中的&

    使用&可以给泛型加多个限定  

        public class A{
        
            }
            public inerface B{
                
            }    
            //不管该限定是类还是接口,统一都使用关键字extends
            //可以使用&符号给出多个限定
            //如果限定既有接口也有类,那么类必须只有一个,并且放在首位置
            public class Point<T extends A&B> {    
            }
    
            class Sub extends A implements B{}
            main:
                //编译报错
                Point<A> p = new Point<A>();
                Point<B> p = new Point<B>();
        
                //编译通过
                Point<Sub> p = new Point<Sub>();    

    总结:我们可以观察API中的Map接口及其方法的声明

    public interface Map<K,V>{
    			public V get(Object key);
    			public Set<Map.Entry<K,V>> entrySet();
    			public Set<K> keySet();
    			public void putAll(Map<? extends K,? extends V> m);
    			..
    		}   
    

      

    觉得不错的点个“推荐”哦!

  • 相关阅读:
    SysTick—系统定时器
    FreeRtos——单任务
    binutils工具集之---objdump
    对连接器的思考
    数组和指针并不相同
    typedef可以成为你的朋友
    gcc,一个神奇的编译器
    FreeRtos——移植
    Makefile 13——理解make的解析行为
    Makefile 12——改善编译效率
  • 原文地址:https://www.cnblogs.com/zhangyinhua/p/7570184.html
Copyright © 2011-2022 走看看