一、为什么使用泛型
泛型,JDK1.5新加入的,解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化时只要指定好需要的具体的类型即可。
Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮。
注意:Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
import java.util.ArrayList;
import java.util.List;
public class test {
public static void main(String[] args) {
List list = new ArrayList();
list.add(111);
list.add("sss");
list.add(true);
//需求,只能在集合中存字符串
List<String> l = new ArrayList<String>();
l.add("xx");
// l.add(true);//这个是编译期发现的问题
}
}
二、泛型怎么用
1.泛型类
1.对象实例化时不指定泛型,默认为:Object。
2.泛型不同的引用不能相互赋值。
import java.util.ArrayList;
import java.util.List;
public class test {
public static void main(String[] args) {
A<String> a = new A<String>();//在 new A的对象指定泛型的类型为String
a.setKey("aaa");//对象使用serKey(T key)方法,中的key形参就是String
String s = a.getKey();//T getKey(),返回值就有new对象确定返回值是String
A<Integer> in = new A<Integer>();
in.setKey(123);
Integer In = in.getKey();
A a1 = new A();//不指定泛型,相当于指定了一个Object类型
// 等同这个 A<Object> a1 = new A<Object>();
a1.setKey(1);
Object i1 = a1.getKey();
System.out.println(i1);
a1.setKey(new Object());
//同样的类,但是在new对象时泛型指定不同的数据类型,这些对象不能互相赋值
// i1 = a;
}
}
class A<T>{
private T key;
public void setKey(T key){
this.key = key;
}
public T getKey(){
return this.key;
}
}
2.泛型方法
未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
传入泛型实参时:定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
public class test1 {
public static void main(String[] args) {
B1<Object> b1 = new B1<Object>();
B1<String> b2 = new B1<String>();
//B2<String> bb2 = new B2<String>(): B2继承接口时已经声明为String类型,所以这里再次声明反而报错
}
}
interface B<T>{
T test(T t);
}
//未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
class B1<T> implements B<T>{
@Override
public T test(T t) {
return t;
}
}
//如果实现接口时指定接口的泛型的具体数据类型
//这个类实现接口所有方法的位置都要泛型替换实际的具体数据类型
class B2 implements B<String>{
@Override
public String test(String s) {
return s;
}
}
3.泛型接口
public class test2 {
public static void main(String[] args) {
g<Object> G = new g<Object>();
G.test("xxx");
//泛型方法,在调用之前没有固定的数据类型
//在调用时,传入的参数是什么类型,就会把泛型改成什么类型
//也就是说,泛型方法会在调用时确定泛型距离数据类型
Integer i = G.test(2);//传递的参数是Integer,泛型就固定成Integer,返回值就是Integer
Boolean b = G.test(true);//传递的参数是Boolean,泛型就固定成Boolean,返回值就是Boolean
}
}
class cc{
//正常有参无返回方法
public void c(String s){
}
//泛型方法
public <T> void test(T t){//在public后面声明泛型就可以在本方法后面任意地方使用泛型
T s = t;
}
//普通又返回值的方法
public String sr(String s){
return s;
}
//泛型方法 注意这两个泛型方法一点都不冲突
public <T> T text1(T t){
return t;
}
//可变参数
public void text2(String...str){
for (String s : str){
System.out.println(s);
}
}
//形参为可变参数的泛型方法
public <T> void text22(T...t){
for (T tr : t){
System.out.println(tr);
}
}
}
//在类上定义的泛型也可以在方法中使用
class g<E>{
private E e;
//普通静态方法在静态方法中,不能使用类定义泛型,如果要使用泛型,只能使用静态方法自己定义的泛型
public static void test1(){
// System.out.println(this.e);
}
//泛型静态方法
public static <T> void test02(T t){
System.out.println(t);
}
public <E> E test(E t){
return t;
}
}
另外补充可变参数
可变参数
就是参数个数可变,若作为方法形参出现,也就是方法参个数是可以变化的。
格式:修饰权限 返回类型 方法名(数据类型…变量名){ }
例如:public static void sum(int…a){}
注意事项:
1.这里的变量是个数组
2.如果参数是多个,包括可变参数,可变参数在最后。
可变参数的使用:
ArrayList工具类有一个静态方法:
public static List asList(T…a){ },对返回集合不能进行增删,可以修改
List接口有一个静态方法:
public static List of(E…elements){ },返回集合不能增删改。
Set 接口有一个静态方法:
public static set of(){},不能有重复元素,不能增删,没有修改
4.泛型通配符
不确定集合中的元素具体的数据类型使用?表示所有类型
<? extends Person> (无穷小 , Person]
只允许泛型为Person及Person子类的引用调用
<? super Person > [Person , 无穷大)
只允许泛型为Person及Person父类的引用调用
<? super Person > [Person , 无穷大)
只允许泛型为Person及Person父类的引用调用
<? extends Comparable>
只允许泛型为实 现Comparable接口的实现类的引用调用
import java.util.ArrayList;
import java.util.List;
public class test3 {
public static void main(String[] args) {
Dd d = new Dd();
List<String> l1 = new ArrayList<String>();
d.test(l1);
List<Integer> l2 = new ArrayList<Integer>();
d.test(l2);
List<C1> lc = new ArrayList<C1>();
d.test1(lc);
List<D1> ld = new ArrayList<D1>();
d.test1(ld);
// List<B3> lb = new ArrayList<B3>();
// d.test1(lb);
d.test2(lc);
List<A1> la = new ArrayList<A1>();
d.test2(la);
// d.test2(ld);
List<IAImpl> lia = new ArrayList<IAImpl>();
d.test3(lia);
// d.test3(la);
}
}
class Dd{
public void test(List<?> list){//test方法需要一个list集合的参数,不确定list集合到底是存的数的类型是什么
}
public void test1(List<? extends C1> list){//list参数的元素数据类型C1和他的子类
}
public void test2(List<? super C1> list){//list参数的元素数据类型C1和他的父类
}
public void test3(List<? extends lA> list){//list参数的元素数据类型是IA的实现类
}
}
class A1{}
class B3 extends A1{}
class C1 extends B3{}
class D1 extends C1{}
interface lA{}
class IAImpl implements lA{}