认识Java泛型

书读的越多而不加思考,你就会觉得你知道得很多;而当你读书而思考得越多的时候,你就会越清楚地看到,你知道得很少。

导读:本篇文章讲解 认识Java泛型,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

泛型

让一个类或一个方法或一个接口能支持多种不同的数据类型
(一套代码可用于多种类型)

泛型分类

1.泛型类

语法
class 类名<泛型参数列表> {
    //类体
}

class ClassName<T, S> {
    public T name;
    public S age;
    public ClassName(T name, S age) {
        this.age = age;
        this.name = name;
    }
}

注意:这里的T和S在实例化类的时候需要指定,且只能指定为引用类型,如果是内在类型,需要使用包装类

在泛型类中不能创建实例,需要在构造函数中传入

这样就会出错

class ClassName<T, S> {
    public T name;
    public S age;
    public ClassName() {
        this.age = new T();
        this.name = new S();
    }
}

java: 意外的类型
需要: 类
找到: 类型参数T

泛型类实例化
类名<类型参数列表> 对象名 = new 类名<类型参数列表>();

上述例子的实例化为

ClassName<String,Integer> object = new ClassName<String, Integer>();

如果不用包装类,写成这样

ClassName<String, Integer> object = new ClassName<>("123", 5);

就会报错

java: 意外的类型
需要: 引用
找到: int

实例化的时候可以简化
如:省略右侧的参数列表

ClassName<String,Integer> object2 = new ClassName<>();

左侧的尖括号如果省略了,T和S就变成了Object类型了,右侧的尖括号如果省略了,new出来的对象也变成Object类型了

这两种情况都不是我们所指定的类型<Stirng,int>

类型边界

用来约束泛型参数的

语法

class 类名<T extends U> {
    //类体
}

在实例化时,T只能为U的子类或者是U本身,否则编译出错

如果未写extends U这样的语句即未指定边界类型,可以看作是extends Object

class A<T> { }

即为

class A<T extends Object> { }

2.泛型方法

语法

方法限定符 <类型参数列表> 返回值类型 方法名(形参列表) {
    方法体    
}

例子

public class Test {

    public static void main(String[] args) {
        fun(new String("123"), 2);
    }
    public static <T, S> boolean fun(T a, S b) {
        return true;
    }
}

调用fun方法的时候,不必写传入的参数,编译器会自动判断

通配符
?

用在泛型,表示通配符

用于方法的参数是泛型类

class ClassName<T, S> {
    public T name;
    public S age;
    public ClassName(T name, S age) {
        this.age = age;
        this.name = name;
    }
}
public class Test {

    public static void main(String[] args) {
        fun(new ClassName<>("张三",16));
    }
    public static void fun(ClassName<?,?> object) { }
    
}
<? extends U>

语法-上界

<? extends U>

表示传入的类型(?为传入的类型)只能是U的子类或者U本身
如:

class Animal { }
class Dog extends Animal { }
class Cat extends Animal { }
class Bird extends Animal { }
class ClassName<T> { }
public class Test {

    public static void main(String[] args) {
        fun(new ClassName<Dog>());
        fun(new ClassName<Animal>());
    }
    
    public static void fun(ClassName<? extends Animal> a) { }
}

这样写没有任何问题,Dog类、Cat类、Bird类都是继承于Animal类

但是这样写就会出问题

fun(new ClassName<Object>());

结果

java: 不兼容的类型: ClassName<java.lang.Object>无法转换为ClassName<? extendsAnimal>

Object类不是Animal类的子类是它的父类

<? super U>

语法-下界

<? super U>

表示传入的类型(?为传入的类型)只能是U的父类或者U本身

class Creature { }
class Person extends Creature { }
class Student extends Person { }
class UniversityStudent extends Student { }
class ClassName<T> { }
public class Test {
    public static void main(String[] args) {
        fun(new ClassName<UniversityStudent>());
        fun(new ClassName<Person>());
    }
    public static void fun(ClassName<? super UniversityStudent> x) { }
}

这里UniversityStudent类的父类是Student类、Person类、Creature类、Object类所以fun方法里可以传入这些对象

3.泛型接口

语法
interface 接口名<泛型参数列表> {
    //接口体
}

例子

interface Comparable<T> {
    public int compareTo(T o);
}

类型擦除

将所有的泛型表示替换为具体的类型
实际的下面代码

class ClassName<T, S, V> {
    private T field1;
    private S field2;
    private V field3;
    public ClassName(T t, S s, V v) {
        this.field1 = t;
        this.field2 = s;
        this.field3 = v;
    }
}

会在编译的时候可能替换成

class ClassName {
    private Object field1;
    private Object field2;
    private Object field3;
    public ClassName(Object t, Object s, Object v) {
        this.field1 = t;
        this.field2 = s;
        this.field3 = v;
    }
}

类型擦除也有规则,这里具体就不说了,感兴趣的读者可以查阅资料

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/122861.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!