写在最前
Java 是一门面向对象的高级编程语言,不仅吸收了 C++ 语言的各种优点,比如继承了 C++ 语言面向对象的技术核心。还摒弃了 C++ 里难以理解的多继承、指针等概念,同时也增加了垃圾回收机制,释放掉不被使用的内存空间,解决了管理内存空间的烦恼。
因此 Java 语言具有功能强大和简单易用两个特征。Java 语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
Java的特点
Java 语言是一种分布式的面向对象语言,具有面向对象、平台无关性、简单性、解释执行、多线程、安全性等很多特点,下面针对这些特点进行逐一介绍。
面向对象
Java 是一种面向对象的语言,它对对象中的类、对象、继承、封装、多态、接口、包等均有很好的支持。为了简单起见,Java 只支持类之间的单继承,但是可以使用接口来实现多继承。使用 Java 语言开发程序,需要采用面向对象的思想设计程序和编写代码。
平台无关性
Java 是**“一次编写,到处运行(Write Once,Run any Where)”**的语言,因此采用 Java 语言编写的程序具有很好的可移植性,而保证这一点的正是 Java 的虚拟机机制。在引入虚拟机之后,Java 语言在不同的平台上运行不需要重新编译。
简单性
Java 语言的语法与 C 语言和 C++ 语言很相近,使得很多程序员学起来很容易。对 Java 来说,它舍弃了很多 C++ 中难以理解的特性,如操作符的重载和多继承等,而且 Java 语言不使用指针,加入了垃圾回收机制,解决了程序员需要管理内存的问题,使编程变得更加简单。
解释执行
Java 程序在 Java 平台运行时会被编译成字节码文件,然后可以在有 Java 环境的操作系统上运行。在运行文件时,Java 的解释器对这些字节码进行解释执行,执行过程中需要加入的类在连接阶段被载入到运行环境中。
多线程
Java 语言是多线程的,这也是 Java 语言的一大特性,它必须由 Thread 类和它的子类来创建。Java 支持多个线程同时执行,并提供多线程之间的同步机制。任何一个线程都有自己的 run() 方法,要执行的方法就写在 run() 方法体内。
分布式
Java 语言支持 Internet 应用的开发,在 Java 的基本应用编程接口中就有一个网络应用编程接口,它提供了网络应用编程的类库,包括 URL、URLConnection、Socket 等。Java 的 RIM 机制也是开发分布式应用的重要手段。
健壮性
Java 的强类型机制、异常处理、垃圾回收机制等都是 Java 健壮性的重要保证。对指针的丢弃是 Java 的一大进步。另外,Java 的异常机制也是健壮性的一大体现。
高性能
Java 的高性能主要是相对其他高级脚本语言来说的,随着 JIT(Just in Time)的发展,Java 的运行速度也越来越高。
安全性
Java 通常被用在网络环境中,为此,Java 提供了一个安全机制以防止恶意代码的攻击。除了 Java 语言具有许多的安全特性以外,Java 还对通过网络下载的类增加一个安全防范机制,分配不同的名字空间以防替代本地的同名类,并包含安全管理机制。
面向对象的特征
面向对象的编程语言有封装、继承 、抽象、多态等4个主要的特征。
封装
把描述一个对象的属性和行为的代码封装在一个模块中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。
继承
子类继承父类的特征和行为。子类可以有父类的方法,属性(非 private )。子类也可以对父类进行扩展,也可以重写父类的方法。缺点就是提高代码之间的耦合性。
抽象
把现实生活中的对象抽象为类。分为过程抽象和数据抽象:
- 数据抽象:鸟有翅膀,羽毛等(类的属性);
- 过程抽象:鸟会飞,会叫(类的方法);
多态
程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定(比如:向上转型,只有运行才能确定其对象属性)。方法覆盖和重载体现了多态性。
JDK、JRE 和 JVM
- JDK 用于开发,JRE 用于运行 Java 程序 ;如果只是运行 Java 程序,可以只安装 JRE,无序安装 JDK。
- JDk 包含 JRE,JDK 和 JRE 中都包含 JVM。
- JVM 是 Java 编程语言的核心并且具有平台独立性。
JDK
JDK(Java SE Development Kit),Java标准的开发包,提供了编译、运行Java程序所需要的各种工具和资源,包括了Java编译器、Java运行时环境、以及常用的Java类库等。
JRE
JRE(Java Runtime Environment),Java运行时环境,用于解释执行Java的字节码文件。普通用户只需要安装 JRE 来运行 Java 程序即可,而作为一名程序员必须安装 JDK,来编译、调试程序。
JVM
JVM(Java Virtual Mechinal),Java虚拟机,是 JRE 的一部分。它是整个Java实现跨平台的核心,负责解释执行字节码文件,是可运行 Java 字节码文件的虚拟计算机。所有平台上的 JVM 向编译器提供相同的接口,而编译器只需要面向虚拟机,生成虚拟机能识别的代码,然后由虚拟机来解释执行。
当使用 Java 编译器编译 Java 程序时,生成的是与平台无关的字节码,这些字节码只面向 JVM。也就是说 JVM 是运行 Java 字节码的虚拟机。
为什么要采用字节码
在 Java 中,JVM 可以理解的代码就叫做字节码(即 Java 源代码经过虚拟机编译器编译后扩展名为.class 的文件),它不面向任何特定的处理器,只面向虚拟机。Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比较高效。而且,由于字节码并不针对一种特定的机器,因此,Java 程序无须重新编译便可在多种不同操作系统的计算机上运行。
Java程序执行过程
程序的执行流程基本都是相同的,它的执行流程如下:
- 先把 Java 代码编译成字节码,也就是把 .java 类型的文件编译成 .class 类型的文件。这个过程的大致执行流程:Java 源代码 -> 词法分析器 -> 语法分析器 -> 语义分析器 -> 字符码生成器 -> 最终生成字节码,其中任何一个节点执行失败就会造成编译失败;
- 把 class 文件放置到 Java 虚拟机,这个虚拟机通常指的是 Oracle 官方自带的 Hotspot JVM;
- Java 虚拟机使用类加载器(Class Loader)装载 class 文件;
- 类加载完成之后,会进行字节码效验,字节码效验通过之后 JVM 解释器会把字节码翻译成机器码交由操作系统执行。但不是所有代码都是解释执行的,JVM 对此做了优化,比如,以 Hotspot 虚拟机来说,它本身提供了 JIT(Just In Time)也就是我们通常所说的动态编译器,它能够在运行时将热点代码编译为机器码,这个时候字节码就变成了编译执行。
Java 程序执行流程图如下:
Java数据类型
基本数据类型
8 种基本数据类型
- 6 种数字类型 (四个整数形,两个浮点型):byte、short、int、long、float、double;
- 1 种字符类型:char;
- 1 种布尔型:boolean;
类型名称 | 关键字 | 占用内存 | 取值范围 |
---|---|---|---|
字节型 | byte | 1 字节 | -128~127 |
短整型 | short | 2 字节 | -32768~32767 |
整型 | int | 4 字节 | -2147483648~2147483647 |
长整型 | long | 8 字节 | -9223372036854775808L~9223372036854775807L |
单精度浮点型 | float | 4 字节 | +/-3.4E+38F(6~7 个有效位) |
双精度浮点型 | double | 8 字节 | +/-1.8E+308 (15 个有效位) |
字符型 | char | 2 字节 | ISO 单一字符集 |
布尔型 | boolean | 1 字节 | true 或 false |
引用数据类型
引用数据类型分3种:类,接口,数组;
简单来说,只要不是基本数据类型.都是引用数据类型。
两者的区别
概念 | 使用 | 内存的构建 | |
---|---|---|---|
基本数据类型 | 指向具体的数值 | 被创建时,在栈内存中会被划分出一定的内存,并将数值存储在该内存中 | 判断数据是否相等,用==和!=判断 |
引用数据类型 | 指向存数据的内存地址 | 被创建时,首先会在栈内存中分配一块空间,然后在堆内存中也会分配一块具体的空间用来存储数据的具体信息,即hash值,然后由栈中引用指向堆中的对象地址 | 判断数据是否相等,用equals()方法,==和!=是比较数值的。而equals()方法是比较内存地址的 |
自动装箱与拆箱
包装类
让基本数据类型也具有对象的特征
基本类型 | 包装器类型 |
---|---|
boolean | Boolean |
char | Character |
int | Integer |
byte | Byte |
short | Short |
long | Long |
float | Float |
double | Double |
如我们在使用集合类型 Collection 时就一定要使用包装类型而非基本类型,因为容器都是装 Object 的,这是就需要这些基本类型的包装器类了~
装箱与拆箱
装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。
在 Java SE 5之前,自动装箱要这样写:
Integer i = new Integer(10)
;
/** @author Strive */
public class DisassemblyAndAssemblyBox {
public static void main(String[] args) {
// 自动装箱
Integer total = 99;
// 自定拆箱
int totalprim = total;
}
}
上述代码的装箱其实是调用包装类的 Integer.valueOf
方法,拆箱调用的是 Integer.intValue
方法。
我们可以通过查看字节码文件证实,通过 javap -c DisassemblyAndAssemblyBox.class
查看字节码文件。
Compiled from "DisassemblyAndAssemblyBox.java"
public class com.csp.dolphin.base.DisassemblyAndAssemblyBox {
public com.csp.dolphin.base.DisassemblyAndAssemblyBox();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 99
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: aload_1
7: invokevirtual #3 // Method java/lang/Integer.intValue:()I
10: istore_2
11: return
}
扩展
static和final
修饰物/关键字 | final | static |
---|---|---|
变量 | 分配到常量池中,程序不可改变其值 | 分配在内存堆上,引用都会指向这一个地址而不会重新分配内存 |
方法 | 子类中将不能被重写 | 虚拟机优先加载 |
类 | 不能被继承 | 可以直接通过类来调用而不需要 new |
我们通常会向如下代码声明一个变量,思考一下为何让 static final 一起使用
public static final String PROJECT_NAME = "虎虎生威";
final 与 static final 的区别是:final 在一个对象类唯一,static final 在多个对象中都唯一;
一个既是 static 又是 final 的域只占据一段不能改变的存储空间,只有一份。