day03_泛型

  • Post author:
  • Post category:其他




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[]数组



版权声明:本文为qq_45234751原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。