[Java 学习笔记] 泛型

摘要:
而numberList实际上和integerList是同一个对象,不可能接受Float类型,在获取Integer的时候将产生ClassCastException。由此,Java泛型的局限也体现出来局限一:不能是基本类型,例如int,因为实际类型是Object,Object类型无法持有基本类型:Pairp=newPair(1,2);//compileerror!

目录

泛型的向上转型

将静态方法的泛型类型和实例类型的泛型类型区分开

多泛型类

java可以创建泛型数组(待完善)

Java实现泛型的方法——擦拭法

由此,Java泛型的局限也体现出来

泛型继承(loading)

通配符(loading)

泛型与反射(loading)


总结自廖雪峰老师的Java教程:

Java教程 - 廖雪峰的官方网站 (liaoxuefeng.com)icon-default.png?t=L9C2https://www.liaoxuefeng.com/wiki/1252599548343744


泛型的向上转型

在Java标准库中, ArrayList<T>实现了List<T>接口,它可以向上转型为List<T>

public class ArrayList<T> implements List<T> {
    ...
}

List<String> list = new ArrayList<String>();

编译器看到泛型类型List<String>就可以自动推断出后面的ArrayList<T>的泛型类型必须是ArrayList<String>,代码可以简写为:

// 可以省略后面的Number,编译器可以自动推断泛型类型:
List<Number> list = new ArrayList<>();

!注意:不能把ArrayList<Integer>向上转型为ArrayList<Number>List<Number>

假设ArrayList<Integer>向上转型为ArrayList<Number>

// 创建ArrayList<Integer>类型:
ArrayList<Integer> integerList = new ArrayList<Integer>();

// 添加一个Integer:
integerList.add(new Integer(123));

// “向上转型”为ArrayList<Number>:
ArrayList<Number> numberList = integerList;

// 添加一个Float,因为Float也是Number:
numberList.add(new Float(12.34));

// 从ArrayList<Integer>获取索引为1的元素(即添加的Float):
Integer n = integerList.get(1); // ClassCastException!
  • 一个ArrayList<Integer>转型为ArrayList<Number>类型后,这个ArrayList<Number>就可以接受Float类型,因为Float是Number的子类。
  • 而numberList实际上和integerList是同一个对象(ArrayList<Integer>类型),不可能接受Float类型, 在获取Integer的时候将产生ClassCastException

总结:

编译器为了避免这种错误,根本就不允许把ArrayList<Integer>转型为ArrayList<Number>。

注意泛型的继承关系:可以把ArrayList<Integer>向上转型为List<Integer>(T不能变),但不能把ArrayList<Integer>向上转型为ArrayList<Number>(T不能变成父类)

另外须知:ArrayList<Integer>和ArrayList<Number>两者完全没有继承关系


将静态方法的泛型类型和实例类型的泛型类型区分开

注意,泛型类型不能用于静态方法

下面的代码编译错误

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>:
    public static Pair<T> create(T first, T last) {
        return new Pair<T>(first, 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() { ... }

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

多泛型类

class Pair<T,K>
{
    private T first;
    private K second;

    public Pair(T first, K second){
        this.first = first;
        this.second = second;
    }

    public T getFirst(){
        return this.first;
    }
    public K getSecond(){
        return this.second;
    }
}
public class pairx {
    public static void main(String[] args) {
        Pair<String, Integer> p1 = new Pair<>("泥烟", 8080);
        System.out.println(p1.getFirst()+p1.getSecond());
    }
}



运行结果:

输出→泥烟8080

另外java是可以创建泛型数组的(还未完全掌握,之后完善):

java可以创建泛型数组(待完善)

Java中创建泛型数组 - minghai - 博客园 (cnblogs.com)icon-default.png?t=L9C2https://www.cnblogs.com/minghaiJ/p/11259318.html

Java实现泛型的方法——擦拭法

Java的泛型是由编译器在编译时实行的,编译器内部永远把所有类型T视为Object处理但是,在需要转型的时候,编译器会根据T的类型自动为我们实行安全地强制转型

由此,Java泛型的局限也体现出来

局限一<T>不能是基本类型,例如int,因为实际类型是ObjectObject类型无法持有基本类型

Pair<int> p = new Pair<>(1, 2); // compile error!

局限二:无法取得带泛型的Class

有如下类

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;
    }
}
    Pair<String> p1 = new Pair<>("Hello", "world");
    Pair<Integer> p2 = new Pair<>(123, 456);
    Class c1 = p1.getClass();
    Class c2 = p2.getClass();
    System.out.println(c1==c2); // true
    System.out.println(c1==Pair.class); // true

无论T的类型是什么,getClass()返回同一个Class实例,因为编译后它们全部都是Pair<Object>

局限三:无法判断带泛型的类型,原因同上

Pair<Integer> p = new Pair<>(123, 456);
// Compile error:
if (p instanceof Pair<String>) {
    ...
}

并不存在Pair<String>.class,而是只有唯一的Pair.class

局限四:不能直接实例化T类型

public class Pair<T> {
    private T first;
    private T last;
    public Pair() {
        // Compile error:
        first = new T();
        last = new T();
    }
}



擦拭后实际上变成了:

first = new Object();
last = new Object();

将其实例化的方法

(待续...)

泛型继承(loading)通配符(loading)泛型与反射(loading)

免责声明:文章转载自《[Java 学习笔记] 泛型》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇netty作为基础通信组件Django配置站点下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

9本Java程序员必读的书

本文列出的9本书在Java程序员界都是被认为很棒的书。当一个程序员开始初学Java时,他的第一个问题应该是如何选择一本书来作为指导学习Java。这个问题也就表明,相对于其他的教程和博客,Java书籍还是很重要的参考,主要表现在以下两点 ●通常书籍是由比较权威的程序员来撰写的。 ●相比其他媒介,书籍对于内容的描述更加详细,解释更加明确。 本文列出的九本...

容器知识的重点总结

什么是容器 数组也是一种容器,可以存放对象或基本数据类型,数组的劣势在于不灵活,容器需要事先定义好,不能随着需求而改变而扩容。而容器则可以随时扩容来装对象,容器也称为集合。 容器的结构 单例集合 将数据一个一个的进行存储 双例集合 基于 key 和 value 的结构存储数据 Collection 接口 LIst接口:有序,可重复 ArrayList 容...

Java高级开发_性能优化的细节

一、核心部分总结: 尽量在合适的场合使用单例【减负提高效率】 尽量避免随意使用静态变量【GC】 尽量重用对象,避免过多过常地创建Java对象【最大限度地重用对象】 尽量使用final修饰符【内联(inline)】 尽量使用局部变量【栈快】 尽量处理好包装类型和基本类型两者的使用场所【堆栈】 慎用synchronized,尽量减小synchronize的方...

Java 泛型小结

1、什么是泛型?   泛型(Generics )是把类型参数化,运用于类、接口、方法中,可以通过执行泛型类型调用 分配一个类型,将用分配的具体类型替换泛型类型。然后,所分配的类型将用于限制容器内使用的值,这样就无需进行类型转换,还可以在编译时提供更强的类型检查。    2、泛型有什么用?   泛型主要有两个好处:   (1)消除显示的强制类型转换,提高代...

Java内存优化和性能优化的几点建议

1.没有必要时请不用使用静态变量     使用Java的开发者都知道,当某个对象被定义为stataic变量所引用,这个对象所占有的内存将不会被回收。有时,开发者会将经常调用的对象或者变量定义为static,以便提高程序的运行性能。因此,不是常用到的对象或者变量,不要定义为static类型的变量,尤其是静态类对象的定义,一定要仔细考虑是否有必要。例如  ...

获取Spring容器中Bean实例的工具类(Java泛型方法实现)

在使用Spring做IoC容器的时候,有的类不方便直接注入bean,需要手动获得一个类型的bean。 因此,实现一个获得bean实例的工具类,就很有必要。 以前,写了一个根据bean的名称和类型获取bean实例的2个工具方法,发现每次调用后,都需要强制转换成目标结果类型。 这样很不方便,突然想到可以使用Java泛型方法,实现1个新的工具方法,避免了类型转换...