zoukankan      html  css  js  c++  java
  • Java泛型基础

    1.泛型的作用
    public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    try {
    Class<? extends List> aClass = list.getClass();
    Method add = aClass.getDeclaredMethod("add", Object.class);
    add.invoke(list,"kl");
    }catch (Exception ex){
    }
    System.out.println(list);
    }
    运行结果: [1, kl]
    为什么泛型为Integer类型的List能存String 其实list添加的时候类型本身就是object,jdk1.5推出泛型这只是为了更严格的代码编写,更安全,也降低了异常:如强制转化带来的麻烦。但是泛型还有其他作用,如框架封装提供的基类等都是使用泛型。
     
    2.泛型主要应用在接口,类,方法上,分为4种。
     
    接口泛型:大致的写法。
    package com.JavaTest1;
     
    class InterfaceClass1 <T,M,N>{
    public T test(M m,N n){
    T t = null;
    return t;
    }
    }
    public class InterfaceClass <T>{
    public T test(T t){
    return t;
    }
    }
    interface InterfactClass2<T extends Number> {
    default T test() {
    T t = null;
    return t;
    }
    T test2();
    }
    当实现接口的类不传入定义的泛型实参,编译报错,上述的T,M,N称为通配符,可以任意命名。
    形参:一般方法上的参数就叫形参
    实参:传给方法的参数叫实参。
     
    泛型方法:大致写法
    public <T> T test1(T... args){
    T t = null;
    return t;
    }
    public void test2(InterfaceClass<T> interfaceClass){
     
    }
    public void test3(InterfaceClass<?> interfaceClass) {
     
    }
    这里的?号是类型实参你可以把它看做是所以参数的父类,比如object类一样。
     
     
    泛型类:大致写法
    class Plate<T> {
    private T item;
    public Plate(T t) {
    this.item = t;
    }
    public T get() {
    return item;
    }
    public void set(T item) {
    this.item = item;
    }
    }
    泛型静态方法:
    public static <T> void show(T t){ }
    <T> 需要额外增加这个申明,因为不依赖泛型类,静态方法本身属于类,不依赖实例对象。
     
    3.泛型上下边界
    查看下面的两个例子:
    public class Abrasion { public static void main(String[] args) { Class a = new ArrayList<Integer>().getClass(); Class b = new ArrayList<String>().getClass(); System.out.println(a == b); } }
    运行结果: true
    为什么运行结果一样呢,因为在泛型代码内部,无法获取任何有关泛型参数类型的任何信息!,Java的泛型就是使用擦除来实现的,当你在使用泛型的时候,任何信息都被擦除,你所知道的就是你在使用一个对象。
    擦除的理解:
    class Hello{ public void hello(){ System.out.println("hello"); } } class TestHello<T>{ private T t; public TestHello(T t){ this.t = t; } public void callHello(){ t.hello();//这里不能编译 } } public class Demo { public static void main(String[] args) { Hello hello = new Hello(); TestHello<Hello> testHello = new TestHello<>(hello); testHello.callHello(); } }
    我们可以看到,t.hello()这里是不能够编译的。因为擦除的存在,main中传入的泛型,在TestHello中编程了Object,因此并不能跟Hello这个类绑定,也就调用不了hello方法,泛型擦除了所以的信息,解决这个问题只需要把TestHello定义为TestHello<T extends Hello> 。这个边界申明了必须具有类型Hello或者从Hello导出的类型。
     
    再看下面的例子
    class redApple extends Apple{};
    class Fruit {}
    class Apple extends Fruit {}
    class Plate<T> {
    private T item;
    public Plate(T t) {
    this.item = t;
    }
    public T get() {
    return item;
    }
    public void set(T item) {
    this.item = item;
    }
    }
    public void test3(){
     
    Plate<? extends Apple> fruitPlate=new Plate<Apple>(new Apple());
    fruitPlate.get();
    fruitPlate.set(new Apple()); // 报错,因为不知道我的子类是哪个
     
    Plate<? super Apple> plate =new Plate<Fruit>(new Fruit());
    plate.set(new redApple());
    }
    这里讲述了通配符和泛型的上界和下界,上界< ? extends Class> 下界下界< ? super Class>
     
    PECS原则
    如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends) 
    如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super) 
    如果既要存又要取,那么就不要使用任何通配符。
    总结:
    无论何时,如果你能做到,你就该尽量使用泛型方法。也就是说,如果使用泛型方法将整个类泛型化,那么就应该使用泛型方法。另外对于一个static的方法而已,无法访问泛型类型的参数。所以如果static方法要使用泛型能力,就必须使其成为泛型方法。

  • 相关阅读:
    水平居中
    flex布局
    get新技能:上传了 flv 或 MP4 文件到服务器,可访问总是出现 “无法找到该页”的 404 错误
    小程序3.8
    小程序3.7
    Vue 中select option默认选中的处理方法
    HTML5 data属性
    静态html返回
    node中可读流、可写流
    node.js fs、http使用
  • 原文地址:https://www.cnblogs.com/Seeasunnyday/p/9140228.html
Copyright © 2011-2022 走看看