世界是沙粒还是宇宙_看到一个沙粒世界:再一次你好世界
世界是沙粒還是宇宙
“看到一個(gè)沙粒中的世界”,我們很可能會(huì)看到最簡(jiǎn)單的“ Hello World”中的世界,所以我們開始吧,再一次向世界問好。
我猜所有的Java課程,教程都是從這個(gè)著名的Hello World程序開始的,這是我可以在沒有IDE的幫助下編寫的非常罕見的程序之一:)
public class HelloWorld {public static void main(String[] args) {System.out.println("Hello World");} }1.您知道這些javac選項(xiàng)嗎?
編寫完第一個(gè)程序后,您將首先執(zhí)行以下命令進(jìn)行編譯,否則將無法運(yùn)行。
javac HelloWorld.java您可能會(huì)發(fā)現(xiàn)不必將文件命名為“ HelloWorld.java”,“ Hello.java”也可以使用。 public class HelloWorld也可以降級(jí)為class HelloWorld 。
如果您好奇地按下javac --help ,將會(huì)看到很多有關(guān)Java編譯器的選項(xiàng),例如,我們要打印中文版“ Hello World”,并希望它完全適用于JDK8語言級(jí)別,元數(shù)據(jù)為包含的參數(shù)名稱,它看起來像這樣:
javac -encoding UTF-8 -source 8 -target 8 -parameters Hello.java您已經(jīng)安裝了JDK11,但是使用上面的命令僅使用1.8功能發(fā)布了類文件。 如果您編寫了一些僅可從JDK9獲得的內(nèi)容,則會(huì)發(fā)現(xiàn)它無法按預(yù)期進(jìn)行編譯。
2.類文件的基礎(chǔ)
關(guān)于Java虛擬機(jī)規(guī)范中的類文件格式的整章內(nèi)容,您是否需要對(duì)其進(jìn)行一些探討?
您會(huì)看到字節(jié)碼(與JDK11一起編譯)以一個(gè)神奇的,神秘的“ cafe babe”開頭,然后以55開頭,很多東西會(huì)傷害您的大腦。 其中,“ cafe babe”是魔術(shù),指向次要版本的55點(diǎn)映射到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 }您會(huì)發(fā)現(xiàn)這里的指令與源代碼有些相似,帶有源代碼的行號(hào)和指令號(hào)的映射,您可能想知道,我可以從這些東西中恢復(fù)源代碼嗎?
3.反編譯器
是的你可以。 反編譯器有很多,但是其中一些反編譯器已經(jīng)過時(shí),例如JD-GUI ,JAD等,它們?cè)谑褂米钚翵DK編譯的類文件上不能很好地工作。 您仍然可以使用它們,但是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"); } }您可能已經(jīng)發(fā)現(xiàn)源代碼和反編譯的代碼(添加了構(gòu)造方法)略有不同,實(shí)際上,您可能會(huì)驚訝地發(fā)現(xiàn)有時(shí)似乎對(duì)源代碼進(jìn)行了修改,從而使您感到驚訝。 但是,其中許多是通過JVM進(jìn)行的優(yōu)化,通常可以提高性能,比較它們之間的差異實(shí)際上很有趣,并且可以為您提供很多見識(shí)。
4.如何再次初始化具有空值的最終變量?
System.out.println("Hello World") ,System是一個(gè)類,out是具有final修飾符的靜態(tài)屬性之一:
public final static PrintStream out = null;然后問題來了,為什么hack System.out.println("Hello World")不會(huì)拋出著名的NullPointerException ,根據(jù)語言規(guī)范,似乎最終的靜態(tài)變量out不可能分配給有效值再次吧?
是的,在大多數(shù)情況下,如果您不使用骯臟的反射技巧并且不引入native好友,那是正確的。
如果您只是想玩轉(zhuǎn),可以這樣做:
Field f = clazz.getDeclaredField("out"); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);但是,這對(duì)于System無效,實(shí)際的秘密隱藏在System.java以下代碼行中:
private static native void registerNatives(); static {registerNatives(); }按照方法上方寫的注釋,“ VM將調(diào)用initializeSystemClass方法來完成此類的初始化”,轉(zhuǎn)到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種本地方法設(shè)置in與out :
private static native void setIn0(InputStream in); private static native void setOut0(PrintStream out); private static native void setErr0(PrintStream err);因此,您現(xiàn)在可能會(huì)問,JVM會(huì)在OS級(jí)別上做這些事情并“繞過” final限制,您可能會(huì)問,JVM將適應(yīng)的OS級(jí)別代碼在哪里被破解?
因此這里是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); }在這里,您可以在注釋中找到后門, “它們是本機(jī)實(shí)現(xiàn)的,因?yàn)樗鼈冞`反了語言的語義(即,設(shè)置最終變量)” 。
然后,您會(huì)發(fā)現(xiàn)這是一條漫長(zhǎng)的道路。 旅程將永遠(yuǎn)不會(huì)停止。
結(jié)束:停一會(huì)兒
“用沙粒看世界
還有野花中的天堂
將Infinity握在手中 一小時(shí)的永恒”
如果最簡(jiǎn)單的HelloWorld只是一片沙粒,那么里面肯定有一個(gè)世界,也許您曾多次對(duì)它說“ Hello”,但這并不意味著您已經(jīng)探索了一點(diǎn)世界,也許現(xiàn)在時(shí)間和探索世界,雖然沙子會(huì)弄臟您的手,但花朵卻不會(huì)。
翻譯自: https://www.javacodegeeks.com/2019/02/world-grain-sand-world.html
世界是沙粒還是宇宙
總結(jié)
以上是生活随笔為你收集整理的世界是沙粒还是宇宙_看到一个沙粒世界:再一次你好世界的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 企业邮箱怎么设置foxmail(企业邮箱
- 下一篇: stripe pay_J2Pay –完整