泛型

72 阅读3分钟

泛型信息只存在于代码编译阶段,但是在java的运行期 (已经生成字节码文件后)与泛型相关的信息会被擦除掉,专业术语叫做类型擦除

泛型类(壁如List,Map,Set)

public class Generic<T>{ 
    //key这个成员变量的类型为T,T的类型由外部指定  
    private T key;

    public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
        this.key = key;
    }

    public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
        return key;
    }
}
Generic<String> genericString = new Generic<String>("key_vlaue")
Generic generic = new Generic("key_vlaue");

泛型接口

public interface Generator<T> {
    public T next();
}
  • 不传入实参
class FruitGenerator<T> implements Generator<T>{
    @Override
    public T next() {
        return null;
    }
}
  • 传入实参
class FruitGenerator implements Generator<String>{
    @Override
    public String next() {
        return null;
    }
}

泛型通配符

Integer是Number的子类,但是否能以下写法:

public class Generic<T>{ 

    private T key;

    public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
        this.key = key;
    }
}
    public void showKeyValue1(Generic<Number> obj){
        Log.d("泛型测试","key value is " + obj.getKey());
    }
Generic<Integer> gInteger = new Generic<Integer>(123);
Generic<Number> gNumber = new Generic<Number>(456);

showKeyValue(gNumber);//会报错,子类也是不兼容的

要改写成以下(对象可以用Object替代?),可以把?看作作所有类型(Integer、Number、String...)的父类

    public void showKeyValue1(Generic<?> obj){
        Log.d("泛型测试","key value is " + obj.getKey());
    }

又或者:

    public void showKeyValue1(Object obj){
        Log.d("泛型测试","key value is " + obj.getKey());
    }
    showKeyValue1("asd")     //这样也可以,好奇?

泛型方法

public class GenericFruit {
    class Fruit{
        @Override
        public String toString() {
            return "fruit";
        }
    }

    class Apple extends Fruit{
        @Override
        public String toString() {
            return "apple";
        }
    }

    class Person{
        @Override
        public String toString() {
            return "Person";
        }
    }

    class GenerateTest<T>{
        public void show_1(T t){
            System.out.println(t.toString());
        }

        //在泛型类中声明了一个泛型方法,使用泛型E,这种泛型E可以为任意类型。可以类型与T相同,也可以不同。
        //由于泛型方法在声明的时候会声明泛型<E>,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型。
        public <E> void show_2(E t){
            System.out.println(t.toString());
        }

        //在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型。show_2(T t)、show_3(T t)基本是一样的
        public <T> void show_3(T t){
            System.out.println(t.toString());
        }
    }

    public static void main(String[] args) {
        Apple apple = new Apple();
        Person person = new Person();

        GenerateTest<Fruit> generateTest = new GenerateTest<Fruit>();
        //apple是Fruit的子类,所以这里可以
        generateTest.show_1(apple);
        //编译器会报错,因为泛型类型实参指定的是Fruit,而传入的实参类是Person
        //generateTest.show_1(person);

        //使用这两个方法都可以成功
        generateTest.show_2(apple);
        generateTest.show_2(person);

        //使用这两个方法也都可以成功
        generateTest.show_3(apple);
        generateTest.show_3(person);
    }
}
  • 静态方法与泛型
    在某个类中,如果想在静态方法中使用泛型,必须设为静态方法。 这个就不能设为静态方法
  • 泛型上下边界
public class Generic<T extends Number>{
    private T key;

    public Generic(T key) {
        this.key = key;
    }

    public T getKey(){
        return key;
    }
}
//这一行代码也会报错,因为String不是Number的子类
Generic<String> generic1 = new Generic<String>("11111");

泛型方法的例子:

//在泛型方法中添加上下边界限制的时候,必须在权限声明与返回值之间的<T>上添加上下边界,即在泛型声明的时候添加
//public <T> T showKeyName(Generic<T extends Number> container),编译器会报错:"Unexpected bound"
public <T extends Number> T showKeyName(Generic<T> container){
    System.out.println("container key :" + container.getKey());
    T test = container.getKey();
    return test;
}