当前位置:首页 > CN2资讯 > 正文内容

我的世界java文件夹

2天前CN2资讯


这是所有Java程序员知道的程序,它很简单,但是这样一个简单的开始可以带领我们更深的理解更多复杂的 概念。在这篇文章中,将探索我们可以从这个简单的程序中学到什么。



HelloWorld.java

 

public class HelloWorld { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("Hello World"); } }



 

1、为什么所有东西都从类开始?

Java程序被一个类构成,所有方法和字段都在一个类中。这是由于Java的面向对象的特征:一切对象都是一个类的实例。面向对象的编程语言对于面向函数式的编程语言而言有许多优点,例如更好的模块化,可扩展性等等。

 

2、为什么总是有一个“Main”方法?

Main方法是一个程序的入口且是静态的,静态意味着这个方法是类的一部分,而不是对象的一部分。

为什么这样做呢,我们为什么不用一个非静态的方法作为一个程序的入口?

如果一个方法是非静态的,我们要实用这个方法时必须首先创建一个对象,因为方法必须在一个对象上被调用。用于程序的入口,显然是不现实的。如果没有鸡,我们就得不到蛋,因此,程序入口方法应该是静态的。

参数“String[] args”表明可以传送一个字符串数组帮助程序的初始化。

 

3、HelloWorld的字节码

执行一个程序时,Java文件首先被编译成Java字节码文件存储在.class文件中,字节码文件时什么样的?字节码文件本身是不可读的,如果我们使用十六进制编辑器,它们看起来是这样的:

我们可以在上面的字节码中看到许多操作码(例如CA,4C等等),每个操作吗都有一个对应的助记码(例如下面例子中的aload_0),操作码是不可读的,但是我们可以使用javap去从.class文件中看到助记码。

“javap -c” 打印出每个类中方法的反汇编代码。反汇编代码意味着指令由java字节码组成。

javap -classpath . -c HelloWorld Compiled from "HelloWorld.java" public class HelloWorld extends java.lang.Object{ public HelloWorld(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); 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;)V 8: return }




上面的代码包含两个方法:一个是默认构造函数,它由编译器自动生成,另一个是Main函数。

每个函数下面,都有一段指令,例如aload_0,invokespecial #1等。每条指令可以查找Java字节码指令清单。例如,aload_0把局部变量0的引用压人堆栈,getstatic取得静态获取类的一个静态字段值。注意 在getstatic指令之后的 #2指向运行时的常量池。常量池是JVM中的一个运行时数据池,可以通过“ javap -verbose”产看常量池。

另外,每条指令从一个数字开始,例如0,1,4等。在.class文件中,每个函数有一个相应的字节码数组,这些数字对应存储这些操作码和它们的参数的数组索引。每个操作码是1 byte的长度,指令可以有0个或者多个参数,这就是为什么这些数字不是连续的。

现在让我们使用“ javap -verbose”去更深入的看看类。

javap -classpath . -verbose HelloWorld Compiled from "HelloWorld.java" public class HelloWorld extends java.lang.Object SourceFile: "HelloWorld.java" minor version: 0 major version: 50 Constant pool: const #1 = Method #6.#15; // java/lang/Object."<init>":()V const #2 = Field #16.#17; // java/lang/System.out:Ljava/io/PrintStream; const #3 = String #18; // Hello World const #4 = Method #19.#20; // java/io/PrintStream.println:(Ljava/lang/String;)V const #5 = class #21; // HelloWorld const #6 = class #22; // java/lang/Object const #7 = Asciz <init>; const #8 = Asciz ()V; const #9 = Asciz Code; const #10 = Asciz LineNumberTable; const #11 = Asciz main; const #12 = Asciz ([Ljava/lang/String;)V; const #13 = Asciz SourceFile; const #14 = Asciz HelloWorld.java; const #15 = NameAndType #7:#8;// "<init>":()V const #16 = class #23; // java/lang/System const #17 = NameAndType #24:#25;// out:Ljava/io/PrintStream; const #18 = Asciz Hello World; const #19 = class #26; // java/io/PrintStream const #20 = NameAndType #27:#28;// println:(Ljava/lang/String;)V const #21 = Asciz HelloWorld; const #22 = Asciz java/lang/Object; const #23 = Asciz java/lang/System; const #24 = Asciz out; const #25 = Asciz Ljava/io/PrintStream;; const #26 = Asciz java/io/PrintStream; const #27 = Asciz println; const #28 = Asciz (Ljava/lang/String;)V; { public HelloWorld(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 2: 0 public static void main(java.lang.String[]); Code: Stack=2, Locals=1, Args_size=1 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;)V 8: return LineNumberTable: line 9: 0 line 10: 8 }




 JVM的运行规范中写道:运行常量池是一个类似传统编程语言的函数符号表,尽管它包含了一个比典型符号表更广泛的数据。

在“invokespecial#1”指令中的#1指向常量池中的#1常量。常量是 #6 #15,通过这些数字,我们就可以递归的找到最终的常量。

 LineNumberTable可以给调试器提供信息以表明Java源代码对应于哪一行的字节码指令。例如Java源代码的第九行对应于字节码0,第10行对应于字节码8.

如果你想知道更多关于字节码的信息,你可以创建和编译一个更加复杂的类来看看,HelloWorld只是这方面的开始。

4、如何在JVM中执行?

现在的问题是JVM如何加载类并且调用Main方法?

在Main方法执行之前,JVM需要三步

1)加载  。2)链接。3)初始化这个类。  

1)将一个类或者接口的二进制形式加载到JVM

2)链接包含二进制类型的数据到运行态的JVM,链接包括三个步骤:验证,准备和可选的解决方案。验证是确保类和接口的格式和结构正确;准备包括给类和接口分配所需要的内存;决议解析符号引用。

3)初始化给类变量分配合适的初始值。


 这个工作由Java的类加载器(Classloader)完成,当JVM启动的时候,有三个类加载器被使用:

1、Bootstrap class loader:加位于/jre/lib目录下的Java核心库,这是JVM核心的一部分,是用原生代码编写的。

2、Extensions class loader:加载扩展目录中的代码(例如:/jar/lib/ext)

3、System class loader:加载CLASSPATH中的代码

所以HelloWorld 类被系统的类加载器所加载。当Main方法执行的时候,如果还有其他相关类存在,类加载器将会加载、链接、和初始化它们。

最后。Main() 框架 被压入JVM堆栈,并相应的设置程序计数器(PC)。程序计数器指示将Println()框架压入JVM堆栈。当Main()方法完成后,它将被弹出堆栈,执行结束。

    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/21974.html

    分享给朋友:

    “我的世界java文件夹” 的相关文章

    Windows SSH使用RSA连接:简单步骤实现安全高效登录

    在Windows系统上生成SSH密钥对是一个简单但关键的步骤,尤其是当你需要通过SSH进行安全连接时。使用RSA算法生成密钥对,可以确保你的连接既安全又高效。我们可以通过PowerShell或CMD来完成这一操作。 使用PowerShell或CMD生成RSA密钥对 打开PowerShell或CMD,...

    搬瓦工带防御:如何提升VPS安全性,抵御DDoS攻击

    搬瓦工VPS的基本介绍 搬瓦工(Bandwagon Host)作为一家知名的VPS提供商,以其稳定的网络连接和出色的性能赢得了众多用户的青睐。无论是个人网站搭建、企业应用部署,还是科学上网需求,搬瓦工VPS都能提供灵活且高效的解决方案。它的价格相对亲民,同时支持多种操作系统和自定义配置,满足了不同用...

    DC3 CN2 VPS方案分析:搬瓦工的性价比之选

    在了解搬瓦工的服务时,我发现了DC3 CN2这个机房方案。它位于美国洛杉矶,是搬瓦工(BandwagonHost)推出的一项虚拟专用服务器(VPS)方案。选择这个机房的用户通常是因为它的网络性能和价格平衡。在洛杉矶的QNET(QuadraNet)机房基础上,搬瓦工向QNET买断了部分CN2 GT线路...

    深入解析APT攻击及其主要案例分析

    在网络安全的领域,APT攻击近年来引起了广泛关注。这种高级持续性威胁(APT)通常是由高度专业化的攻击者发起,针对特定目标进行长期、隐蔽的攻击。APT攻击的目标通常是国家级别的机构、企业、科研单位等,它们的攻击方式不仅难以检测,而且往往具有明显的目的性。 回顾APT攻击的历史,我们可以发现其起源与发...

    bbtec:高性能海外VPS的优质选择,适合联通用户的流媒体与在线游戏体验

    bbtec产品介绍 bbtec,这个在中国联通用户中逐渐崭露头角的海外VPS选择,无疑是一条连接世界的优质线路。作为软银线路,它专为追求高性能网络体验的用户设计,尤其适合频繁访问国外网站的朋友。bbtec具备低延迟、大带宽和快速下载速度的显著特点,特别是在流媒体应用的需求日益增长的今天,bbtec显...

    亚马逊CDN CloudFront:提升网站安全性与加载速度的理想选择

    亚马逊CDN概述 亚马逊CloudFront是亚马逊云科技旗下的一项内容分发网络(CDN)服务,它通过全球范围内的多个数据中心高效分发内容。我对这项服务的了解使我意识到,CloudFront不仅仅是一个简单的资源分发工具,它的设计旨在确保内容的流畅、高效、安全传输,尤其在当今对速度与安全性高度重视的...