1、多泛型变量定义及字母规范
(1)、多泛型变量定义 上在我们只定义了一个泛型变量T,那如果我们需要传进去多个泛型要怎么办呢?
只需要在类似下面这样就可以了:
class MorePoint<T,U>{
}
(2)、字母规范 在定义泛型类时,我们已经提到用于指定泛型的变量是一个大写字母: 当然不是的!!!!任意一个大写字母都可以。他们的意义是完全相同的,但为了提高可读性,大家还是用有意义的字母比较好,一般来讲,在不同的情境下使用的字母意义如下:
- E — Element,常用在java Collection里,如:List
,Iterator ,Set - K,V — Key,Value,代表Map的键值对
- N — Number,数字
- T — Type,类型,如String,Integer等等
### 2、泛型函数定义及使用
怎么单独在一个函数里使用泛型。比如我们在新建一个普通的类StaticFans,然后在其中定义了两个泛型函数:
public class StaticFans {
//静态函数
public static <T> void StaticMethod(T a){
Log.d("harvic","StaticMethod: "+a.toString());
}
//普通函数
public <T> void OtherMethod(T a){
Log.d("harvic","OtherMethod: "+a.toString());
}
}
上面分别是静态泛型函数和常规泛型函数的定义方法,与以往方法的唯一不同点就是在返回值前加上
//静态方法
StaticFans.StaticMethod("adfdsa");//使用方法一
StaticFans.<String>StaticMethod("adfdsa");//使用方法二
//常规方法
StaticFans staticFans = new StaticFans();
staticFans.OtherMethod(new Integer(123));//使用方法一
staticFans.<Integer>OtherMethod(new Integer(123));//使用方法二
首先,我们看静态泛型函数的使用方法:
StaticFans.StaticMethod("adfdsa");//使用方法一
StaticFans.<String>StaticMethod("adfdsa");//使用方法二
从结果中我们可以看到,这两种方法的结果是完全一样的,但他们还有些区别的,区别如下:
方法一,可以像普通方法一样,直接传值,任何值都可以(但必须是派生自Object类的类型,比如String,Integer等),函数会在内部根据传进去的参数来识别当前T的类别。但尽量不要使用这种隐式的传递方式,代码不利于阅读和维护。因为从外观根本看不出来你调用的是一个泛型函数。
方法二,与方法一不同的地方在于,在调用方法前加了一个
StaticFans staticFans = new StaticFans();
staticFans.OtherMethod(new Integer(123));//使用方法一
staticFans.<Integer>OtherMethod(new Integer(123));//使用方法二
可以看到,与平常一样,先创建类的实例,然后调用泛型函数。 方法一,隐式传递了T的类型,与上面一样,不建议这么做。 方法二,显示将T赋值为Integer类型,这样OtherMethod(T a)传递过来的参数如果不是Integer那么编译器就会报错。
进阶:返回值中存在泛型 上面我们的函数中,返回值都是void,但现实中不可能都是void,有时,我们需要将泛型变量返回,比如下面这个函数:
public static <T> List<T> parseArray(String response,Class<T> object){
List<T> modelList = JSON.parseArray(response, object);
return modelList;
}
函数返回值是List
3、其它用法:Class类传递及泛型数组
(1)、使用Class
public static List<SuccessModel> parseArray(String response){
List<SuccessModel> modelList = JSON.parseArray(response, SuccessModel.class);
return modelList;
}
其中SuccessModel是自定义的解析类,代码如下,其实大家不用管SuccessModel的定义,只考虑上面的那段代码就行了。写出来SuccessModel的代码,只是不想大家感到迷惑,其实,这里只是fastJson的基本用法而已。
这段代码的意义就是根据SuccessModel解析出List
public class SuccessModel {
private boolean success;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}
首先,我们应该把SuccessModel单独抽出来做为泛型变量,但parseArray()中用到的SuccessModel.class要怎么弄呢? 先来看代码:
public static <T> List<T> parseArray(String response,Class<T> object){
List<T> modelList = JSON.parseArray(response, object);
return modelList;
}
下面是我自己实际使用泛型的几个实例。 希望看完上面的文章之后,再看实际使用的例子,可以更好的理解和使用和实际使用。 关于泛型类的使用实例
import lombok.Data;
@Data
public class MultiObject<T> {
/**
* 成功状态
*/
private boolean success;
/**
* 异常
*/
private Exception ex;
/**
* 数据
*/
private T obj;
public MultiObject() {
}
/**
* 注意:当传入的泛型是Boolean时,就和第三个构造函数冲突了。
*/
public MultiObject(boolean success) {
this.success = success;
}
public MultiObject(Exception ex) {
this.success = false;
this.ex = ex;
}
public MultiObject(T value) {
this.success = true;
this.obj = value;
}
}
简单解释下这个model。
在实际业务代码里面,可能有很多种操作,然后我们关心这个操作的执行结果,主要有几点。
1,成功与否。对应属性success。
2,异常信息。对应属性ex。若是操作正常执行,则就不在意这个属性的值。
3,我们操作的最终目的对象。对应属性obj。
依赖的包
```apple js
关于泛型方法的使用实例
这个地方就有2个,但是上面文章也都讲到啦。
1,一个是泛型表示某一个类型的参数。为的传递某一类的参数对象
2,另一个则是传递的不是参数,而是代表Class,某一个类。
恰巧我都使用过,就正好记录一下实际使用实例。
```java
/**
* 将Json字符串信息转换成对应的Java对象
*
* @param json json字符串对象
* @param c 对应的类型
*/
public static <T> T parseJsonToObj(String json, Class<T> c) {
try {
JSONObject jsonObject = JSONObject.parseObject(json);
return JSON.toJavaObject(jsonObject, c);
} catch (Exception e) {
LOG.error(e.getMessage());
}
return null;
}
然后是具体调用的地方的代码。
Collector collectorObj = JSONUtils.parseJsonToObj(collector, Collector.class);
Flume flume = JSONUtils.parseJsonToObj(flumeJson, Flume.class);
Probe probe = JSONUtils.parseJsonToObj(probeJson, Probe.class);
可以看到,真的只是因为传入的参数类型不一样,但若你不知道泛型的话,那你就得没遇到一个类型的转换,你就得写一个这么个方法。
/**
* @param dest 目的集合
* @param source 源集合
* @param <T> 集合参数的类型
*/
private static <T> void listAddAllAvoidNPE(List<T> dest, List<T> source) {
if (source == null) {
return;
}
dest.addAll(source);
}
private static <T> void listAddAvoidNull(List<T> dest, T source) {
if (source == null) {
return;
}
dest.add(source);
}
这个就是传入的参数为某一类的参数,主要是要使用参数对象,而不是上面的那个使用的参数的类Class 我这方法提出来,主要是因为,直接使用list类的addAll()方法,如果添加的是null,那么就会抛异常。但是总不能我在所有使用的地方,都判断一下我要添加的参数是不是null,然后再调用list的addAll()方法吧。那样的话,这样的判断代码会啰嗦的海了去了。所以,就这么提出来了。 这个时候,这个T,使用起来就像使用我们常用的一般对象一样,我这的参数是个List类型,当然也可是其他类型的,姿势都一样。
然后是具体调用的地方的代码
List<ProbeObject> list = Lists.newArrayList();
listAddAllAvoidNPE(list, decoder.getProperties());
这个方法的第二个参数的返回值可能是null,所以,直接调用addAll(),就会抛空指针异常。所以,就如上,那么一提取。就好多啦。