没有泛型的坏处:
很多时候,比如我们使用list集合,如果我们没有对他进行约束,那么它里面可以存放很多类型的值,任何类型都可以,这就比较扯淡了,那我现在有一个List集合,我想这个集合里面都装的是学生,结果突然装了一个猫这种的对象类型,这显然很不合理嘛!也就是是说,我其实相对这个集合进行一下约束,就是它只能装某一种类型的数据。那么泛型就可以很好的解决这类问题。
什么是泛型:
泛型通过它的名字我们可以这样解释,他就是广泛通用的类型,你传给我什么类型,那它就是什么类型。或者说,一开始我不知道他是什么类型,只有在真正被用到的时候才能确定他是什么类型。
我们创建一个泛型先:
看下面这段代码,我定义了一个点类,点有横纵坐标,我用T表示这两个坐标的类型,很明显,我们现在谁都不知道这两个点的类型,到底是int,还是float,或者是double?没有办法知道。那什么时候知道?只有在创建这个类的具体示例的时候你给他传了具体的类型了,才能知道,而它的类型就是你创建对象的时候给他传的那个类型。
public class Point<T> {
private T x;
private T y;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
我们创建一个点这个类的具体实例:
public static void main(String[] args) {
Point<Integer> point = new Point<>();
}
很明显,我们就能看到,我们在创建这个对象的时候它就要求我么给他传一个具体的类型,而这个具体的类型就是你这个坐标两点的具体类型。那如果我们创建的时候没有给他指明具体的类型呢?这个时候他就默认为是Object类型。不过还有一点注意的,这个传进去的具体类型只能是引用类型,不能是基本数据类型,(反正基本数据类型也有对应的包装类)嘿嘿~
泛型的本质:
虽然我们写了泛型之后,感觉好像里面的类型都是由我们自己控制了,但是实际上在编译器里它还是object类型,只不过它帮我们做了强制转换,不过这个对我们的使用美哟影响,我们好用就行
泛型类:
public class User<T> {
private T userName;
private T age;
private String sex;
public static void main(String[] args) {
User<String> user = new User<>();
}
}
上面的这个实际上就是泛型类,和我们上面说的那个例子是一样的,也就是在类名的后面加上<T>即可,注意这个T是任意的,你取其他名字也可以的,当你在类上定义了泛型之后,那么这个类中的所有有T的地方,它的类型都会变成你创建对象的时候指定的那个类型。
比如你看我们下面new User对象的时候我们要指定一下它的T的类型,我这里指定的是String,所以userName和age的类型就都都变成了string类型的字段了。
注意一点:泛型类当中定义的泛型是只能用在普通方法上面的,不能用在静态方法上,为什么?想一想,静态方法是直接用类名调用的,而泛型类中的类型是我们在创建对象的时候具体指定的,也就是说我们直接用类名调用就没有经过创建对象这一步,所以泛型自然就没有生效。也就会直接报错。
泛型方法:
泛型方法就是在方法上定义的泛型,它一般是两种情况
第一种:
就像我们上面那样,如果这个方法是在泛型类里面,
public class User<T> {
private T userName;
public T getUserName(){
return userName;
}
public static void main(String[] args) {
User<String> user = new User<>();
user.userName="hello";
System.out.println(user.getUserName());
}
}
比如上面这个,我已经定义了一个泛型类,在里面定义了一个方法,但是这个方法的返回值类型也是T,也就是我们定义的泛型,那么这个方法是可以叫做泛型方法的。同样,这个时候这个方法的返回值类型的确定,需要我们在创建这个类的具体对象的时候具体指定。
第二种:
我们还可以单独的声明泛型方法,什么意思呢?上面我们说的泛型方法不是在泛型类下面声明的嘛,其实我们可以脱离泛型类,直接在类上声明泛型。
但是我们在声明的时候要注意一点,泛型类的具体类型我们都知道是在创建对象的时候具体确定,那单独的泛型方法的类型具体的确定是依靠在调用方法的时候给方法传递的参数来确定的。也就是说泛型方法,你必须给他传递参数。
当声明了泛型方法的时候,这个泛型就只在这个方法及其内部生效。不会对其他程序造成影响。
public class User {
private String userName;
private <T> void test(T a){
System.out.println(a);
}
public static void main(String[] args) {
User user = new User();
user.test("nihao");
}
}
当然你也可以在返回值类型上使用泛型
private <T> T test(T a){
System.out.println(a);
return a;
}
如上这个代码,我们就定义了一个泛型方法,那么这个泛型方法的类型也就是在调用test方法的时候,由传进来的这个参数a确定,传进来的这个a是什么类型,那么这个方法的泛型就是具体是什么类型。
当然,因为是调用方法的时候确定的类型,所以这种自定义方法的泛型也是可以在静态方法中使用的。
泛型中的通配符:?
当我们在接收某些参数的时候,我们可能不知道要用什么类型来接收,这个时候我们就可以使用泛型的通配符来接收,如下使用方法;
public class User {
private void getList(List<?> list){
System.out.println(list);
}
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("puyinzhen");
list1.add("liming");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
User user = new User();
user.getList(list1);
user.getList(list2);
}
}
如同上面这里的一样,我们在getList方法这里使用了一个?作为通配符进行接收。这里我用注意一下,通配符我们一般只用来做接收,不用来做添加。添加会出错。