java基础---泛型

什么是泛型

什么是泛型?

泛型是 Java SE5 出现的新特性,泛型的本质是类型参数化或参数化类型,在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型。

泛型类,接口

1.泛型类

​ 泛型类的定义格式:

  • 格式:修饰符 class 类名<类型>{}

  • 泛例:public class Generic {}

  • T可以是任意标识

    public class Generic<T>{
        private T t;
    
        public T get(){
            return t;
        }
    
        public void set(T t){
            this.t = t;
        }
    }
    
    
public class CollectionDemo {

    public static void main(String[] args) {
        Generic<String> stu = new Generic<String>();
        stu.set("鸣人");
        System.out.println(stu.get());

        Generic<Integer> stu1 = new Generic<Integer>();
        stu1.set(10);
        System.out.println(stu1.get());
    }
}

2.泛型接口

泛型接口的定义格式:

  • 格式:修饰符 interface 接口名<类型>{}

  • 范例:public interface Generic {}

    public interface GenInterface<T> {
        void show(T t);
    }
    
    public class GenImpl<T> implements GenInterface<T>{
        @Override
        public void show(T t) {
            System.out.println(t);
        }
    }
    
    public class CollectionDemo{
    
        public static void main(String[] args) {
            GenImpl<String> str = new GenImpl<String>();
            str.show("加油");
    
            GenImpl<Integer> i = new GenImpl<>();
            i.show(30);
        }
    }
    
    

泛型方法

泛型方法的定义格式:

  • 格式:修饰符 <类型> 返回值类型方法名(类型变量名){}
  • 范例:public void show(T t){}
public <T> T show(T t){
        return t;
    }

    public <T> void show1(T t){
        System.out.println(t);
    }

类型通配符和泛型上下限

为了表示各种泛型List的父类,可以使用类型通配符

  • 类型通配符:<?>
  • List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型
  • 这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中

如果不希望List<?>是任何泛型的父类,只希望代表某一类泛型List的父类,可以使用类型通配符的上限。

类型通配符上限:<?extends类型>
List<? extends Number>:表示的类型是Number或者其子类型

除了可以指定类型通配符的上限,也可以指定类型通配符的下限:

类型通配符下限:<?super类型>
List<?super Number>:表示的类型是Number或者其父类型
import java.util.ArrayList;
import java.util.List;

public class CollectionDemo{

    public static void main(String[] args) {
        List<?> numbersList = new ArrayList<Number>();

        //类型通配符上限
        List<? extends Number> list1 = new ArrayList<Number>();
        List<? extends Number> list2 = new ArrayList<Integer>();

        //类型通配符下限
        List<? super Number> list3 = new ArrayList<Number>();

    }
}


<?> 无限制通配符
<? extends E> extends 关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类
<? super E> super 关键字声明了类型的下界,表示参数化的类型可能是指定的类型,或者是此类型的父类

// 使用原则《Effictive Java》
// 为了获得最大限度的灵活性,要在表示 生产者或者消费者 的输入参数上使用通配符,使用的规则就是:生产者有上限、消费者有下限
1. 如果参数化类型表示一个 T 的生产者,使用 < ? extends T>;
2. 如果它表示一个 T 的消费者,就使用 < ? super T>;
3. 如果既是生产又是消费,那使用通配符就没什么意义了,因为你需要的是精确的参数类型。

泛型擦除

Java语言的泛型实现方式是擦拭法(Type Erasure)。
所谓擦拭法是指,虚拟机对泛型其实一无所知,所有的工作都是编译器做的。Java的泛型是由编译器在编译时实行的,编译器内部永远把所有类型T视为Object处理,但是,在需要转型的时候,编译器会根据T的类型自动为我们实行安全地强制转型。

Java 的泛型是伪泛型,因为在编译期间所有的泛型信息都会被擦除掉,泛型参数保留为原始类型。譬如 List 在运行时仅用一个 List 来表示(所以我们可以通过反射 add 方法来向 Integer 的泛型列表添加字符串,因为编译后都成了 Object),这样做的目的是为了和 Java 1.5 之前版本进行兼容
————————————————

原始类型 就是擦除去了泛型信息,最后在字节码中的类型变量的真正类型,类型变量擦除,并使用其限定类型(无限定的变量用Object)替换。
如果类型变量有限定,那么原始类型就用第一个边界的类型变量类替换。
比如: Pair这样声明的话

public class Pair {}

那么原始类型就是Comparable。

Java编译器是通过先检查代码中泛型的类型,然后再进行类型擦除,再进行编译

分类:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

泛型与数组

首先,我们泛型数组相关的申明:

List<String>[] list11 = new ArrayList<String>[10]; //编译错误,非法创建 
List<String>[] list12 = new ArrayList<?>[10]; //编译错误,需要强转类型 
List<String>[] list13 = (List<String>[]) new ArrayList<?>[10]; //OK,但是会有警告 
List<?>[] list14 = new ArrayList<String>[10]; //编译错误,非法创建 
List<?>[] list15 = new ArrayList<?>[10]; //OK 
List<String>[] list6 = new ArrayList[10]; //OK,但是会有警告


public class GenericsDemo30{  
    public static void main(String args[]){  
        Integer i[] = fun1(1,2,3,4,5,6) ;   // 返回泛型数组  
        fun2(i) ;  
    }  
    public static <T> T[] fun1(T...arg){  // 接收可变参数  
        return arg ;            // 返回泛型数组  
    }  
    public static <T> void fun2(T param[]){   // 输出  
        System.out.print("接收泛型数组:") ;  
        for(T t:param){  
            System.out.print(t + "、") ;  
        }  
    }  
}

合理使用

public ArrayWithTypeToken(Class<T> type, int size) {
    array = (T[]) Array.newInstance(type, size);
}

泛型与反射

反射和泛型都是Java的一种动态技术。而不像继承和多态,是面向对象的技术

我们知道,使用反射的一个最大的烦恼就是应用反射以后得到的基本上都是Object类型的对象,这种对象要使用,需要我们进行强制类型转化 而我们更知道,泛型的功能之一就是消除我们使用强制类型转化

1.反射常用的泛型类
Class
Constructor

public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/**
 * 泛型与反射
 */
public class Test11 {
	public static void main(String[] args) throws Exception {
	     Class<Person> personClass = Person.class;
	     Constructor<Person> constructor = personClass.getConstructor();
	     Person person = constructor.newInstance();
	 }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值