赞
踩
目录
往 泛型指定为Double类型的List集合中添加非 Double 的实例:
例如:
- class Son<T> {
- private T t;
- private T[] tArr;
- public final List<T> list = new ArrayList<>();
-
- public void setT(T t) {
- this.t = t;
- }
-
- public T getT() {
- return t;
- }
-
- public List<T> getList(){
- return list;
- }
- }
test:
例如:
- interface Person<T,S,R,U,Q>{
- S s();
- Map<T,R> setMap(U u,Q q);
-
- default void print(T t,S s){
- System.out.println(t.getClass());
- System.out.println(s.getClass());
- }
- }
test:和自定义泛型类是一样的使用,只是接口的泛型是 它的实现类在初始化时、定义时 或者是 子接口定义时、或者是 子抽象类定义时指定的!
形式1(稍微复杂些的)(不常用):
- interface Person<Q> {
- public abstract void personMethod(Q q);
- }
- // 不给定父接口泛型
- interface SubPerson<Q, C> extends Person<Q> {
- default void subMethod(C c) {
- System.out.println(c.getClass());
- }
- }
- // 给定父接口泛型,同时声明自己类中的泛型
- abstract class AbstractPerson<T, U, S> implements SubPerson<List<String>, HashMap<String, String>> {
-
- @Override
- public void personMethod(List<String> list) {
- list.add("抽象类向集合中添加元素");
- }
-
- public abstract ArrayList<Object> personMethod(T t, U u);
-
- protected void method2(S s) {
- System.out.println(s.getClass());
- }
- }
- // 给定父接口的第三个泛型为 Scanner 类型
- // 其他两个泛型在实例化 Coder的时候再指定。
- // Coder再声明一个自己的泛型。
- class Coder<R, T, U> extends AbstractPerson<T, U, Scanner> {
-
- private T t;
- private U u;
- public Coder(T t,U u){
- this.t = t;
- this.u = u;
- }
- public T getT(){
- return t;
- }
- public U getU(){
- return u;
- }
- @Override
- public ArrayList<Object> personMethod(T t, U u) {
- ArrayList<Object> list = new ArrayList<>();
- Collections.addAll(list, t, u);
- return list;
- }
-
- public Double useR(R r) {
- if (r instanceof Integer) {
- return Double.valueOf(calculate((Integer) r, 100));
- } else {
- System.out.println(r.getClass());
- }
- return Math.PI;
- }
-
- private int calculate(int start, int target) {
- return (start + target) * (target / 2);
- }
- }
test:
- public static void testGenericExtends() {
- Coder<Integer, String, Double> coder =
- new Coder("第二个泛型为String类型",Math.E);
- coder.method2(new Scanner(System.in));
- // 直接以实例化时给定的泛型为准
- String t = coder.getT();
- System.out.println(t);
- Double u = coder.getU();
- System.out.println(u);
-
- coder.personMethod(new ArrayList<>());
- ArrayList<Object> objects = coder.personMethod("圆周率:", Math.PI);
- System.out.println(objects);
-
- Double result = coder.useR(1);
- System.out.println(result);
- }
形式2(什么泛型都不在定义泛型类、泛型接口的时候 给定)(常用):
- interface People<T> {
- public abstract Integer peopleMethod(T t);
- }
-
- interface Man<T, S> extends People<T> {
- @Override
- Integer peopleMethod(T t);
-
- default String m1(S s, T t) {
- return s.getClass().toString() + "和" + t.getClass().toString();
- }
- }
-
- abstract class Dad<T, S> implements Man<T, S> {
- protected T t;
-
- protected Dad(T t) {
- this.t = t;
- }
-
- @Override
- public Integer peopleMethod(T t) {
-
- return (Integer) t + 999999;
- }
- }
-
- class Child<T, S, L> extends Dad<T, S> {
- private S s;
-
- public Child(T t, S s) {
- super(t);
- this.s = s;
- }
-
- public S getS() {
- return s;
- }
-
- public List<? extends L> getList() {
- return new LinkedList<>();
- }
- }
test:
- public static void main(String[] args) {
- Child<Integer, String, Serializable> child = new Child<>(9090, "Created at 2021-06-14 08:59");
- String s = child.getS();
- System.out.println(s);
- Integer integer = child.peopleMethod(789);
- System.out.println(integer);
- Integer t = child.getT();
- System.out.println(t);
-
- List<? super Serializable> list = child.getList();
- list.add(new Date());
- list.add(new java.sql.Date(System.currentTimeMillis()));
- list.add(new ArrayList<Timestamp>().add(null));
- ArrayList<Long> currentTimeMillis = new ArrayList<>();
- currentTimeMillis.add(new GregorianCalendar().getTime().getTime());
-
- System.out.println(list);
- System.out.println(currentTimeMillis);
- System.out.println(child.m1(new String(), Integer.MAX_VALUE));
- }
test:
- public class GenericTest3 {
- public static void main(String[] args) {
- Generic<Generic> generic = new Generic<>();
- Generic generic1 = generic.isNotGenericMethod(generic);
- System.out.println(generic);
- System.out.println(generic1);
-
- String s = generic.isGenericMethod("是String类型");
- System.out.println(s);
- ArrayList<Date> dates = new ArrayList<>();
- List<ArrayList<Date>> listInstance = Generic.getListInstance(dates);
- listInstance.add(dates);
- System.out.println(listInstance.getClass());
- }
-
- }
-
- class Generic<T> {
- private T t;
-
- public Generic(){}
- // 此方法并不是泛型方法
- public T isNotGenericMethod(T t) {
- return isNotGenericMethod2(t);
- }
- // 此方法也不是泛型方法
- private T isNotGenericMethod2(T t) {
- T tt = null;
- try {
- // 通过这样的反射方式 创建本类对象,构造器必须显示初始化才可以!
- tt = (T) t.getClass().getConstructor().newInstance();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return tt;
- }
-
- // 是泛型实例方法
- public <S> S isGenericMethod(S s){
- if ("是String类型".equals(s)){
- return s;
- }
- return null;
- }
-
- // 是泛型静态方法
- public static <U> List<U> getListInstance(U u){
- if (u instanceof List){
- return new LinkedList<>();
- }
- return null;
- }
- }
result:,泛型在编译时的数据类型:- class Generic2<G> {
- private G[] gArr;
- private Object obj;
-
- public <T> Generic2(T t) {
- // 多态的引用!
- obj = t;
- // 创建泛型数组的方式1:
- // (如果在实例化Generic2的时候,给定的泛型不是 被强转的类型时就会
- // 引发并抛出 ClassCastException 异常,
- // 因为向下转型的前提是要
- // 父类引用指向子类对象时。
- // 这时候的向下转型到子类类型的时候 才不会抛出 ClassCastException
- // (G[]) new Object[5] 如果这里的向下转型在实例化Generic2的时候
- // 指定的泛型如果不是Object时,是其他类的时候,就会抛出 ClassCastException异常
- // 因为要清楚的知道的是 new Object[5] 这个动作是在 初始化 Object类型的
- // 数组,而不是在初始化 泛型的数组,泛型的数组不能够被初始化!
- // 因为泛型是未知的数据类型,怎么初始化?)
- gArr = (G[]) new Object[5];
- }
-
- public G[] getgArr(){
- return gArr;
- }
- public Object getObj(){
- return obj;
- }
- }
test1:,使用泛型数组是,引发的ClassCastException异常情况:
- class Generic2<G> {
- private G[] gArr;
- private Object obj;
-
- public <T> Generic2(T t) {
- // 多态的引用!
- obj = t;
- // 创建泛型数组的方式1:
- // (如果在实例化Generic2的时候,给定的泛型不会 被强转的类型时就会
- // 引发并抛出 ClassCastException 异常,
- // 因为向下转型的前提是要
- // 父类引用指向子类对象时。
- // 这时候的向下转型到子类类型的时候 才不会抛出 ClassCastException
- // (G[]) new Object[5] 如果这里的向下转型在实例化Generic2的时候
- // 指定的泛型如果不是Object时,是其他类的时候,
- // 如果在类的外部获取 G[] 这个泛型数组,就会抛出 ClassCastException异常
- // 因为要清楚的知道的是 new Object[5] 这个动作是在 初始化 Object类型的
- // 数组,而不是在初始化 泛型的数组,泛型的数组不能够被初始化!
- // 因为泛型是未知的数据类型,怎么初始化?)
- // 如果这里用了 (G[]) new Object[5] 其本质就是在使用 Object类型的数组!
- // 这种方法没有任何意义。要么就直接使用 Object 的数组,没有必要转来转去。
- gArr = (G[]) new Object[5];
- }
-
-
- public G[] initializeGArr(Class<? super G> clazz, int initLength) {
- // 创建泛型数组的方式2:通过反射包下( java.lang.reflect.Array;)的 Array类的newInstance创建数组对象
- /* public static Object newInstance(Class<?> componentType, int length)
- throws NegativeArraySizeException {
- return newArray(componentType, length);
- }
- 这个API的本质仍是返回的Object类型。)(newArray底层是一个本地方法,由C或者C++实现)
- 而引用数据类型的数组都继承自 Object 和 Object[]
- 基本数据类型的一维数组只继承自 Object,它们并没有继承自 Object[]
- 因为基本数据类型并不是引用数据类型!
- (需要说明的是,基本数据类型
- 二维数组继承自 Object 、Object[]
- 三维数组继承自 Object 、Object[] 、 Object[][]
- 依次类推……
- 引用数据类型
- 二维数组继承自 Object、Object[] 、Object[][]
- 三维数组继承自 Object 、Object[] 、 Object[][] 、Object[][][]
- 依次类推……)
- */
- gArr = (G[]) Array.newInstance(clazz, initLength);
- return gArr;
- // return (G[]) Array.newInstance(clazz, initLength);
- }
-
- public G[] getgArr() {
- return gArr;
- }
-
- public Object getObj() {
- return obj;
- }
- }
-
- /*
- 使用反射创建泛型数组的对象的时候方法签名中接收Class对象时
- 可以有的形式:它们四种方式都有可能引发 ClassCastException!!! 不是绝对安全的!
- 第一种:使用 泛型通配符:
- public G[] initializeGArr(Class<?> clazz, int initLength)
- 第二种:使用 泛型下限通配:
- public G[] initializeGArr(Class<? super G> clazz, int initLength)
- 第三种:使用 泛型上限通配:
- public G[] initializeGArr(Class<? extends G> clazz, int initLength)
- 第四种:就是不使用泛型(泛型擦除):
- public G[] initializeGArr(Class clazz, int initLength)
- */
test:
- public static void main(String[] args) {
- Generic2<HashMap<String, String>> generic2 = new Generic2<>(123);
- HashMap<String, String>[] hashMaps = generic2.initializeGArr(HashMap.class, 3);
- HashMap<String, String> map = new HashMap<>();
- map.put("first", "Array.newInstance(Class<?> componentType, int length)通过反射创建泛型数组");
- hashMaps[0] = map;
- for (int i = 0; i < hashMaps.length; i++) {
- System.out.println(hashMaps[i]);
- }
- System.out.println("hashMaps.length = " + hashMaps.length);
- System.out.println("hashMaps.getClass() = " + hashMaps.getClass());
- Object obj = generic2.getObj();
- System.out.println("obj.getClass() = " + obj.getClass());
- }
result:
- public static void main(String[] args) {
- Generic2<Generic> Generic2 = new Generic2<>();
- Generic<Object> generic = new Generic<>();
- Generic instance = Generic2.getGInstance(generic);
- System.out.println(generic.toString());
- System.out.println(instance.toString());
-
- String str = Generic2.getInstance(String.class);
- System.out.println(str.getClass().getSuperclass().getSimpleName());
-
- }
-
- // 一把都不这样创建 类的泛型的对象。
- // 直接在外部使用的时候创建就好了,
- // 为什么在泛型类中创建?
- public G getGInstance(G g) {
- return reflectNewInstance(g);
- }
-
- private G reflectNewInstance(G g) {
- try {
- g = (G) g.getClass().getConstructor().newInstance();
- } catch (Exception e) {
-
- }
- return g;
- }
-
- // 可以使用泛型方法创建其他类的对象!
- /* 前提是这个类本身就要能够创建对象*/
- public <T> T getInstance(Class<T> c) {
- T t = null;
- try {
- t = c.getConstructor().newInstance();
- } catch (Exception e) {
-
- }
- return t;
- }
-
- public Generic2() {
- }
result:
- 不管是使用 自定义的泛型类还是用别人写的泛型类。在实例化泛型类的时候,在有 数据类型 对象名 引用的情况下。都不用再指定泛型。在JDK1.7之前需要手动指定。到时再JDK1.5之后,编译器会自行推断。比如:
- 泛型类的实例成员(实例变量、常量、方法、代码块、内部类)中可以直接使用类的泛型!
- 类的静态成员(静态变量、常量、方法、代码块、静态内部类、静态内部枚举、静态内部接口、静态内部注解)不能够使用 类的 泛型。因为泛型是属于类的实例的,静态方法是属于类的,并不是属于类的实例的。静态成员加载时还没有创建对象。所以不能够使用类的泛型。
- 泛型类在继承类的时候,这个父类不一定要是 泛型类。可以是一个普通的类。在继承、实现泛型接口的时候,这个父接口不一定要是个 泛型接口,可以是一个普通接口。
- 泛型类在继承泛型父类 or 实现接口、包括泛型子接口继承泛型父接口的时候,如果泛型类在定义的时候,没有给 泛型父类 or 泛型父接口给定具体数据类型的话,那么这个泛型类、泛型子接口 的 泛型声明 也要是和泛型父类、泛型父接口的泛型声明一样!
- 泛型类在继承泛型父类 or 实现接口的时候,泛型类在定义的时候,可以在继承 or 实现时 更改泛型父类 or 泛型父接口的 泛型标识符 ,此时泛型类的 泛型声明的泛型标识符要和自己修改的一样!(一般很少这样操作)子泛型接口 继承 父泛型接口也是一样!
- 泛型类在继承泛型父类 or 实现泛型接口的时候,泛型类在定义的时候,泛型类的泛型声明的泛型标识符的顺序可以和 泛型父类 or 泛型父接口的不一致。但是这样很容易搞混淆(基本上 不会把顺序搞得不一样。)子泛型接口 继承 父泛型接口也是一样!
- 一个普通类 也可以继承、实现 泛型父类、泛型父接口、一个 普通接口 也可以继承 泛型父接口。但是前提是 在 继承 or 实现的时候,要给 泛型父接口、泛型父类给定具体的数据类型!
- 泛型类在继承或者实现时,泛型接口在继承时。可以拓展自己的泛型声明!可以有 0 ~ n个泛型声明!
- 泛型类的构造器写法和普通类的构造器写法是一样的,泛型类的构造器后面没有<>这个符号。比如:,不会因为这个类是个泛型类,构造器的写法就有所改变。构造器如果想使用自己独有的泛型的话,那么这个构造器可以定义成为泛型构造器。
- 泛型类中的静态变量 以及 静态常量 不能使用 泛型!类中的静态成员有 静态方法、静态内部类、静态内部接口 可以使用自己的泛型!静态的成员不能够使用类的泛型!
- 如果在 定义 泛型类 的时候 没有给泛型父类和泛型父接口给定具体类型的话。那么在实例化这个 泛型类的时候,尽量给定具体的数据类型。不然就会 发生编译时的 泛型擦除。即 所有的 泛型标识符 表示的数据类型 都会泛型擦除为 Object 类型。(要么所有的泛型都不给定具体数据类型。要么全部泛型都要给定具体数据类型,没有给定几个和不给定几个的操作!)
- 泛型类的泛型是在 泛型类继承 泛型父类、实现 泛型接口 或者是 实例化泛型类的时候 给定具体数据类型。如果说 在 定义时和实例化时都没有给定具体的数据类型。那么这些泛型声明就啥作用都没有,全部泛型擦除为Object类型
- 自定义异常类不可以是泛型类,编译器不支持。但是 异常类中可以有 泛型方法。
- 自定义枚举类不可以是泛型类,编译器不支持。但是 枚举类中可以有 泛型方法。
- 自定义注解不可以是泛型注解,编译器不支持。
- 泛型方法可以分为 泛型静态方法 和 泛型实例方法 和 泛型构造器 。
- 泛型方法必须要有 <泛型标识符> 泛型声明(钻石运算符 ) !不然这个方法就不是泛型方法!如果是实例方法,那么只能说这个方法使用了类的泛型。而它本身不是泛型方法。
- 泛型方法 可以出现在 普通类、普通抽象类、普通接口、泛型类、泛型抽象类、泛型接口、枚举类、自定义异常类、静态内部类、局部内部类(只能有泛型实例方法)、实例内部类(只能有泛型实例方法)、匿名内部类(只能有泛型实例方法)
- 泛型方法的重载注意事项(不能是相同的泛型声明,这和是不是相同的泛型标识符无关,因为它们 泛型声明的 泛型擦除后的 类型都是Object,所以不构成泛型方法的重载!):,,构造泛型方法的重载就要满足方法重载的必要条件,即(方法名必须相同、参数类型不同、或者 参数类型个数不同 或者参数类型顺序不同 (和是不是静态方法、实例方法无关!)),泛型方法重载的坑:,这样 重载实例方法的时候 虽然在编译时通过了编译,倒是如果在调用的时候,传入了String类型的话。这个时候,编译器就懵逼了。比如:,引发编译不通过的错误:,解决方法:要么实例化泛型类的时候就不要指定泛型为 和已有的重载方法形参类型相同 ,要么就把 已经给定了的数据类型的那个重载方法改成其他数据类型!比如:
- 泛型方法的泛型是独立于类而存在的,类、接口的泛型是以类、接口为单位!而方法的方法是以方法为单位!即 即使泛型方法的泛型声明的泛型标识符和类、接口的泛型标识符是一样的。也是独立开来的,这并影响 泛型方法的调用。为了避免歧义。所以 Java规定了要 写 泛型声明 !
- 泛型方法的泛型声明 必须在返回值的前面、方法修饰符的后面!
- 泛型实例方法、泛型构造器 既可以使用方法、构造器 自己本身的泛型,也可以使用 类的泛型。而泛型静态方法只能够使用 泛型静态方法自己本身 的泛型!
- 泛型方法的泛型是在调用方法时 给定具体的 数据类型 的,即调用泛型方法时,传入了 什么引用数据类型的实例(即 实参)调用方法,即 这个泛型表示符 所表示的 数据类型就是 这个实参的 数据类型。
- 而 (泛型类泛型接口的泛型 可以是在 类、泛型类 继承 泛型父类,实现泛型父接口的时候 给泛型父类、泛型父接口 给定具体的数据类型)(一般都不会在继承、实现是给定 引用数据类型,只是说可以zheyan)。如果没有给定,那么这个泛型类的 泛型标识也要和 泛型父类、泛型父接口的泛型标识一样。如果没有在继承 or 实现的时候给定 泛型父类、泛型父接口具体的数据类型。那么在实例化 泛型类 的时候,也可以 给定 泛型的具体类型!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。