关于java泛型擦除反编译后泛型会出现问题

首先,java中有泛型擦除这一概念。如果不太了解这一概念的同学可以自己找一下度娘。(简单来说:就是如果使用了泛型,在编译期的时候泛型会被擦除掉,也就是说jvm所看到的class文件中是不存在泛型这一概念和东西的。)

好。进入主题,关于泛型擦除,但是反编译class文件泛型会出现的问题。以例子来说明

首先,先写一个使用了泛型的java文件

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by beyondLi on 2017/5/26.
 */
public class GenericsTest {
    @Test
    public void generics(){
        //首先创建一个list集合,并使用泛型
        List<Integer> list = new ArrayList<>();
        list.add(100);
        list.add(200);
        System.out.println(list);
    }
}
使用反编译工具查看生成的class文件(idea自带反编译插件)

import java.util.ArrayList;
import java.util.List;
import org.junit.Test;

public class GenericsTest {
    public GenericsTest() {
    }

    @Test
    public void generics() {
        List<Integer> list = new ArrayList();
        list.add(Integer.valueOf(100));
        list.add(Integer.valueOf(200));
        System.out.println(list);
    }
}
奇怪,泛型不是被擦除了吗。为什么反编译还会存在。肯定有同学会说。和反编译工具有关。这里我使用了jd-gui和Beyond Compare分别进行了反编译结果如下

gui

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;

public class GenericsTest
{
  @Test
  public void generics()
  {
    List<Integer> list = new ArrayList();
    list.add(Integer.valueOf(100));
    list.add(Integer.valueOf(200));
    System.out.println(list);
  }
}

Compare

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

public class GenericsTest
{

    public GenericsTest()
    {
    }

    public void generics()
    {
        List list = new ArrayList();
        list.add(Integer.valueOf(100));
        list.add(Integer.valueOf(200));
        System.out.println(list);
    }
}

肯定有同学说,你看。就说和反编译工具有关吧。Compare不就没有泛型了吗。官方都说了会泛型擦除怎么会有问题。

但是还是存在一个问题,那gui又是怎么找到的泛型呢?idea呢?

最后我使用了java自带的反编译工具javap -c 来进行反编译,来看看到底是怎么回事。

Compiled from "GenericsTest.java"
public class GenericsTest {
  public GenericsTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void generics();
    Code:
       0: new           #2                  // class java/util/ArrayList
       3: dup
       4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
       7: astore_1
       8: aload_1
       9: bipush        100
      11: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      14: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      19: pop
      20: aload_1
      21: sipush        200
      24: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      27: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      32: pop
      33: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      36: aload_1
      37: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      40: return
}
虽然本人也不是很能看懂java自带的反编译工具编译出来的结果,但是可以得到的结论是,从不同的反编译工具中可以看出,至少反编译工具是可以从class文件中找到你之前使用的泛型的,证明文件中是存在标记来记录这个泛型的,然后从javap中我们可以看出,虽然泛型不在代码中了,但是他还是记录在了注释中,这样就可以解释通为什么有的反编译工具可以反编译出泛型了。

泛型在编译期会被擦除的结论是没有问题的,在jvm中不存在泛型的概念。但是反编译工具通过注释中的记录找到了之前使用过的泛型类型,并在反编译时将其添加回来,所以我们所看到的反编译的文件中泛型存在,好像与泛型擦除这一概念冲突了。然而事实证明并没有,只是反编译工具太智能了而已。

以上为本人个人的见解,并且对javap所反编译出来的文件也无法达到完全看懂的地步,如有哪里错误,还希望指出,可让我继续成长。




  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值