世界是沙粒还是宇宙

“看到一个沙粒中的世界”,我们很可能会看到最简单的“ 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是具有final修饰符的静态属性之一:

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种本地方法设置inout

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

世界是沙粒还是宇宙

世界是沙粒还是宇宙_看到一个沙粒世界:再一次你好世界相关推荐

  1. 看到一个沙粒世界:再一次你好世界

    "看到一个沙粒中的世界",我们很可能会看到最简单的" Hello World"中的世界,所以我们开始吧,再一次向世界问好. 我猜所有的Java课程,教程都是从这 ...

  2. 我的世界光影mod怎么用_用“戏剧化”光影艺术 唤醒千年沉睡世界!

    当历史遇上科技,会产生怎样的化学反应? 当博物馆跳出传统展览模式,又带给游客怎样的惊喜? 古老的历史经过时间长河沉淀,当年繁华已被深深埋没, 当艺术家们通过科技手段,用光影点亮沉睡的历史, 那些被风化 ...

  3. 世界人口钟实时数据_全球人口将达80亿 2019年世界人口总数统计数据

    近日,德国全球人口基金会发布统计数据:至2019年底,全球人口总数将达77.5亿,至2023年全球人口将达80亿.联合国人口预期报告估算称,2050年世界一半人口将聚集在印度及非洲等国,2027年印度 ...

  4. Boost.Signals2 的初学者你好世界示例

    Boost.Signals2 的初学者你好世界示例 实现功能 C++实现代码 实现功能 Boost.Signals2 的初学者你好世界示例 C++实现代码 #include <iostream& ...

  5. 我的世界java致命错误_《我的世界》六个“致命错误”,最后一个“不作死就不会死”...

    原标题:<我的世界>六个"致命错误",最后一个"不作死就不会死" 俗话说:"自古整合坑新人",我输入自古整合这四个字,第二个词语 ...

  6. 我的世界java版生存三叉戟_我的世界:三叉戟太难获得?教你做一个溺尸塔,三叉戟随便爆!...

    那么在1.13海洋版本更新中,推出了一种全新的武器--三叉戟.极高的伤害,远近战兼备,加上花里胡哨的附魔,让很多玩家对三叉戟垂诞不已.但是,三叉戟获取的难度是较高的,目前生存中获得三叉戟的唯一方法就是 ...

  7. 我的世界java村庄刷僵尸_我的世界:最安全村庄诞生!仅因一个条件,村民再也不担心僵尸...

    在MC的世界中,村民一直都是一个弱小的存在,基本上处于一种任人宰割的状态.不过村民虽然弱小,但是却十分富有,基本上开局能找到一个村庄就可以安稳地度过前期的生存.假如你是村民,富有但弱小,怎么样的居住地 ...

  8. 我们的宇宙可能是一个3.9999…

    原文地址:我们的宇宙可能是一个3.9999-维的球体作者: 康斯坦丁 佛陀曾说:一花一世界,一叶一如来.在佛陀看来,一颗沙粒即可见三千大世界.难道远古的圣人们真的已经洞见了这个宇宙的真相? 1919年 ...

  9. 宇宙人工智能计算机程序,由人工智能推理出:整个宇宙会变成一个玄计算机,宇宙是虚拟的...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 人工智能 现在的计算机芯片是纳米级的,可简称纳米计算机,未来可能出现量子计算机.玄(量子由玄组成)计算机.现在看生物实质上也是纳米计算机,具有计算机的全部 ...

最新文章

  1. 第一节 并发基础概念及实现、进程、线程基本概念
  2. 【c语言】蓝桥杯入门训练 圆的面积
  3. NXT(未来币)(阿朵)节点钱包
  4. 标志寄存器:CF、PF、AF、ZF、SF、TF、DF、OF
  5. 贝叶斯分类器与贝叶斯网络
  6. 为什么要远程连接Linux
  7. swagger OAuth认证
  8. 【量化】CSFB阿尔法多因子模型研究
  9. 各种开源项目/库/工具介绍
  10. js中的cookie的读写操作示例详解
  11. 最大公约数c语言,C语言求最大公约数代码及解析
  12. Vue 实现页面一键截屏功能
  13. Java学习笔记:Word中创建图表如此简单
  14. 吴恩达-目标检测讲解笔记
  15. 【目标跟踪 SOT】SiamFC -用于对象跟踪的全卷积孪生网络
  16. kettle多数据合并
  17. 没有干货的LTSC浅度体验
  18. Calendar类、System类、StringBuilder类、包装类
  19. 绿叶制药血脂康片高含量规格即将在华开展临床试验
  20. 【linux】nfs挂载错误wrong fs type, bad option, bad superblock

热门文章

  1. 叁仟柒佰万(mex+线段树+dp+前缀和优化+双指针+桶)
  2. CF587F-Duff is Mad【AC自动机,根号分治】
  3. 【做题记录】图论杂题
  4. 2021牛客暑期多校训练营2 G.League of Legends(转化+单调队列)
  5. 【结论题(QAQ)】SSL新年欢乐赛暨BPM退役赛 A 送分题(luogu U102372)
  6. 【Floyed】工厂的烦恼(ssl 1762)
  7. codeforces gym-101741 Elevator 动态规划、单调队列
  8. 由「Metaspace容量不足触发CMS GC」从而引发的思考
  9. JavaFX图表(五)之气泡图
  10. js的字符串和变量拼接