JAVA泛型

一:泛型概念

泛型就是参数化类型

  • 适用于多种数据类型执行相同的代码

  • 泛型中的类型在使用时指定

  • 泛型归根到底就是“模版”

优点:使用泛型时,在实际使用之前类型就已经确定了,不需要强制类型转换。

二:命名规则

JDK 中文档经常能看到T、K、V、E、N等类型参数,而我们在编写泛型相关代码时,这些符号都可以随意使用,实际上还可以使用 JDK 文档中从来没用过的符号,如A、B、C等,但却极力不推荐这样做

JDK 文档中各符号的含义:

  • T:类型

  • K:键

  • V:值

  • E:元素(如集合类中的元素全部用该符号表示)

  • N:Number

三:自定义泛型

1:泛型类

public class Generic {

    private T key ;

    public Generic(T key) {

        this.key = key;

    }

    public T getKey(){

        return key;

    }

}
 测试
Generic  stringGeneric = new Generic<>("haha");

Generic integerGeneric = new Generic<>(123);

System.out.println(stringGeneric.getKey());

System.out.println(integerGeneric.getKey());

结果:

haha

123
在这个泛型类使用的时候,传入实参的话就在初始化的时候限制了类型,编译器会自动识别,如果不符合,会出现错误。
JAVA泛型_第1张图片
image.png

当然我们也可以不使用实参

Generic t1 = new Generic(234);

Generic t2 = new Generic("aaa");

Generic t3 = new Generic(false);

System.out.println(t1.getKey()+"=="+t2.getKey()+"=="+t3.getKey());

结果:

234==aaa==false

2:泛型接口

public interface Generator {

     T next();

}

实现泛型接口

//实现泛型类的时候,没有传入实参,类本身也需要声明泛型,否则会报错

class FruitGenerator implements Generator{

    @Override

    public T next() {

        return null;

    }

}

//

class FruitGenerator1 implements Generator{

    @Override

    public Object next() {

        return null;

    }

}

class FruitGenerator2 implements Generator{

    @Override

    public String next() {

        return null;

    }

}

3:泛型方法

在上述泛型类的例子中

//此方法并不是泛型方法,只是返回值是在声明泛型类的时候已经声明过的泛型

public T getKey(){

        return key;

    }

泛型方法例子

public class Gen {

    //此方法也不是泛型方法,只是使用了泛型参数

    public void show_1(T t){

        System.out.println(t.toString());

    }

    //**该泛型方法中的T泛型和泛型类中T是两种不同的类型**

    public  void show_2(T t){

        System.out.println(t.toString());

    }

    //在泛型方法中声明了泛型E,因此,在参数中可以使用E,即使泛型类中没有声明该泛型

    public  void show_3(E e){

        System.out.println(e.toString());

    }

}

测试

public static void main(String[] args){

    Apple apple = new Apple();

    Person person = new Person();

    Gen g1 = new Gen<>();

    g1.show_1(apple);

    //该调用编译器会报错,因为g1在初始化的时候已经声明泛型为实际参数Apple了,show_1方法会使用泛型类传入的实际参数,因此person类型不匹配

    //g1.show_1(person);

    g1.show_2(apple);

    g1.show_2(person);

    g1.show_3(person);

    g1.show_3(apple);

}

结果:

Apple{}

Apple{}

Person{}

Person{}

Apple{}

四:泛型的边界

public static void test(Generic obj){

    System.out.println(obj.getClass());

}

Generic f1 = new Generic<>(123f);

Generic integerGeneric = new Generic<>(123);

Generic  stringGeneric = new Generic<>("aaa");

GenericTest.test(integerGeneric);

GenericTest.test(f1);

//GenericTest.test(stringGeneric);

结果

class com.ren.practise.generic.Generic

class com.ren.practise.generic.Generic

上述注释掉的内容会报如下错误:

JAVA泛型_第2张图片
image.png

五:泛型通配符

public static void setKeyValue(Generic obj){

    System.out.println(obj.getClass());

}

Generic n1 = new Generic(123);

Generic n2 = new Generic<>(123);

setKeyValue(n1);

//setKeyValue(n2);

结果:

class com.ren.practise.generic.Generic

上述注释掉的内容会报如下错误:

JAVA泛型_第3张图片
image.png

使用通配符

public static void setKeyValue(Generic obj){

    System.out.println(obj.getClass());

}

Generic n1 = new Generic(123);

Generic n2 = new Generic<>(123);

setKeyValue(n1);

setKeyValue(n2);

结果:

class com.ren.practise.generic.Generic

class com.ren.practise.generic.Generic

? 可以当做一种特殊的实际参数

六:泛型特性

ArrayList a2 = new ArrayList<>();

ArrayList a3 = new ArrayList<>();

Class c1 = a2.getClass();

Class c2 = a3.getClass();

System.out.println(c1.equals(c2));

结果:

true

泛型只在编译期有效,编译过程中,如果检查正确,会将泛型相关信息擦除。

你可能感兴趣的:(JAVA泛型)