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

首先看个例子

JAVA 的重载是运行时决定还是编译的时候决定?正确使用泛型_第1张图片

第一个片段A的部分 传入的实际类型是String希望调用C片段,但是实际上是调用的B。
JAVA 的重载是运行时决定还是编译的时候决定?正确使用泛型_第2张图片

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

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

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

解决和建议:

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

 public static  void ifNotEmpty(T t, Consumersuper 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 > 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."":()V
       7: astore_1
       8: aload_1
       9: invokestatic  #5                  // Method isEmpty:(Ljava/util/Collection;)Z
      12: pop
      13: return

第二种为

 public static > 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."":()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 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."":()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

你可能感兴趣的:(JAVA 的重载是运行时决定还是编译的时候决定?正确使用泛型)