泛型使用详解

  • Post author:
  • Post category:其他


1.泛型

泛型类、泛型接口、泛型方法、Class<T>类传递及泛型数组

2.泛型作用在编译阶段

假如不使用泛型,使用Object,需要强制转换,且在编译阶段检测不出来;固后来有了泛型,在编译阶段进行检测。

3.各种泛型定义和使用方法

3.1 泛型类

//定义
class Point<T>{// 此处可以随便写标识符号 
    private T x ;      
    private T y ;      
    public void setX(T x){//作为参数
        this.x = x ;
    }
    public void setY(T y){
        this.y = y ;
    }
    public T getX(){//作为返回值
        return this.x ;
    }
    public T getY(){
        return this.y ;
    }
};
//IntegerPoint使用
Point<Integer> p = new Point<Integer>() ; 
p.setX(new Integer(100)) ; 
System.out.println(p.getX());  
 
//FloatPoint使用
Point<Float> p = new Point<Float>() ; 
p.setX(new Float(100.12f)) ; 
System.out.println(p.getX());  

3.2 泛型接口

interface Info<T>{		// 在接口上定义泛型
	public T getVar() ;	// 定义抽象方法,抽象方法的返回值就是泛型类型
	public void setVar(T var);
}
class InfoImpl<T> implements Info<T>{	// 定义泛型接口的子类
	private T var ;				// 定义属性
	public InfoImpl(T var){		// 通过构造方法设置属性内容
		this.setVar(var) ;	
	}
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
}
public class GenericsDemo24{
	public static void main(String arsg[]){
		InfoImpl<String> i = new InfoImpl<String>("harvic");
		System.out.println(i.getVar()) ;
	}
};

3.3 泛型方法

3.3.1 没有返回值的泛型方法

public class StaticFans {
	//静态函数
    public static  <T> void StaticMethod(T a){
        Log.d("harvic","StaticMethod: "+a.toString());
    }
	//普通函数
    public  <T> void OtherMethod(T a){
        Log.d("harvic","OtherMethod: "+a.toString());
    }
}

使用方法:
//静态方法
StaticFans.StaticMethod("adfdsa");//使用方法一
StaticFans.<String>StaticMethod("adfdsa");//使用方法二
 
//常规方法
StaticFans staticFans = new StaticFans();
staticFans.OtherMethod(new Integer(123));//使用方法一
staticFans.<Integer>OtherMethod(new Integer(123));//使用方法二

3.3.2 有返回值的泛型方法

public static <T> List<T> parseArray(String response,Class<T> object){
    List<T> modelList = JSON.parseArray(response, object);
    return modelList;
}

3.3.3返回值为数组

在写程序时,大家可能会遇到类似String[] list = new String[8];的需求,这里可以定义String数组,当然我们也可以定义泛型数组,泛型数组的定义方法为 T[],与String[]是一致的,下面看看用法:

//定义
public static <T> T[] fun1(T...arg){  // 接收可变参数  
       return arg ;            // 返回泛型数组  
}  
//使用
public static void main(String args[]){  
       Integer i[] = fun1(1,2,3,4,5,6) ;
       Integer[] result = fun1(i) ;
}  

3.4

使用Class<T>传递泛型类Class对象

有时,我们会遇到一个情况,比如,我们在使用JSON解析字符串的时候,代码一般是这样的

public static List<SuccessModel> parseArray(String response){
    List<SuccessModel> modelList = JSON.parseArray(response, SuccessModel.class);
    return modelList;
}

其中SuccessModel是自定义的解析类,代码如下,其实大家不用管SuccessModel的定义,只考虑上面的那段代码就行了。写出来SuccessModel的代码,只是不想大家感到迷惑,其实,这里只是fastJson的基本用法而已。

这段代码的意义就是根据SuccessModel解析出List<SuccessModel>的数组。

public class SuccessModel {
    private boolean success;
    
    public boolean isSuccess() {
        return success;
    }
 
    public void setSuccess(boolean success) {
        this.success = success;
    }
} 

首先,我们应该把SuccessModel单独抽出来做为泛型变量,但parseArray()中用到的SuccessModel.class要怎么弄呢?

先来看代码:

public static <T> List<T> parseArray(String response,Class<T> object){
    List<T> modelList = JSON.parseArray(response, object);
    return modelList;
}

注意到,我们用的Class<T> object来传递类的class对象,即我们上面提到的SuccessModel.class。

这是因为Class<T>也是一泛型,它是传来用来装载类的class对象的,它的定义如下:

public final class Class<T> implements Serializable {
	…………
}

4. 泛型默认类型,类型绑定

泛型默认继承Object,故泛型对象默认只能使用Object的方法。

有时候,你会希望泛型类型只能是某一部分类型,比如操作数据的时候,你会希望是Number或其子类类型。这个想法其实就是给泛型参数添加一个界限。其定义形式为:

class Fruit {
    private String name;
 
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

public static <T extends Fruit> String getFruitName(T t){
    return t.getName();
}

class Banana extends Fruit{
    public Banana(){
        setName("bababa");
    }
}
class Apple extends Fruit{
    public Apple(){
        setName("apple");
    }
}

String name_1 = getFruitName(new Banana());
String name_2 = getFruitName(new Apple());
Log.d(TAG,name_1);
Log.d(TAG,name_2);

输出结果

bababa

apple


绑定多个限定


上面我们讲了,有关绑定限定的用法,其实我们可以同时绑定多个绑定,用&连接,比如:

public static <T extends Comparable & Serializable, U extends Runnable> T foo(T a, U b){
	…………
}

5.通配符?

<? extends XXX>指填充为派生于XXX的任意子类的话,那么<? super XXX>则表示填充为任意XXX的父类!

?extends父类,?代表子类,故能取不能存;?super 子类,?代表子类,能存,不能取。

构造泛型实例时,如果省略了填充类型,则默认填充为无边界通配符!


?是通配符,泛指所有类型

一般用于定义一个引用变量,这么做的好处是,如下所示,定义一个sup的引用变量,就可以指向多个对象。

SuperClass<?> sup = new SuperClass<String>(“lisi”);

sup = new SuperClass<People>(new People());

sup = new SuperClass<Animal>(new Animal());

若不用?,用固定的类型的话,则:

SuperClass<String> sup1 = new SuperClass<String>(“lisi”);

SuperClass<People> sup2 = new SuperClass<People>(“lisi”);

SuperClass<Animal> sup3 = new SuperClass<Animal>(“lisi”);

这就是?通配符的好处。

参考:


https://qijian.blog.csdn.net/article/details/49883589


https://blog.csdn.net/harvic880925/article/details/49883589


https://www.cnblogs.com/jpfss/p/9929045.html