Android/Java 泛型全面详解
1. 泛型的基本概念
什么是泛型?
泛型是Java 5引入的特性,允许在定义类、接口和方法时使用类型参数,提供编译时类型安全检查。
核心概念
// 泛型类
public class Container<T> {private T item;public void setItem(T item) {this.item = item;}public T getItem() {return item;}
}// 使用
Container<String> stringContainer = new Container<>();
stringContainer.setItem("Hello");
String value = stringContainer.getItem(); // 无需强制转换
2. 泛型语法详解
类型参数命名约定
T
- Type(类型)E
- Element(元素,常用于集合)K
- Key(键)V
- Value(值)N
- Number(数字)S
,U
,V
- 第二、第三、第四类型
多类型参数
public class Pair<K, V> {private K key;private V value;public Pair(K key, V value) {this.key = key;this.value = value;}public K getKey() { return key; }public V getValue() { return value; }
}// 使用
Pair<String, Integer> pair = new Pair<>("age", 25);
3. 泛型的使用场景
场景1:集合框架(最常用)
// 没有泛型(Java 5之前)
List list = new ArrayList();
list.add("hello");
list.add(123); // 允许,但危险
String item = (String) list.get(0); // 需要强制转换// 使用泛型
List<String> stringList = new ArrayList<>();
stringList.add("hello");
// stringList.add(123); // 编译错误!
String item = stringList.get(0); // 自动类型推断
场景2:Android RecyclerView Adapter
public abstract class BaseRecyclerAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {protected List<T> dataList = new ArrayList<>();public void updateData(List<T> newData) {dataList.clear();dataList.addAll(newData);notifyDataSetChanged();}public void addItem(T item) {dataList.add(item);notifyItemInserted(dataList.size() - 1);}public T getItem(int position) {return dataList.get(position);}@Overridepublic int getItemCount() {return dataList.size();}
}// 具体实现
public class UserAdapter extends BaseRecyclerAdapter<User, UserAdapter.ViewHolder> {static class ViewHolder extends RecyclerView.ViewHolder {TextView tvName, tvEmail;ViewHolder(View itemView) {super(itemView);tvName = itemView.findViewById(R.id.tv_name);tvEmail = itemView.findViewById(R.id.tv_email);}}@Overridepublic void onBindViewHolder(ViewHolder holder, int position) {User user = getItem(position);holder.tvName.setText(user.getName());holder.tvEmail.setText(user.getEmail());}
}
场景3:Retrofit网络请求
public interface ApiService {@GET("users/{id}")Call<User> getUser(@Path("id") String id);@GET("users")Call<List<User>> getUsers();@POST("users")Call<ApiResponse<User>> createUser(@Body User user);
}// 通用响应包装类
public class ApiResponse<T> {private boolean success;private String message;private T data;// getters and setters
}
场景4:ViewModel with LiveData
public class DataViewModel<T> extends ViewModel {private MutableLiveData<T> data = new MutableLiveData<>();private MutableLiveData<String> error = new MutableLiveData<>();private MutableLiveData<Boolean> loading = new MutableLiveData<>();public LiveData<T> getData() { return data; }public LiveData<String> getError() { return error; }public LiveData<Boolean> getLoading() { return loading; }protected void setData(T data) {this.data.setValue(data);loading.setValue(false);}protected void setError(String error) {this.error.setValue(error);loading.setValue(false);}protected void setLoading() {loading.setValue(true);}
}// 具体实现
public class UserViewModel extends DataViewModel<List<User>> {private UserRepository repository;public UserViewModel() {repository = new UserRepository();}public void loadUsers() {setLoading();repository.getUsers(new Callback<List<User>>() {@Overridepublic void onSuccess(List<User> users) {setData(users);}@Overridepublic void onError(String message) {setError(message);}});}
}
场景5:工具类和方法
public class CollectionUtils {// 泛型方法public static <T> boolean isEmpty(Collection<T> collection) {return collection == null || collection.isEmpty();}public static <T> T getFirstItem(List<T> list) {return isEmpty(list) ? null : list.get(0);}public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {List<T> result = new ArrayList<>();for (T item : list) {if (predicate.test(item)) {result.add(item);}}return result;}
}// 使用
List<User> users = // ... 获取用户列表
List<User> activeUsers = CollectionUtils.filter(users, user -> user.isActive());
4. 通配符和边界
上界通配符 (? extends)
// 生产者,只能读取
public double sumNumbers(List<? extends Number> numbers) {double sum = 0;for (Number number : numbers) {sum += number.doubleValue();}return sum;
}// 使用
List<Integer> integers = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3);
double sum1 = sumNumbers(integers); // 6.0
double sum2 = sumNumbers(doubles); // 6.6
下界通配符 (? super)
// 消费者,只能写入
public void addNumbers(List<? super Integer> list) {for (int i = 1; i <= 5; i++) {list.add(i);}
}// 使用
List<Number> numbers = new ArrayList<>();
List<Object> objects = new ArrayList<>();
addNumbers(numbers); // 可以
addNumbers(objects); // 可以
无界通配符 (?)
// 当你只关心集合操作而不关心具体类型时
public void processList(List<?> list) {System.out.println("List size: " + list.size());for (Object item : list) {System.out.println(item.toString());}
}
5. 泛型的优点
1. 类型安全
// 编译时类型检查
List<String> names = new ArrayList<>();
names.add("Alice");
// names.add(123); // 编译错误!// 运行时不会出现ClassCastException
String name = names.get(0); // 安全
2. 代码复用
// 一个泛型类处理多种类型
public class Repository<T> {public void save(T entity) { /* 通用保存逻辑 */ }public T findById(String id) { /* 通用查询逻辑 */ }
}// 用于不同实体
Repository<User> userRepo = new Repository<>();
Repository<Product> productRepo = new Repository<>();
3. 消除强制转换
// 之前
List list = new ArrayList();
list.add("hello");
String value = (String) list.get(0); // 需要强制转换// 使用泛型
List<String> list = new ArrayList<>();
list.add("hello");
String value = list.get(0); // 自动类型推断
4. 更好的API设计
// 清晰的接口契约
public interface Cache<K, V> {void put(K key, V value);V get(K key);void remove(K key);
}// 实现
public class MemoryCache<K, V> implements Cache<K, V> {private Map<K, V> cache = new HashMap<>();@Overridepublic void put(K key, V value) {cache.put(key, value);}@Overridepublic V get(K key) {return cache.get(key);}@Overridepublic void remove(K key) {cache.remove(key);}
}
6. 泛型的缺点和限制
1. 类型擦除
// 编译时泛型信息会被擦除
List<String> stringList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();// 运行时都是List,无法区分
System.out.println(stringList.getClass() == integerList.getClass()); // true// 无法使用instanceof检查泛型类型
// if (obj instanceof List<String>) // 编译错误
2. 无法创建泛型数组
// 编译错误
// T[] array = new T[10];// 解决方案
@SuppressWarnings("unchecked")
public <T> T[] createArray(Class<T> clazz, int size) {return (T[]) Array.newInstance(clazz, size);
}
3. 无法实例化类型参数
public class Factory<T> {public T createInstance() {// return new T(); // 编译错误// 解决方案:使用Class对象和反射try {return clazz.newInstance();} catch (Exception e) {throw new RuntimeException(e);}}
}
4. 静态上下文的限制
public class GenericClass<T> {private T instance;// 编译错误:不能使用类型参数T// private static T staticField;// 编译错误:静态方法不能使用类的类型参数// public static T getStaticInstance() { return null; }// 但可以定义泛型静态方法public static <U> U staticMethod(U param) {return param;}
}
7. 最佳实践
1. 优先使用泛型集合
// 好的做法
List<String> names = new ArrayList<>();
Map<String, Integer> scores = new HashMap<>();// 避免使用原始类型
List rawList = new ArrayList(); // 不要这样用
2. 使用有意义的类型参数名
// 好的命名
public interface Repository<ENTITY, ID> {ENTITY findById(ID id);void save(ENTITY entity);
}// 避免模糊的命名
public interface Repository<T, U> { // 不清晰T findById(U id);
}
3. 合理使用通配符
// PECS原则:Producer Extends, Consumer Super
public void copy(List<? extends Number> src, List<? super Number> dest) {for (Number number : src) {dest.add(number);}
}
4. 处理类型擦除
// 使用Class对象保留类型信息
public class TypeSafeRepository<T> {private final Class<T> entityClass;private List<T> data = new ArrayList<>();public TypeSafeRepository(Class<T> entityClass) {this.entityClass = entityClass;}public T createInstance() throws Exception {return entityClass.newInstance();}public boolean isInstance(Object obj) {return entityClass.isInstance(obj);}
}
8. Android中的特殊考虑
1. Parcelable泛型处理
public class GenericParcelable<T extends Parcelable> implements Parcelable {private T data;protected GenericParcelable(Parcel in) {// 需要额外的类型信息来处理泛型Class<T> clazz = (Class<T>) in.readSerializable();data = in.readParcelable(clazz.getClassLoader());}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeSerializable(data.getClass());dest.writeParcelable(data, flags);}
}
2. ViewBinding泛型
public abstract class BaseFragment<B extends ViewBinding> extends Fragment {protected B binding;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {binding = createBinding(inflater, container);return binding.getRoot();}protected abstract B createBinding(LayoutInflater inflater, ViewGroup container);@Overridepublic void onDestroyView() {super.onDestroyView();binding = null;}
}// 具体实现
public class HomeFragment extends BaseFragment<FragmentHomeBinding> {@Overrideprotected FragmentHomeBinding createBinding(LayoutInflater inflater, ViewGroup container) {return FragmentHomeBinding.inflate(inflater, container, false);}
}
总结
使用泛型的情况:
- ✅ 集合类操作
- ✅ 通用工具类和组件
- ✅ API接口设计
- ✅ 需要类型安全的场景
- ✅ 代码复用的需求
避免泛型的情况:
- ❌ 简单的类型标识
- ❌ 性能关键的底层代码
- ❌ 需要运行时类型信息的场景
- ❌ 过度复杂的类型层次