泛型概念

是一种未知的数据类型,当不知道用什么数据类型的时候,就可以使用泛型。

泛型也可以看作是一个变量,用来接收数据类型:

 E e: Element 元素

 T t : Type 类型

 

如ArrayList<E>源码中也是使用的泛型。

创建对象的时候,会确定泛型的数据类型

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

会把握String赋值 给泛型E。

B T java 泛型 java泛型怎么用_B T java 泛型

 

 

 

泛型类

 

package com.fx;

/**
 * T: 参数化类型,只有在使用时要指定具体的类型
 * @param <T>
 */
public class Node<T> {
    private T data;

    public Node(){}
    public Node(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    } 

}
package com.fx;

import org.junit.jupiter.api.Test;

public class FxTest {

    @Test
    public void testNOde(){
        Node<String> n = new Node<>("111");
        System.out.println(n.getData());
    }
}

 

泛型普通方法和静态方法

 

package com.generic;


/**
 * 定义含有型的方法 :泛型定义在方法的修饰符和返回值类型之间
 */
public class GenericMethod {

    //定义一个含有泛型的方法
    //下面这个K也可以是任一其他字母
    public <K> void method01(K k){
        System.out.println(k);
    }

    定义一个含有泛型的静态方法
    public static<K> void  method02(K k){
        System.out.println(k);
    }
}

 

package com.generic;

import org.junit.jupiter.api.Test;

public class GenercMethodTest {

    @Test
    public void test01(){
        //调用含有泛型的方法method01
        //传递什么类型,泛型就是什么类型
        GenericMethod gm = new GenericMethod();
        gm.method01("这是一个字符串");
        gm.method01(11.22);
    }

    @Test
    public void test02(){
        //调用含有泛型的静态方法method01
        //传递什么类型,泛型就是什么类型
        GenericMethod.method02("这是一个字符串");
        GenericMethod.method02(11.22);
    }
}

 

接口中使用泛型

 

package com.itf;


/**
 * 定义含有泛型的接口
 * @param <I>
 */
public interface GenericInterface<I> {
    public abstract void method(I i);
}

第一种使用方式 : 实现类中指定接口的泛型

package com.itf;

/*
定义接口的实现类,实现接口,指定接口的泛型
 */
public class GenericInterfaceImpl1 implements GenericInterface<String>  {

    @Override
    public void method(String s) {
        System.out.println(s);
    }
}
package com.itf;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 测试含有泛型的接口
 */
class GenericInterfaceImpl1Test {

    @Test
    void method() {
        GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
        gi1.method("这是字符串");
    }
}

第二种方式:创建对象时指定泛型

package com.itf;

/**
 * 接口使用什么泛型,实现类就使用什么泛型,类跟着接口走
 * 也就是说定义了一个含有泛型的类,创建对象的时候确定泛型
 */
public class GenericInterfaceImpl2<I> implements GenericInterface<I> {
    @Override
    public void method(I i) {
        System.out.println(i);
    }
}

 

package com.itf;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

//测试含有泛型的接口,第二种方式
class GenericInterfaceImpl2Test {

    @Test
    void method() {
        //创建GenericInterfaceImpl2对象
        GenericInterface<Integer> gi2 = new GenericInterfaceImpl2();
        gi2.method(100);

        GenericInterface<String> gi3= new GenericInterfaceImpl2();
        gi3.method("100");

    }
}

 

泛型通配符?

当使用泛型或接口时,传递的数据中,泛型不确定,可以通过通配符<?>表示,但只要使用通配符后,只能使用Object类中的共性方法了,集合中元素自身方法无法使用。

通配符基本使用

不知道使用什么类型来接收的时候,可以使用泛型?,?表示未知道通配符,

此时只能接受数据,不能往集合中存储数据

 

package com.itf;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * 泛型的通配符:
 *    ?: 代表任意的数据类型
 * 使用方式:
 *    不能创建对象时使用
 *    只能作为方式的参数使用
 */
public class GenericDemo {
    public static void main(String[] args) {
        ArrayList<Integer> list01 = new ArrayList<>();
        list01.add(1);
        list01.add(2);

        ArrayList<String> list02 = new ArrayList<>();
        list02.add("a");
        list02.add("b");

        listArray(list01);
        listArray(list02);
    }

    /**
     * 这时候我们不知道要接收的ArrayList集合使用什么数据类型,
     * 可以使用泛型的通配符?来接收数据类型
     * 注意:
     *    泛型没有继承的概念
     */
    public static void listArray(ArrayList<?> list){
        //使用迭代器遍历集合
        Iterator<?> it = list.iterator();
        while (it.hasNext()){
            //it.next()方法,取出来的元素是Object,可以接收任意数据类型
            Object o = it.next();
            System.out.println(o);
        }
    }
}

通配符高级使用 ---受限泛型

  上面设置泛型的泛型,实际上是可以任意设置的,只要是类就可以设置,但是在java的泛型中可以指定一个泛型的上限和下限。

泛型的上限:

   格式:类型名称<? extends 类> 对象名称

   意义:只能接收该及其子类

泛型的下限:

   格式:类型名称<? super类> 对象名称

   意义:只能接收该及其父类

 

 

package com.itf;

import java.util.ArrayList;
import java.util.Collection;

/**
 * 泛型的上限限定: ? extends E   代表使用的泛型只能是E类型的子类/本身
 * 泛型的下限限定: ? super E     代表使用的泛型只能是E类型的父类/本身
 */
public class GenercDemo02 {
    public static void main(String[] args) {
        Collection<Integer> list1 = new ArrayList<Integer>();
        Collection<String> list2 = new ArrayList<String>();
        Collection<Number> list3 = new ArrayList<Number>();
        Collection<Object> list4 = new ArrayList<Object>();

        getElement1(list1);
        getElement1(list2); //报错
        getElement1(list3);
        getElement1(list4);//报错

        getElement2(list1);//报错
        getElement2(list2);//报错
        getElement2(list3);
        getElement2(list4);
    }


    //泛型的上限: 此时的泛型?,必须是Number类型或Number类型的子类
    public static void getElement1(Collection<? extends  Number> coll){};
    
    //泛型的下限: 此时的泛型?,必须是Number类型或Number类型的父类
    public static void getElement2(Collection<? super  Number> coll){};
}