目录
Java | 如何开始学习Java
.关于Java
设置Java
在Java中设置环境
为Windows设置Java环境的步骤
适用于Linux的步骤
使用Hello World示例开始Java编程
Java命名约定
JVM如何工作 - JVM架构?
类加载器子系统它主要负责三个活动。
Java虚拟机(JVM)堆栈区域
Java中的JVM Shutdown Hook
Java类文件
JDK,JRE和JVM之间的差异
JAVA开发套件
JRE和JDK如何工作?
JRE包括什么?JRE由以下组件组成:
JRE如何运作?要了解JRE的工作原理,让我们考虑保存为Example.java的Java源文件。该文件被编译成一组字节代码,存储在“ .class ”文件中。这里将是“ Example.class ”。下图描述了在编译时完成的操作。
JVM是否创建Main类的对象(具有main()的类)?
Java是最流行和最广泛使用的编程语言和平台之一。平台是一种有助于开发和运行用任何编程语言编写的程序的环境。
Java快速,可靠且安全。从桌面到Web应用程序,从科学超级计算机到游戏控制台,从手机到互联网,Java都可以在每个角落使用。
因此,Java是一种非常成功的语言,它日益受到欢迎。
你可以从这里下载java 。在这里,您将找到不同版本的Java。选择并下载与您的操作系统兼容的一个。
有关设置Java的详细说明,请参阅此文章。
正确设置Java环境后,尝试运行这个简单的程序:
理解基础知识:
学习任何编程语言的基础知识非常重要。这是开始学习新事物的最佳方式。不要有任何焦虑,开始学习语言的概念。熟悉环境,慢慢地你会很快习惯它。以下是一些可以帮助您入门的链接:
// A Java program to print GeeksforGeeks
public class GFG {
public static void main(String args[])
{
System.out.println("wellcome subscribe to geekmoney");
}
}
输出:
wellcome subscribe to geekmoney
如果环境设置正确并且代码写得正确,您将在控制台上看到此输出。那是你的第一个Java程序!
Java是一种通用的计算机编程语言,它是并发的,基于类的,面向对象的等
.Java应用程序通常被编译为可以在任何Java虚拟机(JVM)上运行的字节码,而不管计算机体系结构如何。最新版本是Java 11。
以下是Linux和Windows的环境设置。JVM,JRE和JDK都是平台相关的,因为每个操作系统的配置都不同。但是,Java与平台无关。
在设置环境之前,必须清楚几件事情
在linux中,有几种方法可以安装java。但是我们将参考使用终端安装java的最简单方法。对于linux,我们将安装OpenJDK。OpenJDK是Java编程语言的免费开源实现。
sudo apt-get install openjdk-8-jdk
export JAVA_HOME = / usr / lib / jvm / java-8-openjdk
export PATH = $ PATH:/ usr / lib / jvm / java-8-openjdk / bin
热门Java编辑/ IDE:
Java编程的过程可以分三步简化:
下面给出的程序是Java打印“Hello World”的最简单程序。让我们一步一步地尝试理解每一段代码。
/* This is a simple Java program.
FileName : "HelloWorld.java". */
class HelloWorld
{
// Your program begins with a call to main().
// Prints "Hello, World" to the terminal window.
public static void main(String args[])
{
System.out.println("Hello, World");
}
}
输出:
hello world
“Hello World!”程序由三个主要组件组成:HelloWorld类定义,main
方法和源代码注释。以下说明将为您提供对代码的基本了解:
HelloWorld类
HelloWorld是一个标识符,它是类的名称。整个类定义(包括其所有成员)将位于左大括号 { 和右大括号 }之间。
main
签名为的方法:
public static void main(String [] args)
public:这样JVM可以从任何地方执行该方法。
static:主要方法是在没有对象的情况下调用。
修饰符public和static可以按任意顺序编写。
void:main方法不返回任何内容。
main():在JVM中配置的名称。
String []:main方法接受一个参数:
String类型的元素数组。
与C / C ++类似,main方法是应用程序的入口点,随后将调用程序所需的所有其他方法。
System.out.println(“Hello,World”);
该行输出字符串“Hello,World”,然后在屏幕上输出一个新行。输出实际上是由内置的println()方法完成的。System是一个提供对系统访问的预定义类,out是连接到控制台的输出流类型的变量。
/ *这是一个简单的Java程序。
将此文件命名为“HelloWorld.java”。* /
这是一条多行评论。此类注释必须以/ *开头,以* /结尾。对于单行,您可以直接使用//,如在C / C ++中。
重点 :
编译程序:
javac HelloWorld.java
java HelloWorld
这将在终端屏幕上打印“Hello World”。
在Windows中
在Linux中
以下是java编程语言的一些命名约定。在开发java中的软件时必须遵循它们,以便进行良好的维护和代码可读性。Java使用CamelCase作为编写方法,变量,类,包和常量名称的实践。
Java编程中的Camel案例:它由复合词或短语组成,每个单词或缩写以大写字母或带小写字母的第一个单词开头,全部用大写字母表示。
例子:
界面自行车
MountainBike类实现了Bicyle
界面运动
class Football实现运动
例子:
void changeGear(int newValue);
void speedUp(int increment);
void applyBrakes(int decrement);
例子:
// MountainBike类的变量
int speed = 0;
int gear = 1;
例子:
static final int MIN_WIDTH = 4;
//在预定义的Float类中使用的一些常量变量
public static final float POSITIVE_INFINITY = 1.0f / 0.0f;
public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;
public static final float NaN = 0.0f / 0.0f;
例子:
com.sun.eng
com.apple.quicktime.v2
// JDK中的java.lang包
java.lang中
JVM(Java虚拟机)充当运行Java应用程序的运行时引擎。JVM实际上是调用java代码中存在的main方法的。JVM是JRE(Java运行时环境)的一部分。
Java应用程序称为WORA(Write Once Run Anywhere)。这意味着程序员可以在一个系统上开发Java代码,并且可以期望它在任何其他支持Java的系统上运行而无需任何调整。由于JVM,这一切都是可能的。
当我们编译.java文件时,Java编译器会生成.jlass文件中存在的具有相同类名的.class文件(包含字节代码)。当我们运行它时,这个.class文件会进入各个步骤。这些步骤一起描述了整个JVM。
加载:类加载器读取.class文件,生成相应的二进制数据并将其保存在方法区域中。对于每个.class文件,JVM在方法区域中存储以下信息。
加载.class文件后,JVM会创建一个Class类型的对象,以在堆内存中表示此文件。请注意,此对象的类型为java.lang包中预定义的类。程序员可以使用这个Class对象来获取类级别信息,如类名,父名,方法和变量信息等。要获得此对象引用,我们可以使用Object类的getClass()方法。
// A Java program to demonstrate working of a Class type
// object created by JVM to represent .class file in
// memory.
import java.lang.reflect.Field;
import java.lang.reflect.Method;
// Java code to demonstrate use of Class object
// created by JVM
public class Test
{
public static void main(String[] args)
{
Student s1 = new Student();
// Getting hold of Class object created
// by JVM.
Class c1 = s1.getClass();
// Printing type of object using c1.
System.out.println(c1.getName());
// getting all methods in an array
Method m[] = c1.getDeclaredMethods();
for (Method method : m)
System.out.println(method.getName());
// getting all fields in an array
Field f[] = c1.getDeclaredFields();
for (Field field : f)
System.out.println(field.getName());
}
}
// A sample class whose information is fetched above using
// its Class object.
class Student
{
private String name;
private int roll_No;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getRoll_no() { return roll_No; }
public void setRoll_no(int roll_no) {
this.roll_No = roll_no;
}
}
输出:
Student getName setName getRoll_no setRoll_no name roll_No
注意:对于每个加载的.class文件,只创建一个 Class对象。
Student s2 = new Student(); // c2 will point to same object where // c1 is pointing Class c2 = s2.getClass(); System.out.println(c1==c2); // true
链接:执行验证,准备和(可选)解决方案。
初始化:在此阶段,所有静态变量都分配有在代码和静态块(如果有)中定义的值。这在类中从上到下执行,在类层次结构中从父到子执行。
一般来说,有三个类加载器:
// Java code to demonstrate Class Loader subsystem
public class Test
{
public static void main(String[] args)
{
// String class is loaded by bootstrap loader, and
// bootstrap loader is not Java object, hence null
System.out.println(String.class.getClassLoader());
// Test class is loaded by Application loader
System.out.println(Test.class.getClassLoader());
}
}
输出:
null sun.misc.Launcher$AppClassLoader@73d16e93
注意: JVM遵循委托 - 层次结构原则来加载类。系统类加载器委托加载请求到扩展类加载器和扩展类加载器委托请求到引导程序类加载器。如果在boot-strap路径中找到类,则加载类,否则请求再次转移到扩展类加载器,然后再转移到系统类加载器。最后,如果系统类加载器无法加载类,那么我们得到运行时异常java.lang.ClassNotFoundException。
JVM Memory
Method区域:在方法区域中,存储所有类级信息,如类名,直接父类名,方法和变量信息等,包括静态变量。每个JVM只有一个方法区域,它是一个共享资源。
堆区域:所有对象的信息存储在堆区域中。每个JVM还有一个堆区域。它也是一种共享资源。
堆栈区域:对于每个线程,JVM创建一个存储在此处的运行时堆栈。该堆栈的每个块都称为激活记录/堆栈帧,用于存储方法调用。该方法的所有局部变量都存储在相应的框架中。线程终止后,它的运行时堆栈将被JVM销毁。它不是共享资源。
PC寄存器:存储线程当前执行指令的地址。显然每个线程都有独立的PC寄存器。
本机方法堆栈:对于每个线程,都会创建单独的本机堆栈。它存储本机方法信息。
执行引擎
执行引擎执行.class(字节码)。它逐行读取字节码,使用各种存储区中的数据和信息并执行指令。它可分为三个部分: -
Java Native Interface(JNI):
它是一个与Native方法库交互并提供执行所需的本机库(C,C ++)的接口。它使JVM能够调用C / C ++库并由C / C ++库调用,这些库可能是特定于硬件的。
本机方法库:
它是执行引擎所需的本机库(C,C ++)的集合。
对于每个线程,JVM在创建线程时创建一个单独的堆栈。Java虚拟机堆栈的内存不需要是连续的。Java虚拟机只在Java Stacks上直接执行两个操作:它推送和弹出帧。并且特定线程的堆栈可以被称为运行时堆栈。由该线程执行的每个方法调用都存储在相应的运行时堆栈中,包括参数,局部变量,中间计算和其他数据。完成方法后,将删除堆栈中的相应条目。在完成所有方法调用之后,堆栈变为空,并且在终止线程之前,JVM会破坏空堆栈。存储在堆栈中的数据可用于相应的线程,并且不可用于其余线程。因此我们可以说本地数据是线程安全的。堆栈中的每个条目称为堆栈帧或激活记录。
堆栈帧结构
堆栈帧基本上由三部分组成:局部变量数组,操作数堆栈和帧数据。当JVM调用Java方法时,首先检查类数据以确定方法在局部变量数组中所需的字数(局部变量数组和操作数堆栈的大小,以单词为单位测量)和操作数堆栈。它为调用的方法创建适当大小的堆栈帧,并将其推送到Java堆栈。
1.局部变量阵列(LVA):
// Class Declaration class Example { public void bike(int i, long l, float f, double d, Object o, byte b) { return 0; } }
2.操作数堆栈(OS):
3.帧数据(FD):
Shutdown Hooks是一种特殊的结构,允许开发人员插入一段代码,以便在JVM关闭时执行。如果我们需要在VM关闭的情况下进行特殊的清理操作,这就派上用场了。
使用常规构造处理此问题,例如确保在应用程序存在之前调用特殊过程(调用System.exit(0))将不适用于VM因外部原因而关闭的情况(例如kill请求)来自O / S),或由于资源问题(内存不足)。正如我们将很快看到的那样,关闭钩子可以轻松解决这个问题,允许我们提供一个任意的代码块,JVM在关闭时会调用它。
从表面看,使用关闭钩是直接向前的。我们所要做的就是编写一个扩展java.lang.Thread类的类,并在public void run()方法中提供我们想要在VM关闭时执行的逻辑。然后我们通过调用Runtime.getRuntime()。addShutdownHook(Thread)方法将此类的实例注册为VM的关闭挂钩。如果需要删除以前注册的关闭钩子,Runtime类也会提供removeShutdownHook(Thread)方法。
例如 :
public class ShutDownHook
{
public static void main(String[] args)
{
Runtime.getRuntime().addShutdownHook(new Thread()
{
public void run()
{
System.out.println("Shutdown Hook is running !");
}
});
System.out.println("Application Terminating ...");
}
}
当我们运行上面的代码时,您将看到JVM在完成main方法的执行时调用了shutdown钩子。
输出:
Application Terminating ... Shutdown Hook is running !
简单吧?是的。
虽然编写一个关闭钩子非常简单,但是需要知道关闭钩子后面的内部才能正确使用它们。因此,在本文中,我们将探讨关闭钩子设计背后的一些“陷阱”。
1.在某些情况下可能无法执行关机挂钩!
首先要记住的是,无法保证关闭挂钩始终会运行。如果JVM由于某些内部错误而崩溃,那么它可能会在没有机会执行单个指令的情况下崩溃。此外,如果O / S发出SIGKILL(http://en.wikipedia.org/wiki/SIGKILL)信号(Unix / Linux中的kill -9)或TerminateProcess(Windows),则应用程序需要立即终止甚至等待任何清理活动。除了上述内容之外,还可以通过调用Runime.halt()方法来终止JVM而不允许关闭挂钩运行。
当应用程序正常终止时(当所有线程完成或调用System.exit(0)时),将调用关闭挂钩。此外,当JVM由于外部原因(例如用户请求终止(Ctrl + C))而关闭时,由O / S(正常kill命令,不带-9)或操作系统关闭时发出SIGTERM 。
2.一旦启动,可在完成前强行停止关机钩。
这实际上是前面解释过的案例的一个特例。虽然钩子开始执行,但在操作系统关闭的情况下,可以在它完成之前终止。在这种情况下,一旦给出SIGTERM,O / S就等待进程终止指定的时间。如果进程未在此时间限制内终止,则O / S通过发出SIGTERM(或Windows中的对应方)强制终止进程。所以当关闭钩子执行到一半时就会发生这种情况。
因此,建议确保快速写入关机挂钩,确保它们快速完成,并且不会导致死锁等情况。此外,JavaDoc [1]特别提到不应该执行长计算或等待关闭钩子中的用户I / O操作。
3.我们可以有多个关机挂钩,但不保证执行顺序。
正如您可能已经通过addShutdownHook方法的方法名称(而不是setShutdownHook)正确猜到的那样,您可以注册多个关闭挂钩。但是JVM无法保证这些多个钩子的执行顺序。JVM可以以任意顺序执行关闭挂钩。此外,JVM可以同时执行所有这些挂钩。
4.我们无法在关闭挂钩中注册/取消注册关闭挂钩
一旦JVM启动关闭序列,就不允许添加更多或删除任何现有的关闭挂钩。如果尝试这样做,JVM将抛出IllegalStateException。
5.一旦关闭序列启动,它只能由Runtime.halt()停止。
一旦关闭序列启动,只有Runtime.halt()(强制终止JVM)才能停止执行关闭序列(除了SIGKILL等外部影响)。这意味着在Shutdown Hook中调用System.exit()将不起作用。实际上,如果你在Shutdown Hook中调用System.exit(),VM可能会卡住,我们可能不得不强行终止进程。
6.使用shutdown hooks需要安全权限。
如果我们使用Java安全管理器,则执行添加/删除关闭挂钩的代码需要在运行时具有shutdownHooks权限。如果我们在安全环境中未经许可调用此方法,则会导致SecurityException。
甲Java类文件是包含Java字节码和具有文件.class扩展,可以通过执行JVM。由于编译成功,Java编译器会从.java文件创建Java类文件。我们知道单个Java编程语言源文件(或者我们可以说.java文件)可能包含一个类或多个类。因此,如果.java文件具有多个类,则每个类将编译为单独的类文件。
例如: 将以下代码保存为系统上的Test.java。
// Compiling this Java program would
// result in multiple class files.
class Sample
{
}
// Class Declaration
class Student
{
}
// Class Declaration
class Test
{
public static void main(String[] args)
{
System.out.println("Class File Structure");
}
}
用于编译:
javac Test.java
编译后,相应文件夹中将有3个类文件命名为:
单个类文件结构包含描述类文件的属性。
类文件结构的表示
ClassFile { magic_number; minor_version; major_version; constant_pool_count; constant_pool[]; access_flags; this_class; super_class; interfaces_count; interfaces[]; fields_count; fields[]; methods_count; methods[]; attributes_count; attributes[]; }
类文件的元素如下:
// class Declaration class Sample { public static void main(String[] args) { System.out.println("Magic Number"); } }
步骤1: 使用javac Sample.java进行编译
步骤2:现在打开Sample.class文件。它看起来像以下。
步骤3:现在从文件的起始处删除此Sample.class文件中的至少单个符号并保存。
第4步:现在尝试使用java Sample命令运行它并查看魔法,即您将获得运行时异常(请参见下图中突出显示的文本):
注意:这取决于您删除.class文件数据的数量。
注意:较低版本编译器生成的.class文件可以由高版本JVM执行,但较高版本编译器生成的.class文件不能由较低版本的JVM执行。如果我们尝试执行,我们将获得运行时异常。
此演示适用于Windows操作系统,如下所示:
步骤1:打开命令提示符窗口并尝试分别使用以下命令检查java编译器版本和JVM版本(图像中突出显示的文本是命令)
1.8版本的输出将是:
第2步:现在检查可能高于或低于已安装的其他版本。这个下载链接。
并将其安装到您的PC或笔记本电脑上,并记下安装地址。
步骤3:打开第二个命令提示符窗口,并设置第二步安装的已安装的jdk的bin文件夹的路径。并检查Java编译器版本和JVM版本。
第4步:现在在第一个命令提示符下编译任何有效的.java文件。例如:参见上面的Sample.java文件。编译为:
步骤5:现在在第二个命令提示符窗口尝试运行上面编译的代码类文件,看看会发生什么。有一个运行时异常,我在下面的图像中突出显示。
注意:内部jdk 1.5版本表示49.0和1.6表示50.0和1.7表示51.0等类文件版本,其中小数点前的数字表示major_version,小数点后的数字表示minor_version。
Java Development Kit(JDK)是一个用于开发Java应用程序和applet的软件开发环境。它包括Java运行时环境(JRE),解释器/加载器(Java),编译器(javac),归档器(jar),文档生成器(Javadoc)以及Java开发中所需的其他工具。
JAVA运行时环境
JRE代表“Java Runtime Environment”,也可以写成“Java RTE” .Java Runtime Environment提供了执行Java应用程序的最低要求。它由Java虚拟机(JVM),核心类和支持文件组成。
查看上文中的jvm是如何工作的
它是:
JDK,JRE和JVM之间存在差异
注意: JDK仅供Java开发人员使用。
在运行时,解释器加载,检查和运行字节代码。解释器具有以下两个功能:
类加载器加载执行程序所需的所有必要类。它通过将本地文件系统的名称空间与通过网络导入的名称空间分开来提供安全性。这些文件可以从硬盘,网络或其他来源加载。
JVM通过字节代码验证程序放置代码,该代码验证程序检查格式并检查非法代码。例如,非法代码是违反对象访问权限或违反指针实现的代码。
字节代码验证程序可确保代码符合JVM规范,并且不会违反系统完整性。
在运行时,解释器加载,检查和运行字节代码。解释器具有以下两个功能:
这两个操作都可以显示为:
要了解JDK和JRE之间的交互,请考虑下图。
JVM是如何工作的?
JVM在Java程序的运行时成为JRE的实例。它被广泛称为运行时解释器.JVM很大程度上有助于从使用JDK程序库的程序员中抽象内部实现。
有关JVM的详细工作请查看上文中的jvm是如何工作的
考虑以下程序。
class Main {
public static void main(String args[])
{
System.out.println("wellcome subscribe to geekmoney");
}
}
输出:
wellcome subscribe to geekmoney
JVM是否创建了Main类的对象?
答案是不”。我们已经研究过Java中main()静态的原因是确保可以在没有任何实例的情况下调用main()。为了证明这一点,我们可以看到以下程序编译并运行正常。
// Not Main is abstract
abstract class Main {
public static void main(String args[])
{
System.out.println("wellcome subscribe to geekmoney");
}
}
输出:
wellcome subscribe to geekmoney
由于我们无法在Java中创建抽象类的对象,因此可以保证带有main()的类的对象不是由JVM创建的。
感谢大家,本文仅供学习查阅,不可用作商业用途,如果转发,请注明原文链接,谢谢。
本文翻译于国外知识论坛,如果翻译有误或者侵犯版权,请联系我,我会尽快删除。
如果觉得本文有帮助,请关注我,我会持续更新的。希望可以在程序员的路上越走越远。
文章我会同步更新到订阅号:geekmoney。如果有兴趣,欢迎订阅。后续精彩内容不断,希望能和各位一起进步,共同发展