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
阅读全文
0 0
- JAVA 的重载是运行时决定还是编译的时候决定?正确使用泛型
- tuxedo 本地客户端还是远程客户端是由编译时决定的
- 当你自己决定的时候
- 决定你是富人还是穷人的12条标准
- 决定你是富人还是穷人的12条标准
- 决定你是富人还是穷人的12条标准
- 决定你是富人还是穷人的12法则
- 决定你是富人还是穷人的12条标准
- 决定你是富人还是穷人的12条标准!
- 决定你是富人还是穷人的12条标准
- 决定你是富人还是穷人的12条标准
- 决定你是富人还是穷人的12条
- 决定你是富人还是穷人的12条标准
- 决定你是富人还是穷人的12条标准
- 决定你将是穷人还是富人的十二条
- 决定你是富人还是穷人的12法则
- 决定你是富人还是穷人的12法则
- 决定你是富人还是穷人的12法则
- jdk 源码分析(19)java net包简单分析
- PAT基础题 4-3 简单求和
- centos7通过yum安装JDK1.8
- LeetCode 4Sum C++
- 《Unix网络编程》卷1:套接字联网API(第3版):简介、传输层、套接字编程
- JAVA 的重载是运行时决定还是编译的时候决定?正确使用泛型
- c++面向对象
- 比特币:一种P2P的电子现金体制
- 文件编程
- Linux nf_conntrack连接跟踪的实现
- netty(三) NIO编程
- PAT基础题 4-4 求自定类型元素的平均
- NodeJS+Express+MongoDB
- Linux(Centos7)yum安装最新mysql