Java基础

12/31/2023 Java

目录


参考:


# Java基础

# JDK、JRE、JVM

  • JDK: Java Development Kit ,Java开发工具包。是 Java 开发的核心,包括了 Java 运行环境、Java工具 以及 Java 基础类库。

  • JRE: Java Runtime Environment ,Java运行环境。是运行基于Java语言编写的程序所不可缺少的运行环境。

  • JVM:Java Virtual Machine ,Java虚拟机。是Java实现跨平台的最核心部分。所有的 java 程序会首先被编译为 .class 的类文件,这种类文件可以在虚拟机上执行。由虚拟机将程序解释给本地系统执行。

JDK 中包含 JRE,在 JDK 的安装目录下有一个名为 jre 的目录,里面有两个文件夹 bin 和 lib,可以认为 bin 里的就是 jvm,lib中则是 jvm 工作所需要的类库,而 jvm 和 lib 合起来就称为 jre。

19163653_6467352508e3d1744


# Java运行机制

Java 程序的运行必须经过编写、编译、运行三个步骤。

  • 编写:是指在 Java 开发环境中进行程序代码的输入,最终形成后缀名为 .java 的 Java 源文件。
  • 编译:是指使用 Java 编译器对源文件进行错误排查的过程,编译后将生成后缀名为 .class 的字节码文件,这不像 C 语言那样最终生成可执行文件。
  • 运行:是指使用 Java 解释器将字节码文件翻译成机器代码,执行并显示结果。

578fedd5c6ea413f830c210d88d0fe69


# Java 虚拟机

​ Java 虚拟机(JVM)是运行 Java 程序的软件环境,由它来负责解释执行 Java 的字节码,并且 Java 字节码只能运行于 JVM 之上。这样利用 JVM 就可以把 Java 字节码程序和具体的硬件平台以及操作系统环境分隔开来,从而实现了真正的二进制代码级的跨平台移植。JVM 是 Java 与平台无关的基础,Java 的跨平台特性正是通过在 JVM 中运行 Java 程序实现的。

d34aae24d03647c48c34f4836c768d10

# JVM 执行程序的过程

  • 加载 .class 文件。
  • 管理并分配内存。
  • 执行垃圾收集。

# JVM 的生命周期

​ JVM 实例对应了一个独立运行的 java 程序,它是进程级别的。

​ JVM 执行引擎实例则对应了属于用户运行程序的线程,它是线程级别的。

  • 启动。启动一个 Java 程序时,一个 JVM 实例就产生了,任何一个拥有 public static void main(String[] args )函数的 .class 都可以作为 JVM 实例运行的起点。
  • 运行。main() 作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM 内部有两种线程:守护线程和非守护线程,main() 属于非守护线程,守护线程通常由 JVM 自己使用,java 程序也可以表明自己创建的线程是守护线程。
  • 消亡。当程序中的所有非守护线程都终止时,JVM 才退出;若安全管理器允许,程序也可以使用 Runtime 类或者 System.exit() 来退出。

# JVM 运行时数据区(Java 内存)

​ Java 内存是指 Java虚拟机(JVM)在运行时使用的内存空间。它由堆,方法区,虚拟机栈,本地方法栈和程序计数器组成。堆是 Java 应用程序中最大的内存区域,用于存储对象实例。方法区用于存储类和方法的元数据。虚拟机栈用于存储局部变量和操作数栈。本地方法栈用于存储本地(native)方法的信息。程序计数器用于存储当前正在执行的字节码的行号指示器。

  • Java堆(Java Heap)

​ java 堆(Java Heap)是 java 虚拟机所管理的内存中最大的一块,是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例。在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。java 堆是垃圾收集器管理的主要区域,因此也被成为“GC堆”。从内存回收角度来看 java 堆可分为:新生代和老生代。从内存分配的角度看,线程共享的 Java 堆中可能划分出多个线程私有的分配缓冲区。无论怎么划分,都与存放内容无关,无论哪个区域,存储的都是对象实例,进一步的划分都是为了更好的回收内存,或者更快的分配内存。根据 Java 虚拟机规范的规定,java 堆可以处于物理上不连续的内存空间中。当前主流的虚拟机都是可扩展的(通过 -Xmx 和 -Xms 控制)。如果堆中没有内存可以完成实例分配,并且堆也无法再扩展时,将会抛 OutOfMemoryError 异常。

  • 方法区(Method Area)

​ 方法区(Method Area)是所有线程共享的内存区域,它用于存储已被 Java 虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。它有个别命叫 Non-Heap(非堆)。当方法区无法满足内存分配需求时,抛出 OutOfMemoryError 异常。

  • 程序计数器(Program Counter Register)

​ 程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是:保存当前线程所正在执行的字节码指令的地址(行号),也可以把它叫做线程计数器。由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,一个处理器都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储。称之为”线程私有“的内存。程序计数器内存区域是虚拟机中唯一没有规定 OutOfMemoryError 情况的区域。

  • Java虚拟机栈(Java Virtual Machine Stacks)

​ java 虚拟机是线程私有的,它的生命周期和线程相同。虚拟机栈(Java Virtual Machine Stacks)描述的是 Java 方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。虚拟机栈中是有单位的,单位就是栈帧,一个方法一个栈帧。一个栈帧中他又要存储,局部变量,操作数栈,动态链接,出口等。

  • 本地方法栈(Native Method Stack)

​ 本地方法栈(Native Method Stack)很好理解,他和栈很像,只不过方法上带了 native 关键字的栈字,它是虚拟机栈为虚拟机执行 Java 方法(也就是字节码)的服务,native 关键字的方法是看不到的,必须要去 oracle 官网去下载才可以看的到,而且 native 关键字修饰的大部分源码都是 C 和 C++ 的代码。同理可得,本地方法栈中就是 C 和 C++ 的代码。

# Java内存结构

  • 直接内存(Direct Memory)

​ 直接内存不是虚拟机运行时数据区的一部分,也不是 java 虚拟机规范中定义的内存区域。但是既然是内存,肯定还是受本机总内存(包括 RAM 以及 SWAP 区或者分页文件)大小以及处理器寻址空间的限制。在 JDK1.4 中新加入了 NIO(New Input/Output) 类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用 native 函数库直接分配堆外内存,然后通脱一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native(本地)堆中来回复制数据。

​ 直接内存与堆内存的区别:

​ 1)直接内存申请空间耗费很高的性能,堆内存申请空间耗费比较低。

​ 2)直接内存的 IO 读写的性能要优于堆内存,在多次读写操作的情况相差非常明显。

  • JVM 字节码执行引擎

​ 虚拟机核心的组件就是执行引擎,它负责执行虚拟机的字节码,一般户先进行编译成机器码后执行。“虚拟机”是一个相对于“物理机”的概念,虚拟机的字节码是不能直接在物理机上运行的,需要 JVM 字节码执行引擎编译成机器码后才可在物理机上执行。

  • 垃圾收集系统

​ 程序在运行过程中,会产生大量的内存垃圾(一些没有引用指向的内存对象都属于内存垃圾,因为这些对象已经无法访问,程序用不了它们了,对程序而言它们已经死亡),为了确保程序运行时的性能,java 虚拟机在程序运行的过程中不断地进行自动的垃圾回收(GC)。垃圾收集系统是Java的核心,也是不可少的,Java 有一套自己进行垃圾清理的机制,开发人员无需手工清理。

# JVM的垃圾回收机制

垃圾回收机制简称 GC,GC 主要用于 Java 堆的管理。Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。

  • 什么是垃圾回收机制

​ 程序在运行过程中,会产生大量的内存垃圾(一些没有引用指向的内存对象都属于内存垃圾,因为这些对象已经无法访问,程序用不了它们了,对程序而言它们已经死亡),为了确保程序运行时的性能,java 虚拟机在程序运行的过程中不断地进行自动的垃圾回收(GC)。

​ GC 是不定时去堆内存中清理不可达对象。不可达的对象并不会马上就会直接回收, 垃圾收集器在一个 Java 程序中的执行是自动的,不能强制执行清除哪个对象,即使程序员能明确地判断出有一块内存已经无用了,是应该回收的,程序员也不能强制垃圾收集器回收该内存块。程序员唯一能做的就是通过调用System.gc 方法来"建议"执行垃圾收集器,但是他是否执行,什么时候执行却都是不可知的。这也是垃圾收集器的最主要的缺点。当然相对于它给程序员带来的巨大方便性而言,这个缺点是瑕不掩瑜的。

//手动执行GC,回收垃圾
System.gc(); 
1
2
  • finalize方法作用

​ finalize() 方法是在每次执行 GC 操作之前时会调用的方法,可以用它做必要的清理工作。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。

public class Test {

	public static void main(String[] args) {
		Test test = new Test();
		test = null;
		System.gc(); // 手动回收垃圾
	}

	@Override
	protected void finalize() throws Throwable {
		// gc回收垃圾之前调用
		System.out.println("gc回收垃圾之前调用的方法");
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 垃圾收集器

垃圾收集器是垃圾回收算法(引用计数法、标记清楚法、标记整理法、复制算法)的具体实现,不同垃圾收集器、不同版本的 JVM 所提供的垃圾收集器可能会有很在差别。


# Java语言特点

(1)**面向对象:**Java是一种面向对象的编程语言。

(2)**语法简单:**Java语言继承了C++语言的优点,剔除了C++中学习起来比较难的多继承、指针等概念,所以Java语言学习起来比较简单,使用起来也方便。

(3)**平台无关性:**Java并不依赖平台,用Java编写的程序可以运用到任何操作系统上。

(4)**安全性:**Java的存储分配模型是它防御恶意代码的主要方法之一。

(5)**分布式应用:**Java设计成支持在网络上应用,它是分布式语言。只要用Java编写了一个程序,就可以应用。

(6)**多线程:**进程是操作系统中分配的最小内存资源单元。每个进程可以同时拥有两个或多个线程,允许它们同时执行。并且它提供了Rannable接口及其实现类Thread,提供了许多控制线程操作的方法,以及线程同步控制。


# Java语言的发展简史

  • 1990年Sun的“Green计划”(面向嵌入式系统的通用系统),C++到Oak。
  • 1992年Oak相关操作系统、类库等完成,11月,“Green计划”被转化成“FirstPerson有限公司”(致力高度互动的设备),关于机顶盒的交易屡败,Green项目几乎接近夭折。
  • 1994年互联网和浏览器出现,对Oak改进出现第一个Java语言的网页浏览器WebRunner,并得到Sun的赏析,由于Oak已被别人注册,因此改名为Java。
  • 1995年Sun公司发布了Java语言,并将源代码毫不保留地放到互联网上,几个月后,Java成为互联网上最热门的宝贝,涌现了大量Java小程序(Applet),Java在移动互联网上主要用于交互、动画。至此,Java诞生。
  • 1996年Flash的出现逐渐吞噬了Java在网页上的应用。第一个JDK诞生。
  • 1998年定位到企业、桌面和移动3个领域,Java飞速发展。
  • 1999年Sun公司发布J2SE、J2EE、J2EE。
  • 2004年Java SE5.0发布。
  • 2007年Google推出的Android给Java带来了新的发展机会。
  • 2009年Sun公司被Oracle以总价值约74亿美元收购,获得两项软件资产,Java和Solaris。
  • 2012年Oracle发布Java7。

目前,Java的竞争对手有C#、Ruby、Python等。

上次更新时间: 9/25/2024, 9:17:45 AM