首页 > 其他分享 >泛型(genericity)

泛型(genericity)

时间:2022-11-01 13:56:45浏览次数:37  
标签:last String Pair 泛型 genericity public first

泛型的概念

所谓泛型就是编写一种模板实现任意数据类型都可使用的目的,既实现了编写一次,万能匹配,又通过编译器保证了类型安全

向上转型

如下所示,ArrayList<T>实现了List<T>,所以ArrayList可以向上转型为List

public class ArrayList<T> implements List<T> {
    ...
}
// 由于ArrayList实现了List,所以如下代码不会报错
List<String> list = new ArrayList<String>();

注意泛型的继承关系:可以把ArrayList<Integer>向上转型为List<Integer>T不能变!),但不能把ArrayList<Integer>向上转型为ArrayList<Number>T不能变成父类),因为ArrayList<Integer>ArrayList<Number>是同一个对象

泛型使用

  • 使用泛型时,把泛型参数<T>替换为需要的class类型,例如:ArrayList<String>ArrayList<Number>等;
  • 可以省略编译器能自动推断出的类型,例如:List<String> list = new ArrayList<>();
  • 不指定泛型参数类型时,编译器会给出警告,且只能将<T>视为Object类型;
// sort
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        Person[] ps = new Person[] {
            new Person("Bob", 61),
            new Person("Alice", 88),
            new Person("Lily", 75),
        };
        Arrays.sort(ps);
        System.out.println(Arrays.toString(ps));
    }
}

// Person实现Comparable<T>接口
class Person implements Comparable<Person> {
    String name;
    int score;
    Person(String name, int score) {
        this.name = name;
        this.score = score;
    }
    public int compareTo(Person other) {
        return this.name.compareTo(other.name);
    }
    public String toString() {
        return this.name + "," + this.score;
    }
}

泛型的编写

过程

1、按照某种类型,例如:String,来编写类

public class Pair {
    private String first;
    private String last;
    public Pair(String first, String last) {
        this.first = first;
        this.last = last;
    }
    public String getFirst() {
        return first;
    }
    public String getLast() {
        return last;
    }
}

2、标记所有的特定类型,这里是String

public class Pair {
    private String first;
    private String last;
    public Pair(String first, String last) {
        this.first = first;
        this.last = last;
    }
    public String getFirst() {
        return first;
    }
    public String getLast() {
        return last;
    }
}

3、把特定类型String替换为T,并申明<T>

public class Pair<T> {
    private T first;
    private T last;
    public Pair(T first, T last) {
        this.first = first;
        this.last = last;
    }
    public T getFirst() {
        return first;
    }
    public T getLast() {
        return last;
    }
}

泛型不可用于静态方法

如下:

public class Pair<T> {
    private T first;
    private T last;
    public Pair(T first, T last) {
        this.first = first;
        this.last = last;
    }
    public T getFirst() { ... }
    public T getLast() { ... }

    // 对静态方法使用<T>:会导致编译错误,我们无法在静态方法create()的方法参数和返回类型上使用泛型类型T
    public static Pair<T> create(T first, T last) {
        return new Pair<T>(first, last);
    }
}

// 静态方法泛型是单独针对静态方法的泛型和class类的泛型没关系,T!==K
public class Pair<T> {
    private T first;
    private T last;
    public Pair(T first, T last) {
        this.first = first;
        this.last = last;
    }
    public T getFirst() { ... }
    public T getLast() { ... }

    // 静态泛型方法应该使用其他类型区分:
    public static <K> Pair<K> create(K first, K last) {
        return new Pair<K>(first, last);
    }
}

多个泛型类型

public class Pair<T, K> {
    private T first;
    private K last;
    public Pair(T first, K last) {
        this.first = first;
        this.last = last;
    }
    public T getFirst() { ... }
    public K getLast() { ... }
}

// 使用
Pair<String, Integer> p = new Pair<>("test", 123);
// Java标准库的Map<K, V>就是多泛型的例子
Map<String,Integer> map = new Map<>("age", 26)

擦拭法

public class MyUtils<T> {
    private T type_variable;
    MyUtils() throws Exception{
        Type t = getClass().getDeclaredField("type_variable").getGenericType();
        Log.i("xbh", t.toString());
    }
}
// 调用
MyUtils<String> m = new MyUtils<String>();

理论上是输出String,可是就是由于擦拭法的原因,输出是T。

所以擦拭法是泛型在运行的时候,不会暴露出真是类型,可以说是被拭去了。

原因:java语法中认可泛型的,但是虚拟机不认可,所以如果你想获取真实类型的话,必须在编译的时候就要指定了。

extends通配符

使用类似<? extends Number>通配符作为方法参数时表示:

  • 方法内部可以调用获取Number引用的方法,例如:Number n = obj.getFirst();
  • 方法内部无法调用传入Number引用的方法(null除外),例如:obj.setFirst(Number n);

即一句话总结:使用extends通配符表示可以读,不能写。

使用类似<T extends Number>定义泛型类时表示:

  • 泛型类型限定为Number以及Number的子类。

super通配符

使用类似<? super Integer>通配符作为方法参数时表示:

  • 方法内部可以调用传入Integer引用的方法,例如:obj.setFirst(Integer n);
  • 方法内部无法调用获取Integer引用的方法(Object除外),例如:Integer n = obj.getFirst();

即使用super通配符表示只能写不能读。

使用extendssuper通配符要遵循PECS原则。

无限定通配符<?>很少使用,可以用<T>替换,同时它是所有<T>类型的超类。

泛型和反射

部分反射API是泛型,例如:Class<T>Constructor<T>

可以声明带泛型的数组,但不能直接创建带泛型的数组,必须强制转型;

可以通过Array.newInstance(Class<T>, int)创建T[]数组,需要强制转型;

同时使用泛型和可变参数时需要特别小心。

标签:last,String,Pair,泛型,genericity,public,first
From: https://www.cnblogs.com/yangguanglei/p/16847414.html

相关文章

  • 泛型集合List(C#)
    1usingSystem;2usingSystem.Collections.Generic;3usingSystem.Linq;4usingSystem.Text;56namespaceListDemo7{8classProgram9{10staticvoidMai......
  • java-泛型-3
    package泛型;importjava.util.*;/***泛型的高级使用*1.泛型的继承或接口,用extends在<>里面实现*2.语法:A<TextendsanyClass>a;这里的泛型T必须是anyClass的子类......
  • java-泛型-2
    package泛型;/***泛型的继承4种情况*1.全部继承Father<T1,T2>{}my<T1,T2,T3>extendsFather<T1,T2>{}*2.部分继承就是在继承的时候,给父类的泛型进行实例化*F......
  • 泛型受限
    packagecom.msb.test06;importjava.util.ArrayList;importjava.util.List;/***@author:liu*日期:16:15:22*描述:IntelliJIDEA*版本:1.0*/publi......
  • C# HashSet不要遍历或者使用泛型扩展方法
    C#的接口IEnumerable定义了GetEnumerator方法,它的拓展方法是都是基于这个迭代器实现的。当我们使用比如,First、Where等泛型方法时,会实例化一个迭代器Enumerator包含......
  • 0095-Go-泛型
    环境Time2022-08-24Go1.19前言说明参考:https://gobyexample.com/generics目标使用Go语言的泛型。泛型函数packagemainimport"fmt"funcMapKeys[Kcom......
  • 无法将delegate(委托)转换为泛型类型T
    为什么我们不能将委托的实例强制转换为通用类型T?考虑一个实用程序方法CreateDelegate,它创建一个T实例,它是一个委托,即从MulticastDelegate派生的类型。TCreateDelegate......
  • 使用泛型和反射实现一个简单的ORM框架
    什么是ORM框架?ORM框架是连接数据库与实体类帮助程序对接数据库的框架,类似于三层架构的数据访问层,但ORM框架可以根据数据库生成实体类,或者根据实体类生成数据库,解决了......
  • 泛型方法
    packagecom.msb.test03;importjava.util.Collection;/***@author:liu*日期:15:18:34*1。描述:什么是泛型方法*不是带泛型的方法就是泛型方法*泛型......
  • 泛型引入
    【1】什么是泛型(Generic):泛型就相当于标签形式:<>集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把数据类型设计为Obj......