java泛型yyds

泛型的运用


1.泛型举例

1.泛型类,如果没有指定具体的数据类型,此时,操作类型是0bject
2.泛型的类型参数只能是类类型,不能是基本数据类型
3.泛型类型在逻辑上可以看成是多个不同的类型,但实际上都是相同类型

泛型举例

package com.lb.generic.example;

import javax.lang.model.element.VariableElement;
import java.util.ArrayList;
import java.util.Random;
public class ProductGetter<T> {
    private T product;

    ArrayList<T> list=new ArrayList<>();

    Random random=new Random();
    /**
     * 添加产品
     * */
    public void addProduct(T t){
        list.add(t);
    }
    /**
     * 获取产品
     * */
    public T getProduct(){
       product=list.get(random.nextInt(list.size()));
        return product;
    }

}

测试:

package com.lb.generic.example;

public class TestProduct {

    public static void main(String[] args) {
        ProductGetter<String> productGetter = new ProductGetter<>();
        String [] product={"产品1","产品2"};
        for (String s : product) {
            productGetter.addProduct(s);
        }
        String product1 = productGetter.getProduct();
        System.out.println("获取到产品:"+product1);

    }
}

2.泛型类的继承情况

1.泛型类的子类要保证和父类的泛型要一致

语法:class ChildGeneric<T> extends Generic<T>
package com.lb.generic.extenttest;

/**
 * @description  带泛型的父类
 */
public class Parent<E> {
    private E value;

    public E getValue() {
        return value;
    }

    public void setValue(E value) {
        this.value = value;
    }
}

package com.lb.generic.extenttest;

/**
 * @description 泛型类派生子类,子类也是泛型类,那么子类的泛型标识要和父类一致(都为T)
 */
public class ChildOne<T> extends Parent<T> {
    @Override
    public T getValue() {
        return super.getValue();
    }
}

2.子类不是泛型类,父类要明确泛型的数据类型

class ChildGeneric extends Generic<String>  //这里的String指明了泛型的类型
package com.lb.generic.extenttest;

/**
 * @description 泛型类派生子类,子类不是泛型,父类要指明泛型的具体数据类型
 */
public class ChildTwo extends Parent<String> {
    @Override
    public String getValue() {
        return super.getValue();
    }
}

3.泛型接口

泛型接口声明语法

interface    接口名称〈泛型标识,泛型标识,>{
    泛型标 识方法名();
}

泛型接口的使用

1.实现类不是泛型类,接口要明确数据类型
2.实现类也是泛型类,实现类和接口的泛型类型要一致
package com.lb.generic.interfaces;

/**
 * @description  泛型接口
 */
public interface Generator<E> {
    E getName();
}

package com.lb.generic.interfaces;

/**
 * @description  实现泛型的接口不是泛型类,需要明确实现泛型接口的数据类型)(不明确指明为Object类型)
 */
public class TestOne implements Generator<String> {
    @Override
    public String getName() {
        return "test Interface";
    }
}

package com.lb.generic.interfaces;

/**
 * @description 泛型接口的实现类是一个泛型类,要保证实现接口类的泛型标识包含泛型接口的泛型标识(T)
 */
public class TestTwo<T,M> implements Generator<T> {
    private T name;
    private M age;

    public TestTwo(T name, M age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public T getName() {
        return name;
    }

    public void setName(T name) {
        this.name = name;
    }

    public M getAge() {
        return age;
    }

    public void setAge(M age) {
        this.age = age;
    }
}

4.泛型方法

1.泛型类,是在实例化类的时候指明泛型的具体类型。比如创建一个集合(List<String> lsit=new ArrayList<>())
2.泛型方法,是在调用方法的时候指明泛型的具体类型。

声明泛型方法的语法

修饰符  <TE, ...>  返回值类型方法名(形参列表) {
    方法体...
}
1.public与返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
2.只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
3.<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
4.与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
package com.lb.generic.genericmethod;

import com.lb.generic.example.ProductGetter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

/**
 * @description 泛型方法
 */
public class GengericMethod {

    /**
     * 泛型方法
     * @param <E>  泛型标识,具体类型you调用该方法的时候指定
     * @param list 参数
     */
    public <E> E getProduct(ArrayList<E> list) {
        return list.get(new Random().nextInt(list.size()));
    }

    public static void main(String[] args) {
        GengericMethod gengericMethod = new GengericMethod();
        ArrayList<String> name = new ArrayList<>();
        name.add("xiong");
         name.add("bear");
        String product = gengericMethod.getProduct(name);
        System.out.println(product);
    }
}
静态泛型方法
    /**
     * 静态的泛型方法,采用多个泛型类型
     * */
    public static <T,E,K> void getType(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());

    }
 public static void main(String[] args) {
        GengericMethod.getType(100,"java",true);
    }
输出:
100	    Integer
java	String
true	Boolean

泛型方法可变参数
//可变参数的定义
public <E> void print(E... e){
    for (E el : e){
        System. out.println(e);
    }
}
    /**
     * 可变参数的泛型方法
     * */
    public static  <E> void print(E... e){
        for (E el : e){
            System.out.println(el+"\t"+el.getClass().getSimpleName());
        }
    }

 public static void main(String[] args) {
        GengericMethod.print(100,"test",true,new Object());
    }
输出:
100	    Integer
test	String
true	Boolean
java.lang.Object@4a574795	Object
1.泛型方法能使方法独立于类而产生变化
2.如果static方法要使用泛型能力,就必须使其成为泛型方法

5.类型统配符(Type wildcard)

类型通配符一般是使用"?"代替具体的类型实参。
所以,类型通配符是类型实参,而不是类型形参。
package com.lb.generic.typewildcard;
/**
 * @description 类型通配符
 */
public class TypeWildcard<E> {
    private E test;

    public E getTest() {
        return test;
    }
    public void setTest(E test) {
        this.test = test;
    }
}

package com.lb.generic.typewildcard;

/**
 * @description
 */
public class TestType {

    public static void main(String[] args) {
        //使用了“?”通配符后就能穿任意类型的数据作为参数了(如下面的Number类型和String类型)
        TypeWildcard<Number> typeWildcard = new TypeWildcard<>();
        typeWildcard.setTest(1000);
        testType(typeWildcard);
        TypeWildcard<String> wildcard = new TypeWildcard<>();
        wildcard.setTest("1000");
        testType(wildcard);
    }

    /**
     * ?代表任意的参数类型
     * */
    public static void testType(TypeWildcard<?> box) {
        Object test = box.getTest();
        System.out.println(test);
    }
}

类型通配符的上限

语法:

/接口<? extends 实参类型>
要求该泛型的类型,只能是实参类型,或实参类型的子类类型。
//三个类 Animal->dog->SiberianHuskyDog
package com.lb.generic.typewildcard;

/**
 * @description 测试类型通配符上下限(动物类)
 */
public class Animal {

}

package com.lb.generic.typewildcard;

/**
 * @description  狗狗类
 */
public class Dog extends Animal{
}

package com.lb.generic.typewildcard;

/**
 * @description 哈士奇狗狗
 */
public class SiberianHuskyDog extends Dog{
}


package com.lb.generic.typewildcard;
import java.util.ArrayList;
/**
 * @description
 */
public class TestAnimal {
    public static void main(String[] args) {
        ArrayList<Animal> animals=new ArrayList<>();
        ArrayList<Dog> dogs=new ArrayList<>();
        ArrayList<SiberianHuskyDog> hsq=new ArrayList<>();
        showAnimal(animals);//会报错(上限超过了Dog)
        showAnimal(dogs);//正常
        showAnimal(hsq);//正常
        ///
        dogs.addAll(animals);//会报错(上限超过了Dog)
        dogs.addAll(hsq);//正常
    }

    /**
     * 泛型的上限统配符只能是Dog(<? extends Dog>)也就是只能是继承的父类,不能超过父类
     * */
    public static void showAnimal(ArrayList<? extends Dog> list) {
        //上限统配符不允许添加元素
        //list.add(new Dog());//会报错
        //list.add(new SiberianHuskyDog());//会报错
        for (int i = 0; i < list.size(); i++) {
            Dog dog = list.get(i);
            System.out.println(dog);
        }
    }
}

类型通配符下限

语法:

/接口<? super实参类型>
要求该泛型的类型,只能是实参类型,或实参类型的父类类型。
package com.lb.generic.typewildcard;

import java.util.ArrayList;
import java.util.List;
/**
 * @description 类型通配符下限制
 */
public class LowLine {
    public static void main(String[] args) {
        ArrayList<Animal> animals=new ArrayList<>();
        ArrayList<Dog> dogs=new ArrayList<>();
        ArrayList<SiberianHuskyDog> hsq=new ArrayList<>();
        showAnimal(animals);//正常不会错
        showAnimal(dogs);
        //showAnimal(hsq);//会报错
    }

    /**
     * 类型通配符下限,要求只能是Dog本身或者Dog的父类
     * */
    public static void showAnimal(List<? super Dog> list){
        list.add(new Dog());//添加本身
        list.add(new SiberianHuskyDog());//可以添加,因为上限是Object(所有类的父类)
        for (Object o : list) {
            System.out.println(o);
        }
    }
}

下限通配符(TreeSet)
package com.lb.generic.typewildcard;
public class Animal {
    public String name;

    public Animal(String name) {
        this.name = name;
    }
    public Animal() {

    }
    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                '}';
    }
}


package com.lb.generic.typewildcard;

/**
 * @description  狗狗类
 */
public class Dog extends Animal{
    public int age;

    public Dog(String name, int age) {
        super(name);
        this.age = age;
    }

    public Dog() {
        super();
    }
    @Override
    public String toString() {
        return "Dog{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
///
package com.lb.generic.typewildcard;

/**
 * @description 哈士奇狗狗
 */
public class SiberianHuskyDog extends Dog{
    public String color;

    public SiberianHuskyDog(String name, int age, String color) {
        super(name, age);
        this.color = color;
    }

    public SiberianHuskyDog() {
        super();
    }

    @Override
    public String toString() {
        return "SiberianHuskyDog{" +
                "color='" + color + '\'' +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}


package com.lb.generic.typewildcard;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;

/**
 * @description 类型通配符下限制
 */
public class LowLine {
    public static void main(String[] args) {
        TreeSet<Dog> treeSet = new TreeSet<>(new Comparator1());//正常
        //TreeSet<Dog> treeSet2 = new TreeSet<>(new Comparator2());//正常
        //TreeSet<Dog> treeSet3 = new TreeSet<>(new Comparator3());//报错)(下限通配符)
        treeSet.add(new Dog("二哈",2));
        treeSet.add(new Dog("二哈1",2));
        treeSet.add(new Dog("二哈2",2));
        treeSet.add(new Dog("二哈3",2));
        treeSet.add(new Dog("二哈4",2));
        for (Dog dog : treeSet) {
            System.out.println(dog);
        }
    }
}
class Comparator1 implements Comparator<Animal> {
    @Override
    public int compare(Animal o1, Animal o2) {
        return o1.name.compareTo(o2.name);
    }
}
class Comparator2 implements Comparator<Dog> {

    @Override
    public int compare(Dog o1, Dog o2) {
        return o1.age-o2.age;
    }
}

class Comparator3 implements Comparator<SiberianHuskyDog> {
    @Override
    public int compare(SiberianHuskyDog o1, SiberianHuskyDog o2) {
        return o1.color.compareTo(o2.color);
    }
}
///
TreeSet构造器源码:下限通配符
   public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }

6.类型檫除

泛型是Java 1.5版本才引进的概念,在这之前是没有泛型的,但是,泛型代码能够很好地和之前版本的代码兼容。那是因为,泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉,我们称之为–类型擦除。

无限制类型檫除
package com.lb.generic.typeremove;
/**
 * @description
 */
public class Erasure<T> {
    private T test;

    public T getTest() {
        return test;
    }
    public void setTest(T test) {
        this.test = test;
    }
}

package com.lb.generic.typeremove;

import java.lang.reflect.Field;
import java.util.ArrayList;

/**
 * @description 类型檫除(无限制类型檫除)
 */
public class TypeDisapper {

    public static void main(String[] args) {
        //ArrayList<Integer> integers = new ArrayList<>();
        //ArrayList<String> strings = new ArrayList<>();
        //反射获取当前类的字节码文件的class类对象
        Erasure<Integer> erasure = new Erasure<>();
        Class<? extends Erasure> aClass = erasure.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();//获取所有的成员变量
        for (Field declaredField : declaredFields) {
            //打印成员变量的名称和类型
            System.out.println(declaredField.getName() + "    " + declaredField.getType().getSimpleName());
            //输出:test    Object      实际传的是一个Integer( Erasure<Integer>)但是得到的是一个Object(说明进行了类的一个檫除)
        }

    }
}
有限制类型檫除
package com.lb.generic.typeremove;

public class Erasure1<T extends Number> {
    private T test;
    public T getTest() {
        return test;
    }
    public void setTest(T test) {
        this.test = test;
    }
}

package com.lb.generic.typeremove;

import java.lang.reflect.Field;
import java.util.ArrayList;

/**
 * @description 类型檫除(无限制类型檫除)
 */
public class TypeDisapper {

    public static void main(String[] args) {
        //反射获取当前类的字节码文件的class类对象
        Erasure1<Integer> erasure = new Erasure1<>();
        Class<? extends Erasure1> aClass = erasure.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();//获取所有的成员变量
        for (Field declaredField : declaredFields) {
            //打印成员变量的名称和类型
            System.out.println(declaredField.getName() + "    " + declaredField.getType().getSimpleName());
            //输出:test    Number     实际传的是一个Integer但是得到的是一个Number(说明进行了类的上限通配符)
        }

    }
}

檫除方法中类型定义的参数
package com.lb.generic.typeremove;
import java.util.List;
public class Erasure1<T extends Number> {

    private T test;

    public T getTest() {
        return test;
    }

    public void setTest(T test) {
        this.test = test;
    }
    /**
     * 泛型方法
     * */
    public <T extends List> T test(T t){
        return t;
    }
}

package com.lb.generic.typeremove;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * @description 类型檫除(檫除方法中类型定义的参数)
 */
public class TypeDisapper {

    public static void main(String[] args) {
        //反射获取当前类的字节码文件的class类对象
        Erasure1<Integer> erasure = new Erasure1<>();
        Class<? extends Erasure1> aClass = erasure.getClass();
        //获取类中的方法
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            System.out.println("方法名:"+method.getName()+"  返回值类型: "+method.getReturnType().getSimpleName());
        }
        //输出:方法名:test  返回值类型: List
        //     方法名:setTest  返回值类型: void
        //     方法名:getTest  返回值类型: Number
    }
}

桥接方法
package com.lb.generic.typeremove;

/**
 * @description  泛型接口(测试桥接方法)
 */
public interface testInfo<T> {
    T info(T t);
}

package com.lb.generic.typeremove;

import java.lang.reflect.Method;

/**
 * @description 桥接方法
 */
public class TestInfoImpl implements testInfo<Integer> {
    @Override
    public Integer info(Integer integer) {
        return integer;
    }

    public static void main(String[] args) {
        TestInfoImpl testInfo = new TestInfoImpl();
        Class<? extends TestInfoImpl> aClass = testInfo.getClass();
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("方法名:"+declaredMethod.getName()+"  "+declaredMethod.getReturnType().getSimpleName());
        }
        //输出:方法名:info  Integer
        //      方法名:info  Object
    }
}

7.泛型与数组

可以声明带泛型的数组引用,但是不能直接创建带泛型的数组对象
可以通过java.lang.reflect.Array的newInstance(Class<T>, int)创建T[]数组

package com.lb.generic.array;

import java.lang.reflect.Array;

/**
 * @Date 2022/1/13
 * @description
 */
public class Demo<T> {

    private T[] array;

    public Demo(Class<T> tClass,int length){
        //可以通过java.lang.reflect.Array的newInstance(Class<T>, int)创建T[]数组
        array= (T[]) Array.newInstance(tClass,length);
    }
    public void put(int index,T item){
        array[index]=item;
    }

    public T get(int index){
        return array[index];
    }

    public T[] getAll(){
        return array;
    }
}

package com.lb.generic.array;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * @Date 2022/1/13
 * @description
 */
public class ArrayAndGeneric {
    public static void main(String[] args) {
        //可以声明带泛型的数组引用,但是不能直接创建带泛型的数组对象
        ArrayList<String>[] arrayLists = new ArrayList[5];
        ///ArrayList<String>[] lists= arrayLists;

        //可以通过java.lang.reflect.Array的newInstance(Class<T>, int)创建T[]数组
        Demo<String> objectDemo = new Demo<>(String.class,3);
        objectDemo.put(0,"luoxiong");
        objectDemo.put(1,"test");
        objectDemo.put(2,"haha");
        System.out.println(Arrays.toString(objectDemo.getAll()));


    }
}

~~~java

T item){
        array[index]=item;
    }

    public T get(int index){
        return array[index];
    }

    public T[] getAll(){
        return array;
    }
}

package com.lb.generic.array;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * @Date 2022/1/13
 * @description
 */
public class ArrayAndGeneric {
    public static void main(String[] args) {
        //可以声明带泛型的数组引用,但是不能直接创建带泛型的数组对象
        ArrayList<String>[] arrayLists = new ArrayList[5];
        ///ArrayList<String>[] lists= arrayLists;

        //可以通过java.lang.reflect.Array的newInstance(Class<T>, int)创建T[]数组
        Demo<String> objectDemo = new Demo<>(String.class,3);
        objectDemo.put(0,"luoxiong");
        objectDemo.put(1,"test");
        objectDemo.put(2,"haha");
        System.out.println(Arrays.toString(objectDemo.getAll()));


    }
}

到此结束!每天学习一个小技巧!哈哈哈

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值