Java泛型使用建议(List T、List ?、List Object的使用建议)
泛型在用法上可以分成类泛型和方法泛型两种:类泛型泛型类在实例化时就要指明类型,不同的类型实例必须要重新new一次,不够灵活顶层接口:interface GenericInterface<T>子类实现:不指明泛型类型(<T>必须要带,否则子类中无法引用到T)class GenericInterfaceImpl<T> implements Gen...
泛型在用法上可以分成泛型类和泛型方法两种:
泛型类
泛型类在实例化时就要指明类型,不同的类型实例必须要重新new一次,不够灵活
泛型接口interface Request<T>
* 1.接口中有方法,且引用了泛型T时,class SubRequest<T> implements Request<T>
* 父子都要有<T>否则不能编译,因为实现的方法中有T
* 2.接口中没有方法,以下三种定义都可以,第三种相当字面T改成了字面M
* class SubRequest<T> implements Request<T>、
* class SubRequest implements Request、
* class SubRequest<M> implements Request
* 3.子类新增泛型
* class SubRequest<K, T> implements Request<T>
泛型方法
定义泛型方法时,必须在返回值前加上<T>
,声明该方法是泛型方法,泛型方法在调用时指明类型,比较灵活,如果泛型方法返回泛型类型时,方法返回时要强转为泛型类型,调用方直接用真实类型接收
// 无返回值
public static <T> void test(T t) {
System.out.println(t.getClass());
}
// 有返回值
User user = test();
System.out.println(user);
public static <T> T test() {
Object user = new User();
return (T) user;
}
泛型方法的真实案例,可以点击这里查看,基于CountDownLatch的单元测试并发工具类,此案例在实际工作中可以用到,另外我实现了一套泛型的内存队列,写这篇博客也是想总结一下用法,给迷茫的人一些启示。
Class、Class、Class<?>、Class< T>的应用
* 泛型类
* public interface Request<T> {
void serialize(T t);
}
* 声明对象方式:Request request、Request<Object> request,serialize方法的参数T可以是任意类型
* 声明对象方式:Request<?> request,调用serialize方法,任意类型的参数都不会编译成功
* 声明对象方式:Request<String> request,serialize方法的参数T只能是String
* 泛型方法
* <V> void doWork(V v){
* }
* <V> V doWork(){
* return (V) null;
* }
* 方法参数V相当于Object,可以是任意类型
List<T>、List<?>、List<Object>
的选择
List<T>、List<?>、List<Object>
这三者都可以容纳所有的对象,但使用的顺序应该是首选List<T>
,次之List<?>
,最后选择List<Object>
,原因如下:
List<T>
是确定的某一个类型,具体类型在运行期决定;List<?>
表示的是任意类型;List<Object>
表示List集合中的所有元素都是Object
类型;List<T>
可以进行读写操作,例如add
、remove
等操作,因为它的类型是固定的,编码期不需要进行任何的转型操作。List<?>
是只读类型,不能进行增加/修改操作,因为编译器不知道真实类型,无法校验类型是否安全,而且它读出的元素都是Object
类型的,需要主动转型,所以它经常用于泛型方法的返回值。List<?>
虽然不能增加、修改元素,但是可以删除元素,例如remove
、clear
方法,因为删除和泛型类型无关。List<Object>
也可以读写操作,但是它执行写入时需要向上转型,在读取数据后,需要向下转型,而此时已经失去了泛型存在的意义。
? extends E
和? super E
什么时候用
-
泛型结构只参与“读”操作则限定上界(
extends
关键字),例如下面idea
生成的for
循环代码,直接使用Integer
表示public static void read1(List<? extends Integer> list) { for (Integer integer : list) { } }
-
泛型结构只参与“写”操作则限定下界(
super
关键字),例如下面idea
生成的for
循环代码,直接使用Object
表示public static void read(List<? super Integer> list) { for (Object o : list) { } }
泛型方法的应用
public final class MapControl {
private MapControl() {
}
/**
* 单例
*/
private static final MapControl mapControl;
/**
* 数据,实际应用中可以把这个当成RedisTemplate
* Map<K,V> map; 这种声明是错误的,成员变量中不能出现类上没有定义的泛型
*/
private static final Map map;
/**
* 控制并发20
*/
private static final Semaphore semaphore;
static {
mapControl = new MapControl();
map = new ConcurrentHashMap<>();
semaphore = new Semaphore(20);
}
private static <K, V> Map<K, V> getMap() {
try {
semaphore.acquire();
return map;
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
public static void release() {
semaphore.release();
}
private static Object execute(Statement statement) {
try {
Map map = MapControl.getMap();
return statement.prepare(map);
} finally {
release();
}
}
interface Statement<K, V> {
/**
* 方法返回Object更具有统一性,因为不确定返回数据的的类型,例如方法返回V,返回List<V>,返回Map<K,V>
* 所以返回Object可以兼容一切返回类型,再强转为需要的类型
*
* @param map
* @return
*/
Object prepare(final Map<K, V> map);
}
public static <K, V> void set(final K key, final V value) {
MapControl.execute(new MapControl.Statement<K, V>() {
@Override
public V prepare(Map<K, V> map) {
map.put(key, value);
return null;
}
});
}
public static <K, V> V get(final K key) {
/**
* 返回时强转为V
*/
return (V) MapControl.execute(new Statement<K, V>() {
@Override
public V prepare(Map<K, V> map) {
return map.get(key);
}
});
}
public static <K, V> Map<K, V> getAll(final List<K> keys) {
/**
* 返回时强转为Map<K,V>类型
*/
Map<K, V> result = (Map<K, V>) MapControl.execute(new Statement<K, V>() {
@Override
public Object prepare(Map<K, V> map) {
Map<K, V> result = new HashMap<>();
for (K k : keys) {
result.put(k, map.get(k));
}
return result;
}
});
return result;
}
public static void main(String[] args) {
MapControl.set(1, "1");
MapControl.set("name", "p7+");
Object obj = new Object();
MapControl.set(obj, obj);
MapControl.set(2, 2);
MapControl.set(3, 3);
MapControl.set(4, 4);
MapControl.set("name1", "name1");
MapControl.set("name2", "name2");
String v = MapControl.get(1);
System.out.println(v);
System.out.println(MapControl.get("1"));
System.out.println(MapControl.get("name"));
System.out.println(MapControl.get(obj));
List<Integer> keys = new ArrayList<>();
keys.add(2);
keys.add(3);
keys.add(4);
System.out.println(MapControl.getAll(keys));
List<String> strKeys = new ArrayList<>();
strKeys.add("name");
strKeys.add("name1");
strKeys.add("name2");
System.out.println(MapControl.getAll(strKeys));
}
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)