泛型是实现对参数的灵活管理.使得参数由具体类型变成无形类型.也可变成约束范围内的类型.使得类,方法,接口更加的灵活多变.
泛型的使用:第一步先声明,第二步声明后就可以调用指的是在编译和运行是使用
声明规范<泛型标识:可以随便写任意标识号,标识指定的泛型的类型>
//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型 //在实例化泛型类时,必须指定T的具体类型 public class Generic<T>{ //key这个成员变量的类型为T,T的类型由外部指定 private T key; public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定 this.key = key; } public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定 return key; } }
1,泛型类:即在类名位置声明,上面的例子就是泛型类,类中声明后,在类里面的方法中就可以使用声明的泛型标识.
2,泛型方法:即在方法返回类型前声明泛型标识
/** * 这是一个真正的泛型方法。 * 首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,并且声明了一个泛型T * 这个T可以出现在这个泛型方法的任意位置. * 泛型的数量也可以为任意多个 * 如:public <T,K> K showKeyName(Generic<T> container){ * ... * } */ public <E> E showKeyName(Generic<T> container){ System.out.println("container key :" + container.getKey()); //当然这个例子举的不太合适,只是为了说明泛型方法的特性。 T test = container.getKey(); return test; }
3,泛型接口和泛型类差不多.都是在接口名上声明
//定义一个泛型接口 public interface Generator<T> { public T next(); }实现类也要继承接口的泛型类型
/** * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中 * 即:class FruitGenerator<T> implements Generator<T>{ * 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class" */ class FruitGenerator<T> implements Generator<T>{ @Override public T next() { return null; } }
总结:用泛型作用:
1,类型安全性(Type safety):一旦使用类型参数后,在该方法或框架中就不存在其他的数据类型,同时也避免了类型转化的需求.
2,类型多样化,使得泛型类,接口,方法,可以实现参数多样化.
3,泛型使用后,规范类型主要是通过编译过程,如果不符合泛型规范,会编译报错,在运行过程是不参与规范的.
通配符?
使用规则:通配符一般是表示容器类型参数的,只能用在方法的参数列表模块或引用类型的参数模块,接收的是一个不确定的类.
作用:与泛型的作用类型起到类型管理的规范作用,调用时在编译过程起到约束作用,不符合通配符规范会编译报错
和Object区别如果只用"?"那么它和Object是一样的,但是"?"有比Object稍微“高级”有点的用法,就是它能缩小一个不确定的范围,利用类似"? extends Test",这就意味着只接收接收Test类的继承类,是不是比Object的范围缩小了?
List<?>:无边界通配符:接收的不知道是属于什么类型的list
List<? extends E>:上界通配符:接收的类型是继承父类E的子类的list
List<? super E>:下界通配符:接收的类型是属于E类型父类的list,E是子类
使用案例:https://www.cnblogs.com/zhenyu-go/p/5536667.html
该链接有具体的不同通配符使用案例,很详细,大家可以看看
总结:通配符就是用来修饰方法的参数类型的.当函数里调用有通配符修饰的方法时,传入的参数必须满足通配符的约束规范,否则会报编译错误;
//通配符修饰的方法参数 public static void addNumbers(List<? super Integer> list) { for (int i = 1; i <= 10; i++) { list.add(i); } } public static void main(String[] args) { List<Object> list1 = new ArrayList<>(); addNumbers(list1); System.out.println(list1); List<Number> list2 = new ArrayList<>(); addNumbers(list2); System.out.println(list2); List<Double> list3 = new ArrayList<>(); // addNumbers(list3); // 编译报错 }
自在在学习的时候突然想到Object和泛型的区别.因为在参数设置时,参数为Object时,就意味着Java中所有类型都能被接收下面的例子可以看出是支持所有类型
//定义一个接收Object参数的方法 public static Object release(Object obj){ return obj; } release(1); release("22"); release(new HashMap());
下面是泛型的使用:泛型也使得方法内参数都支持各种类型.
public class FanxinObject<T> { public T set(T t){ return t; } public static void main(String[] args) { FanxinObject fo=new FanxinObject(); fo.set(1); fo.set("asd"); fo.set(new HashMap()); } }
通过学习自己总结出泛型之所以存在是有原因的:
1,从功能上来说object是灵活可以接收任何参数,但它却无法去规范化,应用过程中容易产生类型转化异常.而泛型是可以设定具体参数类型的,让参数约束化,可具体到某种类型也可具体到某种范围内,
public static void main(String[] args) { //当加入泛型规范为String时,该方法就只能传入String了 FanxinObject<String> fo=new FanxinObject<String>(); fo.set(1);//此处编译报错 fo.set("asd"); fo.set(new HashMap());//此处编译报错 }
从举例中可以看出泛型更加灵活,且可以避免类型转化问题.