- 泛型(参数只能是引用类型)
- 泛型的好处:1、避免了类型强制转换的麻烦 2.将运行时期的问题提到了编译时期
- 泛型类:修饰符 class 类名<泛型类型1,泛型类型2,...>{undefined}
- 泛型方法:修饰符 (static) <泛型声明1, 泛型声明2,.....> 返回值类型 方法名称(参数列表) {undefined}
- 泛型接口:修饰符 interface 接口名称<泛型类型1, 泛型类型2,...> {undefined}
- 注意事项:
- 1、在方法上声明的泛型,可以在整个方法中,当做已知类型来使用
- 2、如果【非静态】方法上没有任何泛型的声明,那么可以使用类中定义的泛型
- 3、如果【静态】方法上没有任何的泛型声明,那么就不能使用泛型,连类中定义的泛型,也不能使用,因为类中的泛型需要在创建对象的时候才能确定。(因为静态方法不创建对象就可以调用)所以【静态】方法想使用泛型,就必须在自己的方法上单独声明。
- 类型通配符(用于参数,定义泛型类,泛型方法 如:getData(List<?> data))或public class Erasure<E extends Number>或 public <T extends Number> T getValue(T value):
- <?>:任意类型,可以是与泛型形参无关的类型。getData(List<Number> data)中指定Number类型的参数之后,只能传入Number类型的的集合,连继承它的子类也不能传入,所以才有了类型通配符。
- <? extends E>: 接收E类型或者E的子类型。
- <? super E>: 接收E类型或者E的父类型
- 泛型类派生子类
- 继承父类不声明泛型类型的时候,父类的泛型当Object类型处理
- 继承的父类泛型标识符必须是该类定义的标识符,否则会报错。
- 子类不是泛型类的时候,继承父类若不指定父类泛型,则默认为Object类型,否则就必须指定父类泛型类型。
- 类型擦除(用的泛型标识符都会被擦掉)
- 无限制类型擦除:使用的不是固定上限通配符和下限通配符的泛型类和泛型方法中的泛型都会变成Object类型。
- 有限制类型擦除:使用的是固定上限通配符和下限通配符的泛型类和泛型方法中的泛型都会变成其通配符最高级类的类型。
- 桥接方法(继承中才会出现的问题):类实现泛型接口时,接口中的泛型类型都变成Object类型,而在实现类中也会重写接口方法。{ 因为实现接口时已经指定了泛型类型,在实现类中使用接口的泛型类型就是已经指定类型(使用的不是泛型标识符)了。 }
- 泛型数组
- 第一种方式创建一个数组,将其赋值给泛型数组。:ArrayList<String>[] listArr=new ArrayList[5];注意:可以引用泛型数组,但是不能创建泛型数组对象。
- 第二种方式 (建议使用该方式):Array.newInstance(Class<T> cls,int length)
- 通过Array.newInstance(Class<T> cls,int length) 里面的Class<T> cls泛型参数可以用该类型的变量,否则必须要指定类型(因为我们是调用这个方法,参数必须是实参,否则就用变量代替,创建对象的时候让变量初始化。) :array= (T[]) Array.newInstance(cls,length);
- 反射与泛型的关系:Class<? extends Erasure> c:可以看成通配符的范围就是c对象的数据类型范围。如下面,使用泛型,创建的对象直接就是Person类型,不使用泛型的话会变成Object类型。
- Class<Person> c = Person.class;
- Constructor<Person> con = c.getConstructor();
- Person person = con.newInstance();
5.泛型的总结
于 2022-04-11 18:27:00 首次发布