问题:在获取用户信息的API中,后台给咱们返回一个这样形式的json字符串。java
{
"meta": {
"code": 0,
"message": "ok"
},
"data": {
"nick_name": "hellokitty",
"cellphone": "18301824843",
}
}
复制代码
咱们用fastJson解析上述json字符串时候,该怎么处理? ,咱们是否是就会写这样一个类。json
public class User {
private Meta meta;
private Data data;
public Meta getMeta() {
return meta;
}
public void setMeta(Meta meta) {
this.meta = meta;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
static class Meta
{
private String code;
private String message;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
static class Data
{
private String nick_name;
private String cellphone;
public String getNick_name() {
return nick_name;
}
public void setNick_name(String nick_name) {
this.nick_name = nick_name;
}
public String getCellphone() {
return cellphone;
}
public void setCellphone(String cellphone) {
this.cellphone = cellphone;
}
}
}
复制代码
而后调用fastjason的JSON.parseObject(msg,User.class)
进行解析。安全
而若是拉取设备列表API返回的数据格式是这样的一个形式,咱们该怎么处理?bash
{
"meta": {
"code": 0,
"message": "ok"
},
"data": [
{
"device_id": "4acb634aaf5711e8b290000c29c27f42",
"role": 1,
"device_alias": "hellokitty",
"created_at": "2018-09-04T10:55:57"
},
{
"device_id": "4acb634aaf5711e8b290000c29c27f42",
"role": 1,
"device_alias": "hellokitty",
"created_at": "2018-09-04T10:55:57"
}
]
}
复制代码
是否是咱们仍然要再写一个解析类来解析这个设备列表类。ide
public class DeviceList {
private Meta meta;
private List<Device> data;
public Meta getMeta() {
return meta;
}
public void setMeta(Meta meta) {
this.meta = meta;
}
public List<Device> getData() {
return data;
}
public void setData(List<Device> data) {
this.data = data;
}
static class Meta
{
private String code;
private String message;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
static class Device
{
@Override
public String toString() {
return "Device{" +
"device_id='" + device_id + '\'' + ", role=" + role + ", device_alias='" + device_alias + '\'' + ", created_at='" + created_at + '\'' +
'}';
}
private String device_id;
private int role;
private String device_alias;
private String created_at;
public String getDevice_id() {
return device_id;
}
public void setDevice_id(String device_id) {
this.device_id = device_id;
}
public int getRole() {
return role;
}
public void setRole(int role) {
this.role = role;
}
public String getDevice_alias() {
return device_alias;
}
public void setDevice_alias(String device_alias) {
this.device_alias = device_alias;
}
public String getCreated_at() {
return created_at;
}
public void setCreated_at(String created_at) {
this.created_at = created_at;
}
}
}
复制代码
若是每次都这样的话,会不会要建立不少很相像的类,他们只是里面部分变量不一样,其余的部分都相同。ui
再举一个栗子: 若是咱们想要产生多个对象,每一个对象的逻辑彻底同样,只是对象内的成员变量的类型不一样,那咱们如何去作? 在下面咱们建立了两个类,只是data的变量类型不一样,是否是也能够达到咱们刚才的要求。this
static class MyClass1
{
public MyClass1() {
}
private String data;
public MyClass1(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
static class MyClass2
{
public MyClass2() {
}
private int data;
public MyClass2(int data) {
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
复制代码
打印结果:spa
MyClass1 myClass1 = new MyClass1();
myClass1.setData("Cyy");
MyClass2 myClass2 = new MyClass2();
myClass2.setData(10);
System.out.println(myClass1.getData());
System.out.println(myClass2.getData());
复制代码
输出:code
Cyy
10
复制代码
可是若是咱们还想要这样一个对象呢,那咱们是否是还要继续去建立这样的对象,那若是我还要10个这个的对象呢,那咱们是否是就要建立十个。这样明显是很笨重的一种解决方案。对象
那咱们如今思考,若是咱们用Object来代替呢?
static class MyClass1
{
public MyClass1() {
}
private Object data;
public MyClass1(Object data) {
this.data = data;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
复制代码
打印输出:
MyClass1 myClass1 = new MyClass1();
myClass1.setData("Cyy");
System.out.println((String)myClass1.getData());
MyClass1 myClass2 = new MyClass1();
myClass2.setData(10);
System.out.println((int)myClass2.getData());
```
输出结果:
复制代码
Cyy
10
复制代码
呀~看上去好像完美解决了,不用建立多个类,就能够实现刚才须要功能,好像很完美,如今让他变成不完美,如今咱们让他这样打印出来.
复制代码
MyClass1 myClass2 = new MyClass1();
myClass2.setData(10);
System.out.println((String)myClass2.getData());
复制代码
注意咱们给他的是整型,可是打印时候咱们给他的强转类型是String,如今看下会发生什么问题。
复制代码
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at SecDemo.main(SecDemo.java:13)
复制代码
它提示了,类型转换异常。
总结
方案(一) :
方法: 建立多个类文件,给每一个类中的成员变量设置指定的数据类型。
缺点: 致使类的膨胀,重用性太差
方案(二) :
方法: 建立一个类文件,给这个类中的成员变量设置Object数据类型
缺点:编译的时候正常,但运行时候可能会报错.
泛型类就能很好的解决以上两个问题。
复制代码
泛型是JDK1.5引入的新特性,也是最重要的一个特性。
泛型能够在编译的时候检查类型安全
,而且全部的强制转换都是自动和隐式的。
泛型的原理就是类型的参数化
,即把类型看作参数,也就是说把所要操做的数据类型看作参数,就像方法的形式参数是运行时传递的值同样。
简单的说,类型变量扮演的角色如同一个参数,它提供给编译器用来类型检查的信息。
泛型能够提升代码的扩展性和重用性 **
若是咱们将刚才的类改为泛型类是什么样子的呢?
static class MyClass1<T>
{
public MyClass1() {
}
private T data;
public MyClass1(T data) {
this.data = data;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
复制代码
咱们发如今类的开头多了个,这个就表明着传入进来的参数,他能够是整型,能够是字符串类型,只要你传进来了那么后续的get,set方法就所有都是这种类型了。他就至关于一个操做的参数。好的如今咱们试一下。
打印输出:
MyClass1 myClass1 = new MyClass1<String>();
myClass1.setData("Cyy");
System.out.println(myClass1.getData());
MyClass1 myClass2 = new MyClass1<Integer>();
myClass2.setData(10);
System.out.println(myClass2.getData());
复制代码
输出:
Cyy
10
复制代码
有没有发现,咱们不用进行强制类型转换仍然能输出正确的数值。 注意下,当咱们new MyClass1<String>()
传的是String
那么咱们类里面的全部T
就都是String
类型了。
总结:
泛型类使用优势:
防止类膨胀
再也不手动进行类型转换
static class MyClass1<T1>
{
public MyClass1() {
}
private T1 data1;
public T1 getData1() {
return data1;
}
public void setData1(T1 data1) {
this.data1 = data1;
}
}
static class Student
{
private String name;
public Student(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } } 复制代码
使用:
MyClass1<MyClass1<Student>> myClass1MyClass1 = new MyClass1<MyClass1<Student>>();
MyClass1<Student> myClass1 = new MyClass1<Student>();
myClass1.setData1(new Student("cyy"));
myClass1MyClass1.setData1(myClass1);
System.out.println(myClass1MyClass1.getData1().getData1().toString());
复制代码
输出:
Student{name='cyy'}
复制代码
static class MyClass1<T1,T2>
{
public MyClass1() {
}
private T1 data1;
private T2 data2;
public T2 getData2() {
return data2;
}
public void setData2(T2 data2) {
this.data2 = data2;
}
public T1 getData1() {
return data1;
}
public void setData1(T1 data1) {
this.data1 = data1;
}
}
复制代码
使用:
MyClass1<String,Integer> myClass1 = new MyClass1<String,Integer>();
myClass1.setData1("Cyy");
myClass1.setData2(25);
System.out.println(myClass1.getData1());
System.out.println(myClass1.getData2());
复制代码
输出:
Cyy
25
复制代码
class SuperClass<T1>
{
private T1 var1;
public SuperClass(T1 var1) {
this.var1 = var1;
}
public T1 show1()
{
return var1;
}
}
class SubClass<T1,T2> extends SuperClass<T1>
{
private T2 var2;
public SubClass(T1 var1, T2 var2) {
super(var1);
this.var2 = var2;
}
@Override
public T1 show1() {
return super.show1();
}
}
复制代码
使用:
SubClass<String,Integer> subClass = new SubClass<>("cyy",25);
System.out.println(subClass.show1());
复制代码
输出:
cyy
复制代码
interface IInfo<T2>
{
public void show2(T2 var3);
}
static class SubClass<T1,T2> extends SuperClass<T1> implements IInfo<T2>
{
private T2 var2;
public SubClass(T1 var1, T2 var2) {
super(var1);
this.var2 = var2;
}
@Override
public T1 show1() {
return super.show1();
}
@Override
public void show2(T2 var3) {
System.out.println(var3);
System.out.println(var2);
}
}
复制代码
使用:
SubClass<String,Integer> subClass = new SubClass<>("cyy",25);
subClass.show2(100);
System.out.println(subClass.show1());
复制代码
输出:
100
25
cyy
复制代码
注:不能够进行泛型变量之间的运算,由于泛型变量在编译期间会进行类型擦除,所有变成Object,好比Object+Object就不知道是什么类型了,因此这点很重要。
OK,如今咱们能够回到最初那个问题上了,咱们能够利用泛型定义一个CommResult类。
public class CommResult <T> {
private Meta meta;
private T data;
public Meta getMeta() {
return meta;
}
public void setMeta(Meta meta) {
this.meta = meta;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
static class Meta
{
private String code;
private String message;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
}
复制代码
而后使用的时候咱们能够这样:
JSON.parseObject(msg,CommResult<User>)
或JSON.parseObject(msg,CommResult<List<Device>>)
。
这样就完美避免了建立多个结构同样,可是只有里面部分变量不一致的类了。
在定义泛型类别时,默认在实例化泛型类的时候可使用任何类型,可是若是想要限制使用泛型时,只能用某个特定类型或者是其子类型才能实例化该类型时,能够在定义类型时,使用extends
关键字指定这个类型必须是继承某个类,或者实现某个接口。 当没有指定泛型继承的类型或接口时,默认使用extends Object,因此默认状况下,可使用任何类型做为参数。
class GenericClass<T extends Animal>
{
private T data;
public GenericClass(T data)
{
this.data = data;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
abstract class Animal
{
public abstract void eat();
}
class Dog extends Animal
{
@Override
public void eat() {
System.out.println("啃骨头");
}
}
class Cat extends Animal
{
@Override
public void eat() {
System.out.println("吃鱼肉");
}
}
复制代码
如今咱们看下,若是我在泛型类里面传个String
类型的参数,看他会报什么? Type parameter 'java.lang.String' is not within its bound; should extend 'Test.Animal
他说String不是Animal子类,不行吧。
若是咱们换成这样就能够了。
GenericClass<Dog> genericClass = new GenericClass<>(new Dog());
genericClass.getData().eat();
GenericClass<Cat> genericClasscat = new GenericClass<>(new Cat());
genericClasscat.getData().eat();
复制代码
若是换成接口呢?
class GenericClass<T implements eat>
{
private T data;
public GenericClass(T data)
{
this.data = data;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
复制代码
这样写对不对,这样写是不对的,编译器会报错的,由于不论是接口仍是类,都要用extends
。因此换成接口也要写成这样就能够了。
class Cat implements eat
{
@Override
public void eat() {
System.out.println("吃鱼肉");
}
}
class Dog implements eat
{
@Override
public void eat() {
System.out.println("啃骨头");
}
}
interface eat
{
public abstract void eat();
}
class GenericClass<T extends eat>
{
private T data;
public GenericClass(T data)
{
this.data = data;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
复制代码
同一泛型类,若是实例化时给定的实际类型不一样,则这些实例的类型是不兼容的,不能相互赋值。如:
Generic<Boolean> f1 = new Generic<Booleab>();
Generic<integer> f2 = new Generic<integer>();
f1 = f2;//发生编译错误
Generic<Object> f = f1 ;//f1和f类型并不兼容,发生编译错误
f = f2;//f2和f类型一样不兼容,也会发生编译错误。
复制代码
泛型类实例之间的不兼容性会带来使用的不便。咱们可使用泛型通配符(?)生命泛型类的变量就能够解决这个问题。
泛型通配的使用方式
Generic<Boolean> f1 = new Generic<Booleab>();
Generic<?> f= f1;
复制代码
Generic<Dog> f1 = new Generic<Dog>();
Generic<? extends Animal> f= f1;
复制代码
Generic<Animal> f1 = new Generic<Animal>();
Generic<? super Dog> f= f1;
复制代码
如今要在这里特别说下两个限定通配符
extends
上边界限定通配符举个例子一看就懂了,<? extends Animal> , 那这里的`?`就必须是Animal的子类或它本身。
复制代码
super
下边界限定通配符举个例子一看就懂了,<? super Dog> , 那这里的`?`就必须是Dog的父类或它本身。
复制代码
不只类能够声明泛型,类中的方法也能够声明仅用于自身的泛型,这种方法叫作泛型方法。其定义格式为:
访问修饰符<泛型列表> 返回类型 方法名(参数列表)
{
实现代码
}
复制代码
在泛型列表中声明的泛型,可用于该方法的返回类型
声明,参数类型
声明和方法代码中的局部变量
的类型声明。
类中其余方法不能使用当前方法声明的泛型。
注:是否拥有泛型方法,与其所在的类是不是泛型没有关系。要定义泛型方法,秩序将泛型参数列表置于返回值以前。
何时使用泛型方法,而不是泛型类呢?
添加类型约束只做用于一个方法的多个参数之间,而不涉及类中的其余方法时。
施加类型约束的方法为静态方法,只能将其定义为泛型方法,由于静态方法不能使用其所在类的类型参数。
再举个代码的例子:
如今咱们先定义一个泛型类:
public class Demo1 {
public static void main(String[] args)
{
GenericClassOne<String> genericClassOne = new GenericClassOne<>();
genericClassOne.printlinT(10);
}
}
class GenericClassOne<T>
{
public void printlinT(T content)
{
System.out.println(content);
}
}
复制代码
若是咱们这么写,确定编译就报错误了吧,由于咱们上面定义的是String
类型,可是咱们传给他的是int
型的。那若是这样的话,这个方法是否是就有局限性了。
那若是咱们如今使用泛型方法呢?该怎么写?
public class Demo1 {
public static void main(String[] args)
{
GenericClassOne genericClassOne = new GenericClassOne();
genericClassOne.printlinT(10);
genericClassOne.printlinT("cyy");
genericClassOne.printlinT(12.5);
}
}
class GenericClassOne<T>
{
//泛型方法,类型定义写在返回值以前了
public <T> void printlinT(T content)
{
System.out.println(content);
}
}
复制代码
这下不会再报编译错误了,如今看下打印结果。
输出:
10
cyy
12.5
复制代码
这样是否是就灵活了许多啦~
那么泛型的方法可不能够重载呀,固然能够,咱们仍然能够写成这样。
class GenericClassOne<T>
{
//泛型方法,类型定义写在返回值以前了
public <T> void printlinT(T content)
{
System.out.println(content);
}
//泛型方法,类型定义写在返回值以前了
public <T extends Animal> void printlinT(T animal)
{
animal.eat();
}
}
abstract class Animal
{
public abstract void eat();
}
复制代码
由于泛型类在编译过程当中会有个擦除的工做,因此第一个printlnT(T content)中的泛型会变成object,而第二个泛型方法中的T会变成Animal。因此他的方法能够被重载。
Ok,结束!