Java 클래스 파일 생성이 결정적입니까?
사용하는 경우 동일한 JDK (즉, 같은 javac
실행 파일을), 생성 된 클래스 파일이 항상 동일하다? 운영 체제 또는 하드웨어 에 따라 차이가있을 수 있습니까? JDK 버전을 제외하고 다른 요인으로 인해 차이가 발생할 수 있습니까? 차이점을 피하기위한 컴파일러 옵션이 있습니까? 이론적으로 만 차이가 있습니까? 아니면 Oracle이 javac
실제로 동일한 입력 및 컴파일러 옵션에 대해 다른 클래스 파일을 생성합니까?
업데이트 1 클래스 파일이 다양한 플랫폼에서 실행될 수 있는지 여부가 아니라 생성 , 즉 컴파일러 출력에 관심이 있습니다.
업데이트 2 'Same JDK'는 동일한 javac
실행 파일을 의미합니다 .
업데이트 3 Oracle 컴파일러의 이론적 차이와 실제 차이의 구별.
[편집, 의역 된 질문 추가]
"다른 플랫폼에서 실행할 때 동일한 javac 실행 파일이 다른 바이트 코드를 생성하는 상황은 무엇입니까?"
다음과 같이합시다.
동일한 .class
파일이 주어지면 동일한 파일을 두 번 생성하지 않는 완전히 일치하는 Java 컴파일러를 쉽게 생성 할 수 있습니다 .java
.
모든 종류의 바이트 코드 구성을 조정하거나 단순히 내 메서드에 불필요한 속성을 추가하여이를 수행 할 수 있습니다 (허용됨).
사양 이 컴파일러가 바이트 단위 동일한 클래스 파일을 생성 하도록 요구 하지 않는다는 점을 감안할 때 이러한 결과 에 의존 하는 것을 피할 것 입니다.
그러나 몇 번 확인한 결과 동일한 스위치 (및 동일한 라이브러리!)를 사용하여 동일한 컴파일러로 동일한 소스 파일을 컴파일하면 동일한 파일 이 생성되었습니다 .class
.
업데이트 : 최근 에 Java 7에서 on 구현에 대한 흥미로운 블로그 게시물을switch
String
우연히 발견했습니다 . 이 블로그 게시물에는 여기에서 인용 할 관련 부분이 있습니다 (강조 표시).
컴파일러의 출력은 예측 가능하고 반복하기 위해, 이러한 데이터 구조에 사용 된지도와 세트는
LinkedHashMap
s와LinkedHashSet
단지보다는이야HashMaps
하고HashSets
. 생성 된 코드의 기능 정확성의 측면에서 , 주어진 컴파일시에 사용HashMap
하고HashSet
잘 될 것입니다 ; 반복 순서는 중요하지 않습니다. 그러나 시스템 클래스의 구현 세부 사항에 따라의 출력이 달라지지 않는 것이 유익하다는 것을 알게되었습니다javac
.
이것은 문제를 매우 명확하게 보여줍니다. 컴파일러는 사양과 일치하는 한 결정적인 방식으로 작동 할 필요 가 없습니다 . 그러나 컴파일러 개발자는 일반적으로 시도 하는 것이 좋습니다 (너무 비싸지 않은 경우).
컴파일러가 각 플랫폼에서 동일한 바이트 코드를 생성 할 의무는 없습니다. javac
특정 답변을 얻으려면 다른 공급 업체의 유틸리티에 문의해야합니다 .
파일 순서를 지정하여 이에 대한 실제 예를 보여 드리겠습니다.
2 개의 jar 파일이 있다고 가정 해 봅시다 : my1.jar
및 My2.jar
. 그들은 lib
나란히 디렉토리에 저장됩니다. (이 때문에 컴파일러는 알파벳 순서로 읽고 lib
)하지만, 순서는 my1.jar
, My2.jar
파일 시스템의 경우를 구분하지 않습니다 때, 그리고 My2.jar
, my1.jar
그것은 대소 문자를 구분합니다.
는 my1.jar
클래스를 가지고 A.class
하는 방법으로
public class A {
public static void a(String s) {}
}
는 My2.jar
동일한 갖고 A.class
있지만, 다른 방법 서명 (수락 Object
)
public class A {
public static void a(Object o) {}
}
전화가 오면
String s = "x";
A.a(s);
다른 경우에 다른 서명으로 메서드 호출을 컴파일합니다. 따라서 파일 시스템 대소 문자 구분에 따라 결과적으로 다른 클래스를 얻게됩니다.
짧은 답변- 아니요
긴 답변
그들은 bytecode
다른 플랫폼에 대해 동일 할 필요는 없다. 바이트 코드를 정확히 실행하는 방법을 아는 것은 JRE (Java Runtime Environment)입니다.
당신이 통과되면 자바 VM 사양 이이 바이트 코드가 다른 플랫폼에서 동일 함을 사실 필요가 없다 것을 알게 될 것입니다.
를 통과 클래스 파일 형식 , 그것은 클래스 파일의 구조 등을 보여줍니다
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
부 버전 및 주 버전 확인
부 버전, 주 버전
The values of the minor_version and major_version items are the minor and major version numbers of this class file.Together, a major and a minor version number determine the version of the class file format. If a class file has major version number M and minor version number m, we denote the version of its class file format as M.m. Thus, class file format versions may be ordered lexicographically, for example, 1.5 < 2.0 < 2.1. A Java virtual machine implementation can support a class file format of version v if and only if v lies in some contiguous range Mi.0 v Mj.m. Only Sun can specify what range of versions a Java virtual machine implementation conforming to a certain release level of the Java platform may support.1
Reading more through the footnotes
1 The Java virtual machine implementation of Sun's JDK release 1.0.2 supports class file format versions 45.0 through 45.3 inclusive. Sun's JDK releases 1.1.X can support class file formats of versions in the range 45.0 through 45.65535 inclusive. Implementations of version 1.2 of the Java 2 platform can support class file formats of versions in the range 45.0 through 46.0 inclusive.
So, investigating all this shows that the class files generated on different platforms need not be identical.
Firstly, there's absolutely no such guarantee in the spec. A conforming compiler could stamp the time of compilation into the generated class file as an additional (custom) attribute, and the class file would still be correct. It would however produce a byte-level different file on every single build, and trivially so.
Secondly, even without such nasty tricks about, there's no reason to expect a compiler to do exactly the same thing twice in a row unless both its configuration and its input are identical in the two cases. The spec does describe the source filename as one of the standard attributes, and adding blank lines to the source file could well change the line number table.
Thirdly, I've never encountered any difference in build due to the host platform (other than that which was attributable to differences in what was on the classpath). The code which would vary based on platform (i.e., native code libraries) isn't part of the class file, and the actual generation of native code from the bytecode happens after the class is loaded.
Fourthly (and most importantly) it reeks of a bad process smell (like a code smell, but for how you act on the code) to want to know this. Version the source if possible, not the build, and if you do need to version the build, version at the whole-component level and not on individual class files. For preference, use a CI server (such as Jenkins) to manage the process of turning source into runnable code.
I believe that, if you use the same JDK, the generated byte code will always be the same, without relation with the harware and OS used. The byte code production is done by the java compiler, that uses a deterministic algorithm to "transform" the source code into byte code. So, the output will always be the same. In these conditions, only a update on the source code will affect the output.
Overall, I'd have to say there is no guarantee that the same source will produce the same bytecode when compiled by the same compiler but on a different platform.
I'd look into scenarios involving different languages (code-pages), for example Windows with Japanese language support. Think multi-byte characters; unless the compiler always assumes it needs to support all languages it might optimize for 8-bit ASCII.
There is a section on binary compatibility in the Java Language Specification.
Within the framework of Release-to-Release Binary Compatibility in SOM (Forman, Conner, Danforth, and Raper, Proceedings of OOPSLA '95), Java programming language binaries are binary compatible under all relevant transformations that the authors identify (with some caveats with respect to the addition of instance variables). Using their scheme, here is a list of some important binary compatible changes that the Java programming language supports:
•Reimplementing existing methods, constructors, and initializers to improve performance.
•Changing methods or constructors to return values on inputs for which they previously either threw exceptions that normally should not occur or failed by going into an infinite loop or causing a deadlock.
•Adding new fields, methods, or constructors to an existing class or interface.
•Deleting private fields, methods, or constructors of a class.
•When an entire package is updated, deleting default (package-only) access fields, methods, or constructors of classes and interfaces in the package.
•Reordering the fields, methods, or constructors in an existing type declaration.
•Moving a method upward in the class hierarchy.
•Reordering the list of direct superinterfaces of a class or interface.
•Inserting new class or interface types in the type hierarchy.
This chapter specifies minimum standards for binary compatibility guaranteed by all implementations. The Java programming language guarantees compatibility when binaries of classes and interfaces are mixed that are not known to be from compatible sources, but whose sources have been modified in the compatible ways described here. Note that we are discussing compatibility between releases of an application. A discussion of compatibility among releases of the Java SE platform is beyond the scope of this chapter.
Java allows you write/compile code on one platform and run on different platform.
AFAIK; this will be possible only when class file generated on different platform is same or technically same i.e. identical.
Edit
What i mean by technically same comment is that. They don't need to be exactly same if you compare byte by byte.
So as per specification .class file of a class on different platforms don't need to match byte-by-byte.
For the question:
"What are the circumstances where the same javac executable,when run on a different platform, will produce different bytecode?"
The Cross-Compilation example shows how we can use the Javac option:-target version
This flag generates class files which are compatible with the Java version we specify while invoking this command. Hence the class files will differ depending on the attributes we supply during the compaliation using this option.
Most probably, the answer is "yes", but to have precise answer, one does need to search for some keys or guid generation during compiling.
I can't remember the situation where this occurs. For example to have ID for serializing purposes it is hardcoded, i.e. generated by programmer or IDE.
P.S. Also JNI can matter.
P.P.S. I found that javac
is itself written in java. This means that it is identical on different platforms. Hence it would not generate different code without a reason. So, it can do this only with native calls.
There are two questions.
Can there be a difference depending on the operating system or hardware?
This is a theoretical question, and the answer is clearly, yes, there can be. As others have said, the specification does not require the compiler to produce byte-for-byte identical class files.
Even if every compiler currently in existence produced the same byte code in all circumstances (different hardware, etc.), the answer tomorrow might be different. If you never plan to update javac or your operating system, you could test that version's behavior in your particular circumstances, but the results might be different if you go from, for example, Java 7 Update 11 to Java 7 Update 15.
What are the circumstances where the same javac executable, when run on a different platform, will produce different bytecode?
That's unknowable.
I don't know if configuration management is your reason for asking the question, but it's an understandable reason to care. Comparing byte codes is a legitimate IT control, but only to determine if the class files changed, not top determine if the source files did.
I would put it another way.
First, I think the question is not about being deterministic:
Of course it is deterministic: randomness is hard to achieve in computer science, and there is no reason a compiler would introduce it here for any reason.
Second, if you reformulate it by "how similar are bytecode files for a same sourcecode file ?", then No, you can't rely on the fact that they will be similar.
A good way of making sure of this, is by leaving the .class (or .pyc in my case) in your git stage. You'll realize that among different computers in your team, git notices changes between .pyc files, when no changes were brought to the .py file (and .pyc recompiled anyway).
At least that's what I observed. So put *.pyc and *.class in your .gitignore !
참고URL : https://stackoverflow.com/questions/14984984/is-the-creation-of-java-class-files-deterministic
'IT story' 카테고리의 다른 글
Windows에서 GNU Make를 사용하는 방법? (0) | 2020.08.30 |
---|---|
자바 스크립트 개체의 속성을 삭제 / 설정 해제하는 방법은 무엇입니까? (0) | 2020.08.30 |
using 문 내에서 예외가 throw되면 Dispose가 계속 호출됩니까? (0) | 2020.08.30 |
InnoDB로 전체 텍스트 검색 (0) | 2020.08.30 |
SQLite-다른 데이터베이스의 테이블을 어떻게 조인합니까? (0) | 2020.08.30 |