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

首先看个例子

这里写图片描述

第一个片段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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值