【转】java 总结:泛型

参考java泛型操作复习,以及讲解在android中使用的场景
Java总结篇系列:Java泛型
java泛型与数组

android使用泛型的地方很多,比如集成自BaseAdapter实现封装的Adapter,对常用操作进行封装,但是需要对传进来的数据进行处理,此时就使用到泛型,示例如下:

public abstract class EasyAdapter<T> extends BaseAdapter {
    private LayoutInflater inflater;
    private int layoutId;
    private List<T> mlist = new ArrayList<T>();

    public EasyAdapter(Context context, int layoutId, List<T> list) {
        super();
        this.inflater = LayoutInflater.from(context);
        this.layoutId = layoutId;
        this.mlist = list;
    }

    /**
     * 往顶部添加数据
     * 
     * @param list
     */
    public void add2Head(List<T> list) {
        mlist.addAll(0, list);
        notifyDataSetChanged();
    }
    
    public void clearAll() {
        mlist.clear();
        notifyDataSetChanged();
    }

    public List<T> getAllList() {
        return mlist;
    }

    /**
     * 往底部添加数据
     * 
     * @param list
     */
    public void add2Bottom(List<T> list) {
        mlist.addAll(list);
        notifyDataSetChanged();
    }

    public void add2Bottom(T t) {
        mlist.add(t);
        notifyDataSetChanged();
    }

    /**
     * @Title: updateListView
     * @Description: TODO(更新BaseAdapter中的数据)
     * @param @param list 设定文件
     * @return void 返回类型
     * @throws
     */
    public void updateListView(List<T> list) {
        mlist = list;
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return mlist.size();
    }

    @Override
    public T getItem(int position) {
        return mlist.get(position);
    }

    @Override
    public long getItemId(int position) {

        return position;
    }

    /**
     * 实际显示View的方法,使用抽象方法强制调用者覆写!
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder viewHolder = ViewHolder.getViewHolder(parent, convertView,
                inflater, layoutId);
        convert(viewHolder, mlist.get(position));
        return viewHolder.getConvertView();

    }

    public abstract void convert(ViewHolder viewHolder, T t);

}

还有 如 使用Gson来解析json数据,json数据对应的bean实体类各有不同:

public class GsonImpl extends Json {
    private Gson gson = new Gson();

    @Override
    public String toJson(Object src) {
        return gson.toJson(src);
    }

    @Override
    public <T> T toObject(String json, Class<T> claxx) {
        return gson.fromJson(json, claxx);
    }

    @Override
    public <T> T toObject(byte[] bytes, Class<T> claxx) {
        return gson.fromJson(new String(bytes), claxx);
    }

    @Override
    public <T> List<T> toList(String json, Class<T> claxx) {
          Type type = new TypeToken<ArrayList<T>>() {}.getType();  
             List<T> list = gson.fromJson(json, type);  
        return list;
    }

}

什么是泛型?

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

举个栗子:

public class GenericTest {

    public static void main(String[] args) {
       
        List<String> list = new ArrayList<String>();
        list.add("qq");
        list.add("im");
        //list.add(100);   // 1  提示编译错误

        for (int i = 0; i < list.size(); i++) {
            String name = list.get(i); // 2
            System.out.println("name:" + name);
        }
    }
}

采用泛型写法后,在//1处想加入一个Integer类型的对象时会出现编译错误,通过List,直接限定了list集合中只能含有String类型的元素,从而在//2处无须进行强制类型转换,因为此时,集合能够记住元素的类型信息,编译器已经能够确认它是String类型了。

结合上面的泛型定义,我们知道在List中,String是类型实参,也就是说,相应的List接口中肯定含有类型形参。且get()方法的返回结果也直接是此形参类型(也就是对应的传入的类型实参)。

java基础中有关泛型的知识点:

首先:泛型是java1.5提供的新特性;主要是为了解决数据类型的安全性问题,是在类声明的时候通过一个标示表示类中某个属性的类型或者是某个方法的返回值以及参数类型。这样在类声明或者实例化的时候只要指定好需要的类型即可。

泛型定义方法如下:
在这里插入图片描述
实际使用方式:
在这里插入图片描述
能够更好的保护数据类型,避免编译时出错。减少类型转换的代码。

当然可以通过设置构造方法的参数为泛型来进行泛型操作的值传递。

泛型的安全警告:
在这里插入图片描述

通配符

在开发中对象的引用传递是最常见的,但是在泛型操作中,进行引用传递的时候泛型必须匹配才可以传递,否则无法传递

class Info<T>{
    private T var ;        // 定义泛型变量
    public void setVar(T var){
        this.var = var ;
    }
    public T getVar(){
        return this.var ;
    }
    public String toString(){    // 直接打印
        return this.var.toString() ;
    }
};
public class GenericsDemo14{
    public static void main(String args[]){
        Info<String> i = new Info<String>() ;        // 使用String为泛型类型
        i.setVar("MLDN") ;                            // 设置内容
        fun(i) ;
    }
    public static void fun(Info<?> temp){        // 可以接收任意的泛型对象
        System.out.println("内容:" + temp) ;
    }
};

使用?可以接受任意类型的数据,却无法进行修改,?就是通配符

受限泛型

在这里插入图片描述

泛型与数组

java中数组是不支持泛型的,原因是:

泛型只是在编译的时候,起到类型检测,及类型转换字节码的生成,也就是说具有泛型的java文件,最终生成的字节码会将泛型信息抹去,具体数据的引用类型一般都用object的来替代。并在对应的位置加上了类型转换代码。

Java中规定数组在实例化的时候,需要确切的知道存放数据的类型(这样更方便的操作使用数组)。也就是说假设数组支持泛型,那么在编译成字节码的时候对于T[] = new T[10];最终会编译成Object[] objects=new Object[10],也就是说数组的具体类型在运行期间为object 类型,这时候对于数组内的元素操作可以强转也可以正常使用。但是编译器生成字节码的时候也有可能生成 (String[])(Objects) 这样的强转代码(出现转换错误)

包装类实现泛型数组:

例子1 利用object数组间接实现泛型数组:
GenericArray.java

public class GenericArray<T> {
    private Object[] values;

    public GenericArray(int count){

        values = new Object[count];

    }

    public void setValue(T t,int position){

        values[position] = t;
    }

    public T getValue(int position){

        return (T)values[position];
    }

    //注意此句代码调用会出错
    public T[] getValues(){

        return (T[])values;
    }
}

测试代码:

public class Test {

    public static void main(String[] args) {

        GenericArray<String> generic=new GenericArray(10);

        generic.setValue("wenwei1", 0);
        generic.setValue("wenwei2", 1);

        System.out.println(generic.getValue(0));
        System.out.println(generic.getValue(1));
        //
        String[]content = generic.getValues();
        }
    }

执行结果:
在这里插入图片描述
分析:上面代码可以编译通过,而且我们使用GenericArray存储数据可以正常使用,但当我们调用其getValues则会出现强转类型错误(这种错误就是我们在概述中分析的编译器生成强转代码造成的)。

例子2 利用类型标识间接实现泛型数组:
GenericArray1.java

public class GenericArray1 <T>{
    private T[] values;

    public GenericArray1(Class<T> type,int length){
        values= (T[])Array.newInstance(type, length);
    }

    public void setValue(T t,int position){

        values[position] = t;
    }

    public T getValue(int position){

        return (T)values[position];
    }

    public T[] getValues(){

        return values;
    }


}

测试代码:

public class Test {

    public static void main(String[] args) {

        GenericArray1<String> generic=new GenericArray1<String>(String.class,10);

        generic.setValue("wenwei1", 0);
        generic.setValue("wenwei2", 1);

        System.out.println(generic.getValue(0));
        System.out.println(generic.getValue(1));

        String[]content = generic.getValues();
        System.out.println(content[0]);
        }
    }   

运行结果:
在这里插入图片描述
分析:上面代码可以编译通过,我们使用GenericArray存储数据可以正常使用,而且调用其getValues也不会出现强转类型错误,这种方式比较推荐(因为我们调用Array.newInstance()生成的数组是String[]类型的数组)。

补充说明:对于泛型数组,最简单的我们可以利用容器List来模拟实现!

猜你喜欢

转载自blog.csdn.net/weixin_43115440/article/details/90607736