JAVA 的重载是运行时决定还是编译的时候决定?正确使用泛型

来源:互联网 发布:php培训费用 编辑:程序博客网 时间:2024/05/21 17:46

首先看个例子

这里写图片描述

第一个片段A的部分 传入的实际类型是String希望调用C片段,但是实际上是调用的B。
这里写图片描述

敲黑板:Java的泛型是运行时就擦除了的。
不要出现参数数量一样的方法重载,可能出错不说,而且完全不清晰。
T 会擦除成Object。
调哪个编译时就确定了。

我们看下Optional的泛型如何可以准确找到isEmpty(String s)

Optional<String> str = Optional.of("me");        str.ifPresent(v->{            boolean exit = Util.isEmpty(v);        });

解决和建议:

一个是去掉泛型,避免同一后再细化。第二种是修改重载的部分如下:

 public static <T> void ifNotEmpty(T t, Consumer<? super T> consumer) {    if (!isEmpty(t)) {        consumer.accept(t);    }    }    public static boolean isEmpty(Object obj) {    if (obj == null)        return true;    Class<?> clazz = obj.getClass();    if (clazz.isArray()) {        if (clazz == byte[].class) // eClass.getComponentType() == byte.class        return ((byte[]) obj).length == 0;        if (clazz == short[].class)        return ((short[]) obj).length == 0;        if (clazz == int[].class)        return ((int[]) obj).length == 0;        if (clazz == long[].class)        return ((long[]) obj).length == 0;        if (clazz == char[].class)        return ((char[]) obj).length == 0;        if (clazz == float[].class)        return ((float[]) obj).length == 0;        if (clazz == double[].class)        return ((double[]) obj).length == 0;        if (clazz == boolean[].class)        return ((boolean[]) obj).length == 0;        Object[] objArr = (Object[]) obj;        return objArr.length == 0;    }    if (String.class.isAssignableFrom(clazz)) {        return ((String) obj).length() == 0;    }    if (Map.class.isAssignableFrom(clazz)) {        return ((Map<?, ?>) obj).size() == 0;    }    if (Collection.class.isAssignableFrom(clazz)) {        return ((Collection<?>) obj).size() == 0;    }    throw new SysException("unkown classType {}", clazz.getCanonicalName());    }
另外判断类型是否是某个接口的子类实现或者本身的正确姿势
    System.out.println(Map.class.isAssignableFrom(HashMap.class));    System.out.println(null instanceof String);    System.out.println(String.class.isInstance("a"));

正确使用泛型

下面两段代码是一样的

 public static  boolean isEmpty(Collection<?> t) {    return null == t || 0 == t.size();    }    public static <T extends Collection<?>> boolean isEmpty(T t) {    return null == t || 0 == t.size();      }

编译后:

public static boolean isEmpty(java.util.Collection<?>);    Code:       0: aconst_null       1: aload_0       2: if_acmpeq     15       5: iconst_0       6: aload_0       7: invokeinterface #2,  1            // InterfaceMethod java/util/Collection.size:()I      12: if_icmpne     19      15: iconst_1      16: goto          20      19: iconst_0      20: ireturn  public static void main(java.lang.String[]);    Code:       0: new           #3                  // class java/util/ArrayList       3: dup       4: invokespecial #4                  // Method java/util/ArrayList."<init>":()V       7: astore_1       8: aload_1       9: invokestatic  #5                  // Method isEmpty:(Ljava/util/Collection;)Z      12: pop      13: return

第二种为

 public static <T extends java.util.Collection<?>> boolean isEmpty(T);    Code:       0: aconst_null       1: aload_0       2: if_acmpeq     15       5: iconst_0       6: aload_0       7: invokeinterface #2,  1            // InterfaceMethod java/util/Collection.size:()I      12: if_icmpne     19      15: iconst_1      16: goto          20      19: iconst_0      20: ireturn  public static void main(java.lang.String[]);    Code:       0: new           #3                  // class java/util/ArrayList       3: dup       4: invokespecial #4                  // Method java/util/ArrayList."<init>":()V       7: astore_1       8: aload_1       9: invokestatic  #5                  // Method isEmpty:(Ljava/util/Collection;)Z      12: pop      13: return

可以看到main方法中在编译后已经指定具体方法了
如果我们将main函数的代码修改如下

public static void main(String args[]){    List<Object> list = new ArrayList<>();    Object o = list;    isEmpty(o);    }

反编译会发现调用的是isEmpty(Object o)而不是isEmpty(Collection list),即不是根据实际类型来寻找具体的重载方法,而是在编译的时候就已经决定了

public static void main(java.lang.String[]);    Code:       0: new           #3                  // class java/util/ArrayList       3: dup       4: invokespecial #4                  // Method java/util/ArrayList."<init>":()V       7: astore_1       8: aload_1       9: astore_2      10: aload_2      11: invokestatic  #5                  // Method isEmpty:(Ljava/lang/Object;)Z      14: pop      15: return
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 车贷合同没给我怎么办 车内老是有灰尘怎么办 车在北京怎么办进京证 五证合一后社保怎么办 五证齐全烂尾了怎么办 5万罚款交不起怎么办 炼铅环保手续要怎么办 贴膏药过敏红肿太痒了怎么办 没工作想贷款5万怎么办 燃气管超过2米了怎么办 建行燃气卡丢了怎么办 周浦燃气卡丢了怎么办 长沙燃气卡丢了怎么办 郑州燃气卡丢了怎么办 租房燃气卡丢了怎么办 洛阳燃气卡丢了怎么办 零线火线都带电怎么办 档案里年龄错了怎么办 档案年龄大了怎么办呢 吃菌子致幻了怎么办 野外吃了毒蘑菇怎么办 头顶头发稀少怎么办头顶头发稀 遇见无赖的人该怎么办 扶了老人被讹诈怎么办 遇见碰瓷讹人的怎么办 假机油用了4年怎么办 苹果6手机变砖头怎么办 苹果8升级变砖头怎么办 苹果id锁变砖头怎么办 钥匙断在锁里了怎么办? u型锁忽然打不开怎么办 密码门锁没电了怎么办 智能门锁没电了怎么办 十字锁钥匙丢了怎么办 罐头的拉环断了怎么办 锁坏了 打不开了怎么办 门锁锁不起来了怎么办 卧室门锁舌断了怎么办 锁舌头坏了怎么办自救 门锁斜舌头断了怎么办 锁把手断了半截怎么办