为什么要定义泛型
比如下面的例子
public class Example {
private Object object; /
public Object getObject(){
return object;
}
public void setObject(Object object){
this.object=object;
}
public static void main(String[] args) {
Example example=new Example();
example.setObject(new Boolean(true));
System.out.println(example.getObject());
example.setObject(new Float(3.14));
float f=(float)example.getObject();
System.out.println(f);
int i=(int)example.getObject();
System.out.println(i);
}
}
example.setObject(new Float(3.14));
float f=(float)example.getObject();
在上面这段代码中,将setObject()的参数传入的是一个Float类,而将Float转换为float变量是没有任何问题的
但是 int i=(int)example.getObject(); 将Float类转换成int类型在运行时他会抛出异常,无法转换。但是在编译的时候并不会报错,这对程序的开发和调试会造成影响
编译时并没有报错
运行时出错
定义泛型
定义类时
类名<类型参数1,类型参数2,....类型参数n>{}
类名<T>
类型<T,A,B> //多个泛型
public class Example<T> {
private T object;
public T getObject(){
return object;
}
public void setObject(T object){
this.object=object;
}
public static void main(String[] args) {
Example<Boolean> example1=new Example<Boolean>();
example1.setObject(true);
System.out.println(example1.getObject());
Example<Float> example2=new Example<Float>();
example2.setObject(3.14f); //float型后面要加f
float f=example2.getObject();
System.out.println(f);
//int i=(int)example2.getObject(); 编译报错 不能转换为int,强制转换也不行
}
}
输出结果:
true
3.14
在main方法里实例化Example< Boolean > example1=new Example< Boolean >() 时,example1里的T就已经变成了Boolean类。
实例化 Example example2=new Example()时,example2的T就变成了Float类,所以它的getObject()方法的返回值也就变成了Float,所以可以赋值给float变量,且不能强制转化为其他类型,所以这时int i=(int)example2.getObject()时会报错。
实力话Example< Boolean > example1=new Example< Boolean >()时也可以Example< Boolean > example1=new Example< >()这么声明
如果是实例化Example example1=new Example(),那么example的 T 默认是Object类
注意
使用泛型声明类时,在<>里声明泛型名称,名称声明时不要和java里已经存在的类重名。
泛型名称中有String,而在类中声明String并赋值时会出错,因为这里的String是泛型名称而不是java里的String,所以无法赋值。想要使用String就得用类的全称java.lang.String
泛型的用法
(1)定义泛型类时声明多个类型
类名<T1,T2>
(2)定义泛型时声明数组类型
类名<T>{
T[] over;
}
public class Example<T> {
private T[] object; //泛型数组
public T[] getObject(){
return object;
}
public void setObject(T[] object){
this.object=object;
}
public static void main(String[] args) {
Example<String> example=new Example<>();
String[] strs={"1","2","3"};
example.setObject(strs);
for(int i=0;i<example.getObject().length;i++){
System.out.println(example.getObject()[i]);
}
}
}
输出结果;
1
2
3
(3)集合类声明容器的元素
还记得Map吗,Map就是使用了泛型
Map的定义
Map<K k,V v> //这就是使用了泛型
比如
Map<String,Integer> map=new HashMap<String, Integer>();
还有ArrayList<>,Vector<>等等
集合类 | 泛型定义 |
---|---|
ArrayList | ArrayList< E > |
HashMap | HashMap<K,V> |
HashSet | HashSet< E > |
Vector | Vector< E> |
泛型的高级用法
(1)限制泛型可用类型
class 类名<T extends anyClass> //anyClass:某个接口或类
限制T 继承List后,就不能用HashMap,HashMao没有继承List
(2)类型通配符
泛型机制中,提供了类型通配符
作用:在创建一个泛型类对象时限制这个泛型类的类型实现或继承某个接口或类的子类
类名<? >
类名<? extends anyClass> //泛型必须是anyClass的子类,且此对象不能做增加和改写操作
类名<? super anyClass> //泛型必须是anyClass的父类,且此对象不能做增加和改写操作
public class Example<T extends List> {
public static void main(String[] args) {
List<String> l1=new ArrayList<>();
List<?> l2=new ArrayList<Number>();
List<?> l3=l1;
l1.add("成员1");
System.out.println(l3.get(0));
l1.set(0,"成员改变");
//l2.add("123"); 编译报错
//l3.set(0,"改变"); 编译报错
System.out.println(l3.get(0));
}
}
输出结果:
成员1
成员改变
因为l2,l3使用了类型通配符,所以不能增加和修改操作
public class Example<T extends List> {
public static void main(String[] args) {
List<? extends List> l1=new ArrayList<List>();
//List<? extends List> l2=new ArrayList<Object>(); 编译报错 因为object不是List的子类
List<? super List> l3=new ArrayList<Object>(); //y因为Object是List的父类
}
}
注意
?类型通配符是在使用的时候可以用,不能在定义的时候去用
报错,因为不能在定义的时候去用
(3)继承泛型类与实现泛型接口
interface MyInterface<T>{
}
class Father<T>{
}
public class Son<T1 ,T2,T3,T4> extends Father<T1> implements MyInterface<T3>{
public static void main(String[] args) {
}
}
Son继承Father,所以Son的泛型里要有Father的泛型T1,Son实现接口MyInterface,所以Son的接口里要有T3,其他的T2,T4是Son独有的
1.全部继承
Son<T1 ,T2,T3> extends Father<T1,T3> //全部继承 Son的T1,T3继承自Father,只有T2是Son独有的
public class Example{
public static void main(String[] args) {
Father<Integer,String> f=new Son<>(1,"2");
//Son<Integer,String,Boolean> s=new Son<>(1,"3"); 报错 因为T3是Boolean ,而构造方法里传入了字符串
Son<Integer,String,Boolean> s=new Son<>(1,true);
}
}
class Father<T1,T2>{
T1 t1;
T2 t2;
public Father(T1 t1,T2 t2){
this.t1=t1;
this.t2=t2;
System.out.println("t1的类型"+this.t1.getClass());
System.out.println("t2的类型"+this.t2.getClass());
}
}
class Son<T1 ,T2,T3> extends Father<T1,T3> {
public Son(T1 t1,T3 t3){
super(t1,t3);
}
}
输出结果:
t1的类型class java.lang.Integer
t2的类型class java.lang.String
t1的类型class java.lang.Integer
t2的类型class java.lang.Boolean
class Son<T1 ,T2,T3> extends Father<T1,T3>
Son<Integer,String,Boolean> s=new Son<>(1,“3”); 会报错 。因为T3是Boolean ,而构造方法里传入了字符串
2.部分继承
Son<T1 ,T2,T3> extends Father<T1,String > //部分继承 在继承时已经将父类的一个泛型实例化了 Son的T1继承自Father,只有T2,T3是Son独有的
public class Example{
public static void main(String[] args) {
Father<Integer,String> f=new Son<>(1,"2");
// Son<Integer,String,Boolean> s=new Son<>(1,true); 报错 因为true 不是字符串类型
Son<Integer,String,Boolean> s=new Son<>(1,"3") //子类的T2,T3随便写 因为他们都不继承自父类,而构造方法里的第一个参数必须是Integer 因为T1继承自父类
}
}
class Father<T1,T2>{
T1 t1;
T2 t2;
public Father(T1 t1,T2 t2){
this.t1=t1;
this.t2=t2;
System.out.println("t1的类型"+this.t1.getClass());
System.out.println("t2的类型"+this.t2.getClass());
}
}
class Son<T1 ,T2,T3> extends Father<T1,String> {
public Son(T1 t1,String t3){ //这里就必须是String 因为已经实例化为String,所以必须传入String
super(t1,t3);
}
}
class Son<T1 ,T2,T3> extends Father<T1,String>
Son<Integer,String,Boolean> s=new Son<>(1,true); 会报错 因为true 不是字符串类型
Son<Integer,String,Boolean> s=new Son<>(1,“3”) ;不会报错 父类的T3已经实例化为String,所以构造方法的第二个参数必须是字符串类型 。子类的T2,T3随便写 因为他们都不继承自父类,而构造方法里的第一个参数必须是Integer 因为T1继承自父类
3.实现父类泛型
class Son<T1 ,T2,T3> extends Father<Integer,String> //已经将父类的泛型全部实现 子类的T1,T2,T3都与父类无关
public class Example{
public static void main(String[] args) {
//Father<Integer,String> f=new Son<>(1,"2");
//Son<Integer,String,Boolean> s=new Son<>(1,true);
Son<Integer,String,Boolean> s1=new Son<>(1,"3"); //因为与父类的泛型无关,所以子类的T1,T2,T3随便写
Son<Integer,Integer,Integer> s2=new Son<>(1,"3");
}
}
class Father<T1,T2>{
T1 t1;
T2 t2;
public Father(T1 t1,T2 t2){
this.t1=t1;
this.t2=t2;
System.out.println("t1的类型"+this.t1.getClass());
System.out.println("t2的类型"+this.t2.getClass());
}
}
class Son<T1 ,T2,T3> extends Father<Integer,String> {
public Son(Integer t1,String t3){
super(t1,t3); //这里就必须是Integer,String 因为已经实例化为Integer,String,所以必须传入Integer,String
}
}
class Son<T1 ,T2,T3> extends Father<Integer,String>
Son<Integer,String,Boolean> s1=new Son<>(1,“3”);
Son<Integer,Integer,Integer> s2=new Son<>(1,“3”);
因为与父类的泛型无关,所以子类的T1,T2,T3随便写,但是构造方法里传入的参数必须是父类已经实现的泛型
4.不实现父类泛型
class Son<T1 ,T2,T3> extends Father //不继承父类的任何泛型 这时父类的泛型就默认为Object
public class Example{
public static void main(String[] args) {
//Father<Integer,String> f=new Son<>(1,"2");
//Son<Integer,String,Boolean> s=new Son<>(1,true);
Son<Integer,String,Boolean> s1=new Son<>(1,"3");
Son<Integer,Integer,Integer> s2=new Son<>(1,3.14f);
Son<String,String,String> s3=new Son<>("1",3.14); //构造方法参数随便写
//子类的T1,T2,T3也随便写
}
}
class Father<T1,T2>{
T1 t1;
T2 t2;
public Father(T1 t1,T2 t2){
this.t1=t1;
this.t2=t2;
System.out.println("t1的类型"+this.t1.getClass());
System.out.println("t2的类型"+this.t2.getClass());
}
}
class Son<T1 ,T2,T3> extends Father {
public Son(Object t1,Object t3){ //因为不实现父类泛型所以默认是Object
super(t1,t3);
}
}
输出结果:(输出结果只与构造方法的参数有关)
t1的类型class java.lang.Integer
t2的类型class java.lang.String
t1的类型class java.lang.Integer
t2的类型class java.lang.Float
t1的类型class java.lang.String
t2的类型class java.lang.Double