泛型的使用

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.总结

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值