Java泛型的应用

---恢复内容开始---

在开发中,我们有时候会用到泛型来写工具类,为了使方法更通用,以前,没有完全弄懂,今天,就这个机会把泛形写一写

泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。泛型的引入,让JAVA更安全。之前没有引入泛型,各种的类型转换错误。

泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

我们见不各种泛型的字母通配符TEKV等等还有?,其实这些字母只约定,实际中使用什么字母都可以,以下是约定:

  •  表示不确定的java类型
  • T (type) 表示具体的一个java类型
  • K V (key value) 分别代表java键值中的Key Value
  • E (element) 代表Element


 import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) {


    }

    public <T>  void aa(T t){
        ArrayList<?> al=new ArrayList<T>();
    }
}

这种方式 正确

 ArrayList<?> al=new ArrayList<T>();

扫描二维码关注公众号,回复: 4622581 查看本文章

但是这样就不行了,后面只能是具体类型,不能是通配符,前边是可以的

 ArrayList<?> al=new ArrayList<?>();

?和T都表示不确定的类型 ,但如果是T的话,函数里面可以对T进行操作,比方 T car = getCar(),而不能用? car = getCar()

Class<T>在实例化的时候,T要替换成具体类

Class<?>它是个通配泛型,?可以代表任何类型,主要用于声明时的限制情况

public class Test {
    public static <T> T createInstance(Class<T> clazz) throws IllegalAccessException, InstantiationException {
        return clazz.newInstance();
    }

    public static void main(String[] args)  throws IllegalAccessException, InstantiationException  {
            Fruit fruit= createInstance(Fruit .class);
            People people= createInstance(People.class);
    }
}

class Fruit{
    
}
class People{
    
}

上面的类使用Class<T>泛型后,newInstance不用强转

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
 
//虽然Test<T1,T2>,但类名字仍为Test。T1,T2只是告诉我们new的时候要加入泛型,更方便通用
//T1,T2可以任意定义,比如改成K,V都可以
//他们不会关联到其他类,只是在本类中通用
public class Test<T1, T2> {
    public static void main(String[] args) {
        System.out.println(new Test().getT1());
        System.out.println(new Test().getT2());
        new Test<String, String>().getClassName("");//T1,T2在new的时候用到,这里都为String
        new Test().getClassAndList(Integer.class);
        //HashMap的括号里面不能是T,E,T1,T2等不确定的东西,但可以是?
        HashMap<?, ?> map = new HashMap<Object, String>();
        List<?> list = new ArrayList<String>();
    }
 
    public T1 getT1() {
        //这里的“T1”替换成1或1.0都会报错
        return (T1) "T1";
 
    }
 
    T2 getT2() {
        //将自动转型为String
        return (T2) "T2";
 
    }
 
    public <T> void getClassName(T x) {
        //<T>必须放在void或者返回类型的前面
        System.out.println(x.getClass().getName());
    }
 
    public <T> Class<?> getClassAndList(Class<?> a) {
        //Class<T>前面缺少<T>必须定义,否则将出现编译错误
        //T改成其他字母都可以,但一定要声明
        // 返回类型和参数中的类型:Class<T>和Class<?>都可以。因为返回的a的类型为Class<T>,Class<?>可以通配
        //当两个都是Class<?>,参数中的?自动通配成T
        System.out.println(a.getClass().getName());//传入的a是一个类,Class类型
        //参数里面的Class<T>最大的好处是如果方法里面定义了泛型,可以自动获取类型值,比如如下的List<T>可以自动获取到a的类型,不必强调死
        List<?> aa = new ArrayList<T>();
        //List<?> aa = new ArrayList<?>();会报错,以为ArrayList必须是一种类型,List<>起到通配的作用
        //List<T> aa = new ArrayList<T>();当然正确
        System.out.println(aa);
        return a;
    }
}

这个例子说明泛型可以是任何字母

public class GenericTest {

     public static void main(String[] args) {

         Box<String> name = new Box<String>("corn");
         Box<Integer> age = new Box<Integer>(712);
         Box<Number> number = new Box<Number>(314);

         getData(name);
         getData(age);
         getData(number);

         //getUpperNumberData(name); // 1
         getUpperNumberData(age);    // 2
         getUpperNumberData(number); // 3
     }

     public static void getData(Box<?> data) {
         System.out.println("data :" + data.getData());
     }

     public static void getUpperNumberData(Box<? extends Number> data){
         System.out.println("data :" + data.getData());
     }

 }
class Box<T> {

 private T data;

 public Box() {

 }

 public Box(T data) {
  setData(data);
 }

 public T getData() {
  return data;
 }

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

}

Box<? extends Number> 问号也可以通过这种方式代表,传入的都是Nubmber的子类

猜你喜欢

转载自www.cnblogs.com/vkbwxdx/p/10166309.html