看到一个沙粒世界:再一次你好世界
“看到一個沙粒中的世界”,我們很可能會看到最簡單的“ Hello World”中的世界,所以我們開始吧,再一次向世界問好。
我猜所有的Java課程,教程都是從這個著名的Hello World程序開始的,這是我可以在沒有IDE的幫助下編寫的非常罕見的程序之一:)
public class HelloWorld {public static void main(String[] args) {System.out.println("Hello World");} }1.您知道這些javac選項嗎?
編寫第一個程序后,您將首先執行以下命令進行編譯,否則將無法運行。
javac HelloWorld.java您可能會發現不必將文件命名為“ HelloWorld.java”,“ Hello.java”也可以使用。 public class HelloWorld也可以降級為class HelloWorld 。
如果您好奇地按下javac --help ,將會看到很多有關Java編譯器的選項,例如,我們要打印中文版“ Hello World”,并希望它完全適用于JDK8語言級別,元數據為包含的參數名稱,它看起來像這樣:
javac -encoding UTF-8 -source 8 -target 8 -parameters Hello.java您已經安裝了JDK11,但是使用上面的命令僅使用1.8功能發布了類文件。 如果您編寫了一些僅可從JDK9獲得的內容,則會發現它無法按預期進行編譯。
2.類文件的基礎
關于Java虛擬機規范中的類文件格式的整章內容,您是否需要對其進行一些探討?
您會看到字節碼(與JDK11一起編譯)以一個神奇的,神秘的“ cafe babe”開頭,隨后為55,很多東西會傷害您的大腦。 其中,“ cafe babe”是魔力,指向次要版本的55分,映射到JDK11。 與讀取超贊的類文件格式相比,您還可以使用javap檢索該類文件的信息:
# You would use javap -h to see how many options you have javap -p -l -c -s -constants HelloWorld您將獲得如下內容:
class HelloWorld {HelloWorld(); descriptor: ()V Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V Code: 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello World 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: return LineNumberTable: line 4: 0 line 5: 8 }您會發現這里的指令與源代碼有些相似,帶有源代碼的行號和指令號的映射,您可能想知道,我可以從這些東西中恢復源代碼嗎?
3.反編譯器
是的你可以。 反編譯器有很多,但是其中一些反編譯器已經過時,例如JD-GUI ,JAD等,它們在使用最新JDK編譯的類文件上不能很好地工作。 您仍然可以使用它們,但CFR更合適。
# java -jar cfr-0.139.jar HelloWorld.class /* * Decompiled with CFR 0.139.*/ import java.io.PrintStream; class HelloWorld { HelloWorld() { } public static void main(String[] arrstring) {System.out.println("Hello World"); } }您可能已經發現源代碼和反編譯的代碼(添加了構造方法)略有不同,實際上,您可能會驚訝地發現有時似乎對源代碼進行了修改,從而使您感到驚訝。 但是,其中許多是通過JVM進行的優化,通常可以提高性能,比較它們之間的差異實際上很有趣,并且可以為您提供很多見識。
4.如何再次初始化具有空值的最終變量?
System.out.println("Hello World") ,System是一個類,out是其最終屬性的靜態屬性之一:
public final static PrintStream out = null;然后問題來了,為什么hack System.out.println("Hello World")不會拋出著名的NullPointerException ,根據語言規范,似乎最終的靜態變量out不可能分配給有效值再次吧?
是的,在大多數情況下,如果您不使用骯臟的反射技巧并且不引入native好友,那是對的。
如果您只是想玩轉,可以這樣做:
Field f = clazz.getDeclaredField("out"); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);但是,這對于System無效,實際的秘密隱藏在System.java以下代碼行中:
private static native void registerNatives(); static {registerNatives(); }按照方法上方寫的注釋,“ VM將調用initializeSystemClass方法來完成此類的初始化”,轉到initializeSystemClass方法,您將看到以下行:
FileInputStream fdIn = new FileInputStream(FileDescriptor.in); FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out); FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err); setIn0(new BufferedInputStream(fdIn)); setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding"))); setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding")));而且你還可以看到這3種本地方法設置in與out :
private static native void setIn0(InputStream in); private static native void setOut0(PrintStream out); private static native void setErr0(PrintStream err);因此,現在您知道JVM在OS級別上做了這些工作并“繞過”了final限制,您可能會問,JVM將適應的OS級別代碼在哪里被破解?
所以這里是System.c (JDK11版本) 。
JNIEXPORT void JNICALL Java_java_lang_System_registerNatives(JNIEnv *env, jclass cls) {(*env)->RegisterNatives(env, cls,methods, sizeof(methods)/sizeof(methods[0])); } /** The following three functions implement setter methods for* java.lang.System.{in, out, err}. They are natively implemented* because they violate the semantics of the language (i.e. set final* variable).*/ JNIEXPORT void JNICALL Java_java_lang_System_setIn0(JNIEnv *env, jclass cla, jobject stream) {jfieldID fid =(*env)->GetStaticFieldID(env,cla,"in","Ljava/io/InputStream;");if (fid == 0)return;(*env)->SetStaticObjectField(env,cla,fid,stream); }在這里,您可以在注釋中找到后門, “它們是本機實現的,因為它們違反了語言的語義(即,設置最終變量)” 。
然后,您會發現這是一條漫長的道路。 旅程將永遠不會停止。
結束:停一會兒
“用沙粒看世界
還有野花中的天堂
將Infinity握在手中 一小時的永恒”
如果最簡單的HelloWorld只是一片沙粒,那么里面肯定有一個世界,也許您對它說過很多次“ Hello”,但這并不意味著您已經探索了一點世界,也許現在時間和探索世界,雖然沙子會使您的手變臟,但花朵卻不會。
翻譯自: https://www.javacodegeeks.com/2019/02/world-grain-sand-world.html
總結
以上是生活随笔為你收集整理的看到一个沙粒世界:再一次你好世界的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ddos是病毒吗(ddos病毒的来源)
- 下一篇: moreunit_MoreUnit与Mo