引言
Java的泛型(generics)是JDK5中引入的一个新特性,它提供了编译时类型安全的检测机制,该机制允许在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。下面我们分为四个部分进行讲解
泛型方法的规则:
1):泛型方法声明时候会有一个类型参数声明部分,是由尖括号<>进行分隔的,在方法的返回值类型之前。
2):每一个类型参数声明部分包含一个或者多个类型参数,参数间用逗号分隔,一个泛型参数也被称作一个类型变量,是用于指定一个泛型类型名称的标识符。
3):类型参数能够被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
4):泛型方法体的声明和其他方法一样,注意类型参数只能代表引用型类型,不能是原始类型。
- 泛型方法
public class PrintArray {
public static void main(String[] args) {
Integer[] integers = {1, 2, 3};
String[] strings = {"Hello", "World"};
printArray(integers);
printArray(strings);
}
/**
* 泛型打印数组
*
* @param array
* @param <T>
*/
public static <T> void printArray(T[] array) {
for (T t : array) {
System.out.print(" "+t);
}
System.out.println();
}
}
- 有界的类型参数
有时候我们传递参数的时候会对参数范围做一些限制,比如我只想传递某一个类或者他的子类,并不是所有的类都可以作为泛型的参数传进去,这时候就会使用到有界的类型参数;比如这里我自定义的一个适配器类,其中E就只能传递TemplateViewHolder或者它的子类才可以,否则会报错。
public abstract class TemplateListAdapter<T, E extends TemplateViewHolder> extends BaseAdapter {
public Context mContext;
public List<T> mData;
public LayoutInflater mInflater;
public TemplateListAdapter(Context context, List<T> data) {
mInflater = LayoutInflater.from(context);
mContext = context;
mData = data;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
E holder;
if (convertView == null) {
convertView = mInflater.inflate(getLayoutID(), null);
holder = getViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (E) convertView.getTag();
}
bindData(position, holder);
return convertView;
}
protected abstract void bindData(int position, E holder);
protected abstract E getViewHolder(View convertView);
protected abstract int getLayoutID();
}
- 泛型类
在实际的开发中,泛型类非常实用,比如我们将通过接口返回的数据的模板固定,那么我们只需要将真正的数据使用泛型来传递即可,例子如下:
class Result<T> {
private T data;
private int code;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public static void main(String[] args) {
Result<String> stringResult = new Result<>();
stringResult.setData("Hello World");
System.out.println("String:"+stringResult.getData());
Result<Integer> intResult = new Result<>();
intResult.setData(123456789);
System.out.println("Integer:"+intResult.getData());
}
}
结果是:
- 类型通配符
1 类型通配符一般是使用?来代替的,可以传入任意类型的参数,和泛型E的区别就是不需要在返回值类型前面加上尖括号<>
2 类型通配符还可以使用
public class PrintArray {
public static void main(String[] args) {
Integer[] integers = {1, 2, 3};
String[] strings = {"Hello", "World"};
printArray(integers);
printArray(strings);
List<String> list = new ArrayList<>();
list.add("hello");
printArray(list);
List<Integer> list1 = new ArrayList<>();
list1.add(23);
printArray2(list1);
List<Number> list2 = new ArrayList<>();
list2.add(2.5);
printArray3(list2);
}
/**
* 泛型打印数组
*
* @param array
* @param <T>
*/
public static <T> void printArray(T[] array) {
for (T t : array) {
System.out.print(" " + t);
}
System.out.println();
}
/**
* 泛型打印集合
*
* @param data
* @param <E>
*/
public static <E> void printArray(List<E> data) {
System.out.println("泛型:"+data.get(0));
}
/**
* 类型通配符打印数据
* @param data
*/
public static void printArray2(List<?> data) {
System.out.println("类型通配符?:"+data.get(0));
}
public static void printArray3(List<? extends Number> data) {
System.out.println("类型通配符extends:"+data.get(0));
}
}