A、泛型的概念
1.背景
Java推出泛型之前,程序员可以构建一个元素类型为Object类型的集合,该集合就能够存储任何数据类型的对象,而在使用该集合的过程中,需要程序员明确知道存储的每个元素的类型数据,否则很容易引发ClassCastException。那通过泛型我们就可以通过约束集合插入的类型,那么该集合中所有的元素都必须是此类型,就不需要从Object类型强转成相应的类型
未加泛型的场景:
如:
class Student{
private String name;
private int age;
private char sex;
public Student() {
}
public Student(String name, int age, char sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public void showStudent() {
System.out.println("你好我是:"+name+",年龄是:"+age+",性别是:"+sex);
}
}
public static void main(String[] args) {
Student stu1 = new Student("杨幂",28,'女');
Student stu2 = new Student("胡歌",35,'男');
Student stu3 = new Student("张译",40,'男');
Student stu4 = new Student("郭德纲",48,'男');
List list = new ArrayList();
list.add(stu1);
list.add(stu2);
list.add(stu1);
list.add(stu3);
list.add(1,stu4);
//由于这个集合我们需要限定数组里面为Student类型,不能插入String类型
//会出现ClassCastException,所以要使用泛型
//list.add("张三丰");因为add(Object)类型可以插入任意类型
for(int i = 0;i< list.size();i++)
{
Student student = (Student) list.get(i);
student.showStudent();
}
for (Object object : list) {
Student student2 = (Student) object;
student2.showStudent();
}
2.概念
java泛型(generics)是java5引入的一个新特性,泛型提供了类型安全的检测机制,该机制允许我们在编译检测到非法的数据类型结构,泛型的本质时参数化类型,通过<>指定参数来设定该数据类型
3.好处
1.类型安全,不会插入指定类型以外的类型
2.消除了强制类型的转换
4.泛型的类型
泛型的类型可以定义在类上、父类上、子类上、方法上、参数上、
泛型类型可以是任意字母来代替你需要传入的参数
一般我们的写法时:
E -Element 代表集合中存放的元素
T -Type 代表java类,包括基本的类和我们自定义的类
K -key 表示键,比如Map中的key
V -Value 表示值
N -Number表示数值类型
? 代表不确定java类型
B、泛型类:
1.泛型类的定义:
1.语法
类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>();
java7之后可以这样写:
类名<具体的数据类型> 对象名 = new 类名<>();
泛型类特征:
1.泛型类,如果没有指定具体的数据类型,那么默认的类型是Object类型
2.泛型的类型参数只能是类类型,不能是基本类型
3.泛型类型在逻辑上可以看成是多个不同的类型,但实际上是相同的类型
需求:
公司要做一个抽奖的项目案例,抽奖两种方案:方案一是抽手机(字符串),方案二是抽现金(整型)
public class ProductGetter<T> {
private T product;
//奖品池
ArrayList<T> list = new ArrayList<>();
//添加产品
public void addProduct(T t){
list.add(t);
}
public T getProduct(){
//随机取到奖品集合中的一个元素
product = list.get(new Random().nextInt(list.size()));
return this.product;
}
}
public class ProductTest {
public static void main(String[] args) {
ProductGetter<String> string = new ProductGetter<String>();
String[] strProducts = {"苹果手机","华为手机","扫地机器人","咖啡机"};
//给奖品容器填充奖品
for (int i = 0;i<strProducts.length;i++){
string.addProduct(strProducts[i]);
}
String product = string.getProduct();
System.out.println("恭喜你,你抽中了"+product);
ProductGetter<Integer> intProductsGetter = new ProductGetter<>();
//给奖品填充奖品
int[] intProducts = {10000,5000,3000,200};
for(int i = 0;i<intProducts.length;i++){
intProductsGetter.addProduct(intProducts[i]);
}
Integer product2 = intProductsGetter.getProduct();
System.out.println("恭喜你,抽中了"+product2);
}
2.泛型子类
案例1
public class Parent<E> {
private E value;
public E getValue() {
return value;
}
public void setValue(E value) {
this.value = value;
}
}
/**
* @author yao
* 泛型类型的子类,泛型标识符一定要和父类一致
* @param <T>
*/
public class ChildFirst<T> extends Parent<T> {
@Override
public T getValue() {
return super.getValue();
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
public class ChildSecond extends Parent<Integer>{
@Override
public Integer getValue() {
return super.getValue();
}
@Override
public void setValue(Integer value) {
super.setValue(value);
}
}
public class ParentTest {
public static void main(String[] args) {
ChildFirst<String> childFirst = new ChildFirst<>();
childFirst.setValue("abc");
String value = childFirst.getValue();
System.out.println(value);
System.out.println("====================");
ChildSecond childSecond= new ChildSecond();
//ChildSecond子类没有定义泛型,但是父类定义了是Integer类型
childSecond.setValue(12);
Integer value1 = childSecond.getValue();
System.out.println(value1);
}
}
D、泛型接口
public interface Generic1<T> {
public T getKey();
}
/**
* @author yao
* 子类如果不是泛型类型,则父类要明确数据类型
*/
public class Apple implements Generic1<String>{
@Override
public String getKey() {
return "hello 泛型";
}
}
//public class Pair<T> implements Generic1<T>
//泛型类继承泛型接口,除了必须标识父类的泛型标识符之外,还可以实现泛型的扩充
public class Pair<T,E> implements Generic1<T> {
private T key;
private E value;
@Override
public T getKey() {
return this.key;
}
public Pair(T key,E value){
this.key = key;
this.value = value;
}
}
public class Generic1Test {
public static void main(String[] args) {
Pair<String,Integer> pair = new Pair<String,Integer>("张三",1000);
String key = pair.getKey();
Integer value = pair.getValue();
System.out.println(key+"="+value);
System.out.println("====================");
Apple apple = new Apple();
String key1 = apple.getKey();
System.out.println(key1);
}
}
泛型方法
public class ProductGetter<T> {
private T product;
Random random= new Random();
//奖品chi池
ArrayList<T> list = new ArrayList<>();
//添加产品
public void addProduct(T t){
list.add(t);
}
/**
* 泛型成员方法(不是泛型方法)
*/
//抽奖获取产品
public T getProduct(){
//随机取到奖品集合中的一个元素
product = list.get(random.nextInt(list.size()));
return product;
}
/**
* 定义泛型方法(在public和返回值中间定义<>才是泛型方法)
* @param <E> 泛型标识,具体类型由调用方法的时候来决定的
* @param list 参数
* @return
*/
public <E> E getProduct(ArrayList<E> list){
return list.get(random.nextInt(list.size()));
}
/**
* * 定义静态的泛型方法,并且采用多个泛型类型
* * @param <T>
* @param <E>
* @param <K>
* @param t
* @param e
* @param k
*/
public static <T,E,K> void printType(T t,E e,K k){
System.out.println(t+"\t"+t.getClass().getSimpleName());
System.out.println(e+"\t"+e.getClass().getSimpleName());
System.out.println(k+"\t"+k.getClass().getSimpleName());
}
/**
* String ... 代表多个String类型的参数
* 定义泛型个数可变的参数
* @param <E>
* @param e
*/
public static <E> void print(E... e){
for (int i = 0; i < e.length; i++) {
System.out.println(e[i]);
}
}
}
package com.genertor;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
ProductGetter<Integer> productGetter = new ProductGetter<>();
ArrayList<String> strList = new ArrayList<>();
strList.add("笔记本");
strList.add("苹果手机");
strList.add("扫地机器人");
String product1=productGetter.getProduct(strList);
System.out.println(product1+"\t"+product1.getClass().getSimpleName());
System.out.println("-----------------------------------------------------");
ArrayList<Integer> intList=new ArrayList<Integer>(); intList.add(1000);
intList.add(5000);
intList.add(300);
//调用泛型方法 <E> 泛型标识,具体类型由调用方法的时候来决定的
Integer product2=productGetter.getProduct(intList);
System.out.println(product2+"\t"+product2.getClass().getSimpleName());
System.out.println("-----------------------------------------------------");
ProductGetter.printType(100,"java",true);
ProductGetter.printType("java",true,98.99);
ProductGetter.printType(true,false,true);
System.out.println("-----------------------------------------------------");
ProductGetter.print(1,2,3,4,5);
System.out.println("-----------------------------------------------------");
ProductGetter.print(1,true,"b");
}
}
}
类型通配符?
类型通配符一般使用”?”代替具体的类型实参,当类型不明确具体的类型的时候可以用?来替代
案例1:
public class Box<E> {
private E first;
public E getFirst() {
return first;
}
public void setFirst(E first) {
this.first = first;
}
}
public class Test01 {
public static void main(String[] args) {
Box<Number> box1 = new Box<>();
box1.setFirst(100);
showBox(box1);
Box<Integer> box2 = new Box<>();
box2.setFirst(200);
// showBox(box2);//报错;按照多态的思维创建子类对象后showBox以父类Number类型接收是可以 的,但是在泛型中不支持
// showBox方法中定义的是Box<Number> Number类型,所以它只能是接收Number类型实参
}
private static void showBox(Box<Number> box1) {
Number first= box1.getFirst();
System.out.println(first);
}
}
案例2:
public class Box<E> {
private E first;
public E getFirst() {
return first;
}
public void setFirst(E first) {
this.first = first;
}
}
package com.genertor;
public class Test02 {
public static void main(String[] args) {
Box<Number> box1 = new Box<>();
box1.setFirst(100);
showBox(box1);
Box<Integer> box2 = new Box<>();
box2.setFirst(200);
// showBox(box2);//报错;按照多态的思维创建子类对象后showBox以父类Number类型接收是可以 的,但是在泛型中不支持
// showBox方法中定义的是Box<Number> Number类型,所以它只能是接收Number类型实参
}
//?是通配符,代表任意类型
/* private static void showBox(Box<?> box1) {
Object first = box1.getFirst();
System.out.println(first);
}*/
//通配符上限 ? extends Number 只能是Number类型或者是Number类型的子类
private static void showBox(Box<? extends Number> box1) {
Number first= box1.getFirst();
System.out.println(first);
}
}
类型通配符上限<? extends 父类>
public class Animal {
}
public class Cat extends Animal{
}
public class MiniCat extends Cat{
}
public class Test {
public static void main(String[] args){
ArrayList<Animal> animals = new ArrayList<>();
ArrayList<Cat> cats = new ArrayList<Cat>();
ArrayList<MiniCat> minicat = new ArrayList<MiniCat>();
showAnimal(cats);
// showAnimal(animals);//报错:showAnimal(ArrayList<? extends Cat> list)设定参 数只能是Cat子类或者Cat类型
}
/**
*
*泛型通配符上限
*/
privavte static void showAnimal(ArrayList<? extends Cat> list){
for (int i = 0;i<list.size();i++)
{
Cat cat = list.get(i);
System.out.println(cat);
}
}
}
类型通配符下限<? super 子类>
public class Test {
public static void main(String[] args) {
ArrayList<Animal> animals=new ArrayList<Animal>();
ArrayList<Cat> cats=new ArrayList<Cat>();
ArrayList<MiniCat> minicat=new ArrayList<MiniCat>();
showAnimal(cats); showAnimal(animals);
// showAnimal(minicat);//报错:ArrayList<? super Cat>是通配符下限,定义了参数只能 是Cat类型或者Cat类型的父类类型
}
/** * 泛型通配符下限,只能是Cat或者Cat的父类类型 * */
private static void showAnimal(ArrayList<? super Cat> list) {
for (int i = 0; i < list.size(); i++) {
Object obj= list.get(i);
System.out.println(obj);
}
}
}
泛型数组
1.可以声明带泛型的数组引用,但不能直接创建带泛型的数组对象
2.可以通过java.lang.reflect,Array的newInstance(class,int)创建T[]数组