主要介绍泛型方法的使用
如果方法参数或者返回值是类型可变的容器,则需要使用泛型方法,使用泛型方法对参数进行限制的示例如下:
public class Demo01 {
private static final Logger LOG = LoggerFactory.getLogger(Demo01.class);
// 不使用泛型方法,无法对参数进行限制
public static Set UnionWithoutGeneric(Set s1, Set s2) {
Set result = new HashSet(s1);
result.addAll(s2);
return result;
}
// 使用泛型方法,可以对参数进行限制
public static <E> Set<E> UnionUseGeneric(Set<E> s1, Set<E> s2) {
Set<E> result = new HashSet<>(s1);
result.addAll(s2);
return result;
}
@Test
public void test() {
Set<String> s1 = Sets.newHashSet("a", "b", "c");
Set<Integer> s2 = Sets.newHashSet(1, 2, 3, 4);
Set<String> res1 = UnionWithoutGeneric(s1, s2);
// 2024-01-16 09:48:54,127 | INFO | Demo01.java.test(): 41 - [a, 1, b, 2, c, 3, 4]
LOG.info(res1.toString());
// 使用泛型方法,可以避免堆污染
// Set<String> objects = UnionUseGeneric(s1, s2);
Set<Integer> res2 = unionUseGeneric(s2, s3);
// 2024-01-16 09:55:18,275 | INFO | Demo01.java.test(): 50 - [1, 2, 3, 4, 5, 6, 7, 8]
LOG.info(res2.toString());
}
}
集合排序方法的标准写法
public static <E extends Comparable<E>> E max(Collection<E> c, boolean failFast) {
if (c.isEmpty() && failFast) {
throw new IllegalArgumentException("Empty Collection");
}
E result = null;
for (E e : c) {
if (result == null || e.compareTo(result) > 0) {
result = Objects.requireNonNull(e);
}
}
return result;
}
恒等函数示例:
static class Demo11 {
static <T> Function<T, T> identity() {
return t -> t;
}
}
协变、逆变
public class Covariance {
public static final Logger LOG = LoggerFactory.getLogger(Covariance.class);
public static void testvCovariance(List<? extends Apple> lst) {
// 只能调用读取方法,无法调用修改方法
Apple apple = lst.get(0);
// lst.add(new BigApple());
LOG.info("Covariance:" + lst);
}
public static void testContravariance(List<? super Apple> lst) {
// 调用读取方法只能读到Object类型
Object object = lst.get(0);
// 一般只调用修改方法
lst.add(0, new BigApple());
LOG.info("Contravariance:" + lst);
}
@Test
public void test() {
List<Fruit> lst1 = Lists.newArrayList(new Fruit());
List<Orange> lst2 = Lists.newArrayList(new Orange());
List<Apple> lst3 = Lists.newArrayList(new Apple());
List<BigApple> lst4 = Lists.newArrayList(new BigApple());
// testvCovariance(lst1);
// testvCovariance(lst2);
// Covariance:[com.pcx.chapter01.Apple@6295d394]
testvCovariance(lst3);
// Covariance:[com.pcx.chapter01.BigApple@fdefd3f]
testvCovariance(lst4);
// Contravariance:[com.pcx.chapter01.BigApple@d83da2e, com.pcx.chapter01.Fruit@a4102b8]
testContravariance(lst1);
// testContravariance(lst2);
// Contravariance:[com.pcx.chapter01.BigApple@11dc3715, com.pcx.chapter01.Apple@6295d394]
testContravariance(lst3);
// testContravariance(lst4);
}
}
使用泛型实现异构容器
public class Favourites {
private final Map<Class<?>, Object> favourite = Maps.newHashMap();
private static final Logger LOG = LoggerFactory.getLogger(Favourites.class);
public <T> T getFavourite(Class<T> type) {
return type.cast(favourite.get(type));
}
public <T> void putFavourite(Class<T> type, T instance) {
favourite.put(Objects.requireNonNull(type), type.cast(instance));
}
@Test
public void test() {
Favourites f = new Favourites();
f.putFavourite(String.class, "Java");
f.putFavourite(Integer.class, 1231);
String f1 = f.getFavourite(String.class);
Integer f2 = f.getFavourite(Integer.class);
LOG.info(f1);
LOG.info("" + f2);
}
}
总结
- 泛型定义:
<E extends Comparable<E>> E
; - 泛型方法可以通过先定义返回值进行限制;
- 泛型容器取东西,用super,将东西放入泛型容器则使用extend;
- 如果参数化类型是一个生产者,即提供数据则使用
<? extends T>
,只能调用其读取方法; - 如果它表示一个消费者,那就使用
<? super T>
,只能调用其设置方法。