class A<T>{}
interface B <T1,T2>{}
我们在声明完自定义泛型类以后,可以在类的内部(比如:属性、方法、构造器中)使用类的泛型。
我们在创建自定义泛型类的对象时,可以指明泛型参数类型。一旦指明,内部凡是使用类的泛型参数的位置,都具体化为指定的类的泛型类型。
如果在创建自定义泛型类的对象时,没有指明泛型参数类型,那么型将被擦除,泛型对应的类型均按照Object处理,但不等价于0bject。
经验:泛型要使用一路都用。要不用,一路都不要用。
泛型的指定中必须使用引用数据类型。不能使用基本数据类型,此时只能使用包装类替换
除创建泛型类对象外,子类继承泛型类时、实现类实现泛型接口时,也可以确定泛型结构中的泛型参数
如果我们在给泛型类提供子类时,子类也不确定泛型的类型,则可以继续使用泛型参数。
我们还可以在现有的父类的泛型参数的基础上,新增泛型参数。
异常不能带泛型
不能在静态方法中使用泛型。因为使用静态方法时会预先加载,这个时候还不知道泛型是否指明了类型。
在方法中指明了泛型,就是泛型方法吗?
不是,如下不属于泛型方法。
public T getT() {return t}
public void setT(T t) {this.t = t}
//通常在形参列表和返回值类型会出现泛型参数T
//权限修饰符 <T> 返回值类型 方法名 (形参列表 ){}
public <E> E method(E e){
return e
}
就看方法前有没有声明< E >,否则会被认为是泛型类,让编译器知道这个是个泛型的方法。
声明泛型方法时,一定要添加泛型参数< T >
泛型参数在方法调用时,指明其具体的类型
泛型方法可以根据需要声明为static的
泛型方法所属的类是否是一个泛型类,都可以。
在 Java 中,泛型类型参数是在实例化时确定的,并且静态方法是属于类而不是属于对象的。因为泛型类型参数是在实例化时才会被确定,而静态方法在编译期就已经确定了,所以无法使用泛型类型参数。
另外,对于静态方法来说,它们不能访问非静态的成员变量或者调用非静态的方法,因为在调用静态方法时可能还没有创建对象。如果允许泛型类型参数用于静态方法,则会与这种限制相矛盾。
因此,在 Java 中,我们无法在静态方法中使用泛型类型参数。如果需要在静态方法中使用泛型类型,则可以将泛型类型参数声明为该类的一个属性或者方法的形参,然后通过这个属性或者形参来使用泛型类型。
子类的泛型已经指定类型了,就不能向上转换类了。
例如,
Person<String> per=null;
Person<Object> per1=null;
//per不可以赋值给per1
如果per可以赋值给per1那么per1可以添加非String类型元素,String的限制将会消失,所以不可以。
如果都指定类型为String,子类是可以赋值给父类的,内容类型都一样
例如:
public class Test11 {
@org.junit.Test
public void test111(){
List<String> list1 = null;
ArrayList<String> list2 = new ArrayList<>();
list2.add("asd");
list2.add("dsa");
list1 = list2;
System.out.println(list1);
}
}
通配符: ?
使用说明
G< ?>可以看做是G< A>类型的父类,即可以将G< A>的对象赋值给G< ?>类型的引用(或变量)
举例 ArrayList< ? >
这里Object类型的List和String类型的都可以放进< ?>的List中
@Test
public void test12(){
List<?> list=null;
List<Object> list1=null;
List<String> list2=null;
list=list1;
list=list2;
}
@Test
public void test2() {
List<?> list = null;
List<String> list1 = new ArrayList<>();
list1.add("AA");
list = list1;
//读取数据(以集合为例说明)
Object obj = list.get(0);
System.out.println(obj);
//写入数据(以集合为例说明),不可以写入,但是null可以
// list.add("BB");
list.add(null);
}
@Test
public void test6(){
List<? extends Father> list = null;
List<Object> list1 = null;
List<Father> list2 = null;
List<Son> list3 = null;
//Object不可以赋值,可以把extends理解为小于等于号,只有它的子类和本身类的可以赋值
list = list1;
list = list2;
list = list3;
}
@Test
public void test7(){
List<? super Father> list = null;
List<Object> list1 = null;
List<Father> list2 = null;
List<Son> list3 = null;
//Son不可以赋值,可以把super理解为大于等于号,只有它的父类和本身类的可以赋值
list = list1;
list = list2;
list = list3;
}
技巧:开发中,遇到了带限制条件的通配符,在赋值时,如果没报错,那就正常使用。
如果报错了,知道不能这样写。改改!
举例:
@Test
public void test3_1() {
List<? extends Father> list = null;
List<Father> list1 = new ArrayList<>();
list1.add(new Father());
list = list1;
//读取数据: 可以的
Father father = list.get(0);
//写入数据: 不可以的。例外:list.add(null);
list.add(new Father());
list.add(new Son());
}
@Test
public void test4_1() {
List<? super Father> list = null;
List<Father> list1 = new ArrayList<>();
list1.add(new Father());
list = list1;
//读取数据: 可以的
Object obj = list.get(0);
//写入数据:
list.add(null);
//下界为Father类,Father以下的类都可以放入
list.add(new Object());
list.add(new Father());
list.add(new Son());
}
推荐阅读: