前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >JAVA 的重载是运行时决定还是编译的时候决定?正确使用泛型

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

作者头像
用户7886150
修改2020-12-15 10:36:16
修改2020-12-15 10:36:16
4820
举报
文章被收录于专栏:bit哲学院bit哲学院

参考链接: 重载Java中的main()

首先看个例子 

第一个片段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

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档