【问题标题】:Decompiler tools modify the source code for .class file in java反编译工具修改java中.class文件的源代码
【发布时间】:2015-03-29 05:18:16
【问题描述】:

我使用DJ JAVA DECOMPILER工具从java中的.class文件中取回源代码。它生成的源文件与我之前在原始源程序中编写的代码相比具有不同的代码

我的疑问是:

  1. 这是因为JVM在创建之前做了代码优化 目标代码以提高执行速度并减少空间和时间 复杂性?
  2. 或者反编译工具修改.class文件代码生成 又是源程序?

看到原来的源程序是这样的:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;


public class Test1 {
    /**
     * @param args
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public static void main(String args[]) throws SQLException, ClassNotFoundException{
        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection con= DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:choxx","choxx","choxx");
        if(con==null){
            System.out.println("not established");
        }else{
            System.out.println("established");
        }

        Statement st= con.createStatement();
        //st.executeQuery("create table student if not exists(sno number(10), name varchar2(30), addr varchar(20))");
        if(st!=null){
            System.out.println("table created..");
        }

        st.execute("delete from student where addr='hyderabad'");
        ResultSet rs= st.executeQuery("select * from student");
        while(rs.next()){
            System.out.println(rs.getInt(1)+"   "+rs.getString(2)+"   "+rs.getString(3));
        }


    }
}

反编译后得到的是:

// Decompiled by DJ v3.12.12.99 Copyright 2015 Atanas Neshkov  Date: 29-03-2015 10:55:31
// Home Page:  http://www.neshkov.com/dj.html - Check often for new version!
// Decompiler options: packimports(3) 
// Source File Name:   Test1.java

import java.io.PrintStream;
import java.sql.*;

public class Test1
{

    public Test1()
    {
    }

    public static void main(String args[])
        throws SQLException, ClassNotFoundException
    {
        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:choxx", "choxx", "choxx");
        if(con == null)
            System.out.println("not established");
        else
            System.out.println("established");
        Statement st = con.createStatement();
        if(st != null)
            System.out.println("table created..");
        st.execute("delete from student where addr='hyderabad'");
        for(ResultSet rs = st.executeQuery("select * from student"); rs.next(); System.out.println(rs.getInt(1) + "   " + rs.getString(2) + "   " + rs.getString(3)));
    }
}

【问题讨论】:

  • 您能解释一下您观察到的任何变化吗?
  • 所以它已经完成了编译器的优化目的。如果您比较您在源代码中完成的 for 循环和反编译版本中的 while 循环,您就会明白。
  • 查看我在问题中编辑的示例。在原始源代码中,我使用了 while 循环。后来在反编译后我看到while循环被替换为for循环并且代码仍然工作正常。

标签: java compiler-optimization decompiler .class-file


【解决方案1】:

Java 编译器只做最少的优化。

大多数优化仅由 JIT 编译器完成。(因为它包含有关平台和运行时环境的最多信息。)

for 循环和 while 循环在字节码中使用相同的模式。这并不奇怪,因为所有的 while 循环都可以很容易地重写为一个相同的 for 循环

http://blog.jamesdbloom.com/JavaCodeToByteCode_PartOne.html

由于在字节码版本中,for循环和while循环看起来一样,反编译器可能会反编译成while循环。

【讨论】:

    【解决方案2】:

    Java 编译器实际上不会对生成的代码进行优化(尽管有一些优化,比如评估常量表达式和内联某些静态最终字段)。

    但问题是,您实际上不能期望得到您开始使用的确切代码。 Java 不是脚本语言,代码实际上被编译成字节码——原始的文本源代码不存储在类文件的任何地方。

    您发布的输出与您预期的一样好。你总是会丢失诸如空格、cmets 和格式化之类的东西,因为它们根本没有存储在类文件中。对于最底层的循环,显然有多种方式可以编写相同的代码,而反编译器只是选择了不同的方式来表达相同的代码。由于无法判断最初使用了所有可能的等效代码样式中的哪一个,因此反编译器只是猜测。

    这可能只是启发式的结果,人们更常编写 for 循环而不是像您最初使用的 while 循环。在这种特殊情况下,实际上没有人会将 print 语句放在这样的 for 循环表达式中,但启发式方法并不完美。

    【讨论】:

    • 嗯,你解释的没错,但仍然不满意。你能稍微解释一下生成的for循环吗?
    • @choxx 如果您仔细查看 for 循环,您会注意到它与您的 while 循环执行相同的操作。 for 循环中的语句通常用于增加一个变量,但并没有说它们必须这样做。
    • 是的,我明白了。我只是想知道反编译器工具是如何开发这种内部逻辑的,并且代码转换是以这种方式发生的。真是太棒了!!
    • @choxx 您必须询问 JAD(DJ 使用的引擎)的开发人员。由于 JAD 太老了,这可能很困难。
    猜你喜欢
    • 2014-03-31
    • 2018-09-08
    • 2016-11-19
    • 2013-09-01
    • 2014-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-19
    相关资源
    最近更新 更多