泛型的使用

  • Post author:
  • Post category:其他




1. 什么是泛型

​ 泛型,即“参数化类型”,将参数的类型泛化。在声明时不指定参数类型,根据传入的实际参数的类型来决定。是jdk1.5的特性

泛型可以随便写,但默认的规则为:

  1. E—Element,常用在Java的集合中
  2. K,V—–key,value 代表Map中的键值对
  3. N—–Number 代表数字
  4. T—-Type 类型,如String,Integer等等

注意:基本数据类型不能作为泛型

​ 在集合中不使用泛型时,可以存储任意类型的

对象

,集合中的元素是对象。

泛型在编译期有效,可以

动态修改参数类型

,泛型的底层主要是通过list源码来实现的。

 public static void main(String[] args) {
        List<String> list=new ArrayList();
        List<Double> list2=new ArrayList();
        //通过反射获取class文件
        Class aClass = list.getClass();
        Class aClass1 = list.getClass();
        System.out.println(aClass.equals(aClass1));
    }
//输出结果为true,由此可得泛型只在编译期有效,相同的代码,不同的泛型编译以后的class文件相同



2. 泛型的使用方式

泛型的使用方式有三种分别为:泛型类、泛型接口、泛型方法。



泛型类

主要规范类型的类型,一个类可以有多个泛型。

public class tyuio<S,N,E>{
    private S name;
    private N age;
    public tyuio(S name, N age) {
        this.name = name;
        this.age = age;
    }
    public S getName() {
        return name;
    }
    public void setName(S name) {
        this.name = name;
    }
    public N getAge() {
        return age;
    }
    public void setAge(N age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "tyuio{" +
                "name=" + name +
                ", age=" + age +
                '}';
    }
    public static void main(String[] args) {
        tyuio t=new tyuio<String,Integer,String>("123",4);//在实例化对象时,可指定泛型,也可不指定泛型。
        //若在实例化时要指定泛型的参数,则必须全部指定,不能部分指定
        System.out.println(t);
    }
}
//编译后的代码为
public static void main(String[] paramArrayOfString)
  {
    tyuio localtyuio = new tyuio("123", Integer.valueOf(4));//此处没有了泛型,且对象名与设定的不同,对4进行了装箱操作转为Integer类型的一个对象
    System.out.println(localtyuio);
  }
}



泛型接口

创建方式与泛型类相同。

public interface qwr<T> {
    public void eat(T name);
}
class tyuio implements qwr{
    public static void main(String[] args) {

    }
    @Override
    public void eat(Object name) {

    }
}
class tyuio implements qwr<String>{
    public static void main(String[] args) {

    }
    @Override
    public void eat(String name) {

    }
}

//编译后的代码都为
class 
{
} 
class tyuio
  implements qwr
{
  public static void main(String[] paramArrayOfString)
  {
  }

  public void eat(Object paramObject)
  {
  }
}



在使用泛型类和泛型接口时需注意

  1. 泛型类和接口主要在继承和实现时使用。

  2. 未传入泛型的实参时,与泛型类定义的相同,在声明类时,需要将泛型的声明也一起加到类中

    class a<T>{
        public void eat(Object name) {
    //        return null;
        }
    }
    class b<T> extends a<T>{
        public static void main(String[] args) {
            b w=new b();
        }
    }
    
  3. 接口和类在被继承的时候指定具体的类型,子类将不需要泛型,但所有在接口和父类中使用泛型的地方都要替换成传入的实参类型

    class a<T>{
        public T eat(T name) {
            return null;
        }
    }
    class b extends a<String>{
        //即b可以不使用泛型,在a中使用泛型的地方都变为了String
        @Override
        public String eat(String name) {
            return null;
        }
    
        public static void main(String[] args) {
            b w=new b();
        }
    }
    
    public interface qwr<T> {
        public T eat(T name);
    }
    public class tyuio implements qwr<Integer>{
    
    
        @Override
        public Integer eat(Integer name) {
            return null;
        }
    
        public static void main(String[] args) {
            tyuio t=new tyuio();
        }
    }
    



泛型方法

一个方法由于传入的参数不同,最终输出的结果也不同。

在泛型方法中 :代表声明此方法为泛型方法,类型为T, F :代表方法的返回值类型

表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。

class a{   //方法的返回值类型
    public <F> F eat(String name) {
       //泛型方法
       return null ;
    }
}



基本用法

class a<T> {
    //此类是一个泛型类
    private T name;

    /*此方法不是泛型方法,因为没有<T>,它是一个普通的成员方法,
    因为泛型类已经声明了泛型T,所以此处的T可以使用,该方法的返回值类型为T类型
    */
    public T getName(T d) {
        return name;
    }
   /*d
   下列方法是错误的,因为类的声明中并未声明泛型B,泛型B在作为返回值和形参时无法被编译器识别。
   public B getName(B d) {
        return name;
    }*/

    public void setName(T name) {
        this.name = name;
    }

    /*下列方法为一个泛型方法,主要体现在使用了<T>,<T>表明该方法为一个泛型方法,并且声明了一个泛型T,T可以出现在任意位置,需注意的是此处的T与泛型类中声明的T是不同类型的*/
    public <T> T lok(a<T> name) {
        T d = null;
        return name.getName(d);
    }
    /*此方法正确,E在public 后被声明(方法声明是被声明),所以即使泛型类中未声明也可以在该方法中可以使用,编译器也能正确识别泛型方法中的泛型
    
    */
    public <E> E lok(E name) {
        E d = null;
        return d;
    }

   /*
   此方法错误因为此方法只是声明了泛型E并未声明N
   public <E> E lok(N name) {
       E d = null;
       return d;
   }*/

   /*
   此方法错误,对于编译器来说N并没有在项目中被声明过,因此编译器不知道如何编译N
   所以此方法不是一个正确的泛型方法的声明
   public  void  lok(N name) {

   }
   */

}



泛型方法与可变参数

  public void d(T...arg){
       for (T t:arg) {
           System.out.println(t);  
       }
  }



静态方法与泛型

需注意:静态方法无法访问类上定义的泛型。如果静态方法操作的引用数据不确定的时候,必须要将泛型定义在方法上。即

如果静态方法要是用泛型的话,必须将静态方法定义为泛型方法。

class o<T>{
    
    public static  void d(T...arg){
        System.out.println(arg);
    }
//此方法会报错,在静态方法中使用泛型时,无论该泛型类型是否在泛型类中声明,必须将静态方法设定为泛型方法。
    public static <T> void d2(T...arg){
        System.out.println(arg);
    }
//此静态方法使用的泛型正确
    public static void main(String[] args) {
        d();
        d2();
    }
}



泛型的通配符和上下限

通配符一般是用

?

代替具体的类型参数。



说明

  1. 在实例化对象的时候,不确定泛型参数的具体类型时,可以使用通配符进行对象定义

  2. ?

    表示不限定通配符,通常与集合配合使用
  3. 集合中所用类型,不继承父子关系。如:Base是基类,Child为子类,则List和List不具备继承关系,并且而这没有任何关系

  4. <? extends T>

    称为上限通配符,表示T类型及其T子类

  5. <? super T>

    称为下限通配符,表示T类型及其父类



创建对象时的通配符(new 集合时)

有时候在创建集合时,并不知道集合中要存放的数据是什么,所以就会使用到通配符,案例见:–上限通配符

<? extends T>

–和–下限通配符

<? super T>



无限定通配符<?>

  1. 通常与集合配合使用
  2. 集合中的限定类型,表示集合中只能包含一种类型;不限定类型,表示不限定任何类型。

    一旦集合转为不限定类型,不可以向集合中添加数据,只能进行查询集合长度、判断集合是否为空等一些与集合中数据的类型无关的一些操作。
  3. 通常与

    <? extends T>



    <? super T>

    配合使用
class o{
    public static void main(String[] args) {
        List l=new ArrayList();
        l.add("123");
        l.add("as");
        l.add("aca");
        List <?> l1=l;
        
        l1.add("123");//此处会编译报错,因为一旦集合转为不限定类型,不可以向集合中添加数据
        
        System.out.println(l1.size());
        System.out.println(l1.isEmpty());
        List<String> l2=new ArrayList();
        l2.add("2345");
        l2.add("345");
        System.out.println(l2.size());
        System.out.println(l2.isEmpty());
        List<Double> l3=new ArrayList();
        l3.add(2.3);
        System.out.println(l3.size());
        System.out.println(l3.isEmpty());

    }
}



上限通配符

<? extends T>


<? extends T>

:表示的意思为T类型及其子类

  1. 表示规定范围的类型。比如

    <? extends T>

    :规定的类型是T类型及其子类
  2. 表示的集合不能添加元素。
class o{
    public static void main(String[] args) {
        List l=new ArrayList();
        l.add("123");
        l.add("as");
        l.add("aca");
        List <? extends String> l1=l;
//        l1.add("234"); 不可以添加元素
        l1.remove(2);
        Iterator iterator=l.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println(l1.size());
        System.out.println(l1.isEmpty());

    }
}



下限通配符

<? super T>


<? super T>

:表示T类型及其父类

  1. 表示规定范围的类型。
  2. 在集合中可以添加元素,也可以查询
class o{
    public static void main(String[] args) {
        List l=new ArrayList();
        l.add("123");
        l.add("as");
        l.add("aca");
        List <? super String> l1=l;
        l1.add("234");
//        l1.remove(2);
        Iterator iterator=l.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println(l1.size());
        System.out.println(l1.isEmpty());
        for (int i = 0; i < l1.size(); i++) {
            System.out.println(l1.get(i));
        }

    }
}



3.总结

泛型的提出只要是为了规范代码中的数据类型,防止在某些地方随便使用。有了泛型就不需要做类型转换了。



版权声明:本文为qq_46603402原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。