• java泛型的理解


    最近在看视频,看到比较经典的比大小问题。输入两个数,返回大的数,类型可以为int,long,float等。

    通常的教程中用这个例子引入了构造函数以及重载的概念,在学习完泛型后,我想到能不能写一个泛型的方法,用以实现比较。

    为了完成这个任务,我们首先需要了解一下泛型。

    什么的泛型

    泛型是java语言系统的一种扩展,支持创建可以按照类型进行参数化的类。

    泛型的好处

    泛型的好处也是显而易见的,

    首先可以扩充代码的通用性,通过泛型可以使方法支持更多的类型。

    泛型有助于增强类型安全,编译器可以对类型进行比较准确的解读。

    泛型有助于减少类型强制转换,减少出错机会。

    我们需要掌握泛型哪些用法

    需要掌握泛型接口、泛型类、泛型类中泛型方法、非泛型类中泛型方法、类型通配符、类型通配符的上下限这几个用法。

    泛型接口

    泛型接口的一个比较好的例子是java.util.List.class,<E>中的E为类型形参,可以接收具体类型的实参。接口中出现E的地方,均为接收到的具体类型的实参。

    package java.util;
    
    public abstract interface List<E> extends Collection<E>
    {
      public abstract int size();
    
      public abstract boolean isEmpty();
    
      public abstract boolean contains(Object paramObject);
    
      public abstract Iterator<E> iterator();
    
      public abstract Object[] toArray();
    
      public abstract <T> T[] toArray(T[] paramArrayOfT);
    
      public abstract boolean add(E paramE);
    
      public abstract boolean remove(Object paramObject);
    
      public abstract boolean containsAll(Collection<?> paramCollection);
    
      public abstract boolean addAll(Collection<? extends E> paramCollection);
    
      public abstract boolean addAll(int paramInt, Collection<? extends E> paramCollection);
    
      public abstract boolean removeAll(Collection<?> paramCollection);
    
      public abstract boolean retainAll(Collection<?> paramCollection);
    
      public abstract void clear();
    
      public abstract boolean equals(Object paramObject);
    
      public abstract int hashCode();
    
      public abstract E get(int paramInt);
    
      public abstract E set(int paramInt, E paramE);
    
      public abstract void add(int paramInt, E paramE);
    
      public abstract E remove(int paramInt);
    
      public abstract int indexOf(Object paramObject);
    
      public abstract int lastIndexOf(Object paramObject);
    
      public abstract ListIterator<E> listIterator();
    
      public abstract ListIterator<E> listIterator(int paramInt);
    
      public abstract List<E> subList(int paramInt1, int paramInt2);
    }

    泛型类

    泛型类的定义方法类似于接口

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        private static final long serialVersionUID = 8683452581122892189L;
    
        /**
         * The array buffer into which the elements of the ArrayList are stored.
         * The capacity of the ArrayList is the length of this array buffer.
         */
        private transient Object[] elementData;
    
        public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
        }
        
        public E set(int index, E element) {
        RangeCheck(index);
    
        E oldValue = (E) elementData[index];
        elementData[index] = element;
        return oldValue;
        }    
    }

    泛型类中泛型方法

    以上文中set方法为例,使用时,直接用E表示其代表的类型实参。

    非泛型类中泛型方法

    泛型的声明需要在方法修饰符之后,返回值之前。

    class test{
        public <T> void paly(T a){
            System.out.println(a.getClass());
        }
    }

    类型通配符

    通过下面的测试方法可以比较好的反应出类型通配符的使用方法:

    Box.java

    public class Box<T>{
    
        private T box;
        
        public T getBox() {
            return box;
        }
    
        public void setBox(T box) {
            this.box = box;
        }
    
        public Box(T a) {
            setBox(a);
        }
    
    }

    BoxMain.java

    public class BoxMain {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            Box<Integer> test1 = new Box<Integer>(111);
            Box<String> test2 = new  Box<String>("aaa");
            
            show3(test1);
            show4(test2);
            
            show1(test1);
            show1(test2);
            
            show2(test1);
            show2(test2);
        }
        
        public static <T> void show1(Box<T> a){
            System.out.println(a.getBox());        
        }
        
        public static void show2(Box<?> a){
            System.out.println(a.getBox());    
        }
        
        public static void  show3(Box<Integer> a) {
            System.out.println(a.getBox());
        }
        
        public static void  show4(Box<String> a) {
            System.out.println(a.getBox());
        }
    }

    其中,show1方法是非泛型类中的泛型方法,show2用了类型通配符,show3和show4是什么都没有用的情况。可以看出,使用类型通配符可以取代show3和show4方法,比较方便。

    类型通配符的上下限

    在该使用类型通配符的地方,如果需要考虑其类型的安全,我们有时需要提出这样的限制:类型通配符代表的类型需要有一个限制,如,必须是Test或者Test的子类,必须是Test或者Test的父类等。

    这里就用到了

    ? extends Test

    ? super Test

    这两种写法,其中? extends Test表示必须是Test或者Test的子类,称为类型通配符的上限。

    ? super Test表示必须是Test或者Test的父类,称为类型通配符的下限。

    至此,我们完成了泛型的学习,下面我们完成一开始提出的问题,用泛型比较大小。

    ReturnBig.java

    package com.fan;
    
    public class ReturnBig <T extends Comparable<T>>{
        public T a;
        public T b;
        
        public T getA() {
            return a;
        }
        public void setA(T a) {
            this.a = a;
        }
    
        public T getB() {
            return b;
        }
        public void setB(T b) {
            this.b = b;
        }
        public int compareTo(T o) {
            return a.compareTo(o);
        }
        
        public ReturnBig(T a,T b){
            setA(a);
            setB(b);
        }
        
        public T returnBigT(){
            if (compareTo(b)>0) {
                return a;
            }else{
                return b;
            }
        }
    }

    FanMain.java

    package com.fan;
    
    public class FanMain {
    
    
        public static void main(String[] args) {
            //比较大小相对而言限制的比较多一点,如果是判等,简单的多。
            ReturnBig<Integer> returnBig = new ReturnBig<Integer>(11,22);
            System.out.println("the big num is:" + returnBig.returnBigT());
            
            ReturnBig<Float> returnBig1 = new ReturnBig<Float>(11.11f,22.11f);
            System.out.println("the big num is:" + returnBig1.returnBigT());
        }
        
    }

    这里用到了Comparable接口,需要注意的是实现Comparable接口的类是有限的,随便两个对象的比较本身也是没有意义的事。只有特定类型的比较才有意义。

  • 相关阅读:
    springboot启动后执行某些动作
    Virtualbox的nat网络
    xshell6
    day01 K8S
    Nginx的日志文件切割
    virtualbox磁盘空间大小调整
    装修柜子木台面
    mybatis 批量in 多个字段写法
    jenkins shell常用配置
    activiti工作流引擎数据库表结构
  • 原文地址:https://www.cnblogs.com/wee616/p/4792261.html
Copyright © 2020-2023  润新知