重学java(一)

这是每一个Java程序员都知道的程序。 我想看看我们能从这个简单的程序。 一个简单的开始可能导致学习更复杂的东西变得更加容易。 这将是伟大的如果这篇文章读起来很有趣,不仅为Java程序员入门级。 请留下你的评论,如果hello world意味着更多的给你。

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程序是由类,每一个方法和字段在一个类。 这是由于其面向对象的特性。 面向对象的编程语言有很多的优点,如模块化、可扩展性等。

2。 然后“主要”方法——程序入口

“主要”方法是程序入口,它是静态的。 “静态”意味着该方法类的一部分,不是对象的一部分。

那是为什么? 我们为什么不把一个非静态方法是程序入口?

如果一个方法不是静态的,那么需要首先创建一个对象使用方法。 因为必须调用一个对象的方法。 对于一个入口,这是不现实的。 因此,程序入口方法是静态的。

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

3。 字节码的HelloWorld

执行程序,Java文件第一次编译为Java字节代码存储在。 类文件。

字节代码看起来像什么?

字节代码本身是不可读的。 如果我们使用十六进制编辑器,它看起来像下面的:

java-bytecode-example

我们可以看到很多操作码(如。 CA,4 c等)在上面的字节码中,他们每个人都有一个相应的助记码(如。 在下面的例子中,aload_0)。 操作码是不可读的,但我们可以使用javap的记忆形式。 类文件。

“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

}


上面的代码包含两个方法:一个是默认的构造函数,编译器推断的;另一种是主要方法。

下面每个方法,有一系列的指令,如aload_0 invokespecial # 1等。什么每条指令可以抬起头来Java字节码指令列表。 例如,aload_0加载一个引用从局部变量0压入堆栈,getstatic获取类的一个静态字段值。 注意到“2”getstatic指令指向运行时常量池。 常量池的JVM运行时数据区。 这让我们看看常量池,这可以通过使用“javap - verbose”命令。

此外,每条指令开始于一个数字,如0、1,4,等等。。 类文件,每个方法都有一个对应的字节数组。 这些数字对应的索引数组,其中每个操作码及其参数存储。 每个操作码1个字节长,说明可以有0或多个参数。 这就是为什么这些数字并不连续。

现在,我们可以使用“javap - verbose”采取进一步的类。

javap -classpath。 - verbose 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

}


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规范:运行时常量池是一个函数的符号表类似传统的编程语言,尽管它包含了一个广泛的数据比一个典型的符号表。

“# 1”“invokespecial # 1”指令指向常量池中的# 1常数。 不变的是“方法# 6,# 15;”。 的号码,我们就可以按递归方式来得到最终的常数。

LineNumberTable提供调试器显示这行信息对应于Java源代码的字节码指令。 例如,Java源代码中的第9行对应于0字节代码的主要方法和第10行对应于8字节码。

如果你想知道更多关于字节码,您可以创建和编译一个更复杂的类来看看。 HelloWorld确实是这样做的出发点。

4。 它在JVM中执行的是怎样的?

现在的问题是如何JVM加载类和调用的主要方法?

JVM执行的主要方法之前,需要加载,链接,初始化类。 为一个类/接口带来二进制形式加载到JVM。 链接包含二进制数据类型到JVM运行时的状态。 连接分为3步:验证,准备,和可选的决议。 验证保证了类/接口结构是正确的。 类/接口所需的准备包括分配内存。 分辨率解析符号引用。 最后在初始化步骤中,类变量给出适当的初始值。

JVM-loading-linking-initialization

这是通过Java类加载器加载工作。 当JVM启动时,三个类加载器使用:

  1. 引导类加载器加载:位于核心Java库/ jre / lib目录中。 它是核心JVM的一部分,是用原生代码写的。
  2. 扩展类装入器:加载扩展目录中的代码(例如,/ jar / lib / ext)。
  3. 系统类装入器:加载代码在类路径中找到。

因此HelloWorld类由系统类加载。 当执行的主要方法,它将触发加载、链接和其他类的初始化如果他们存在。

最后,main()框架被推到JVM堆栈,并相应地设置程序计数器(PC)。 电脑然后指出推动println()JVM堆栈帧。 main()方法完成后,它将从堆栈中弹出和执行完成

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

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值