Java基础语法
Java
Java简介
Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 面向对象程序设计语言和 Java 平台的总称。由 James Gosling和同事们共同研发,并在 1995 年正式推出。后来 Sun 公司被 Oracle (甲骨文)公司收购,Java 也随之成为 Oracle 公司的产品。
Java分为三个体系:
- JavaSE(J2SE)(Java2 Platform Standard Edition,java平台标准版)
- JavaEE(J2EE)(Java 2 Platform,Enterprise Edition,java平台企业版)
- JavaME(J2ME)(Java 2 Platform Micro Edition,java平台微型版)
2005 年 6 月,JavaOne 大会召开,SUN 公司公开 Java SE 6。此时,Java 的各种版本已经更名,以取消其中的数字 "2":J2EE 更名为 Java EE,J2SE 更名为Java SE,J2ME 更名为 Java ME。
主要特性
Java 语言是简单的:
Java 语言的语法与 C 语言和 C++ 语言很接近,使得大多数程序员很容易学习和使用。另一方面,Java 丢弃了 C++ 中很少使用的、很难理解的、令人迷惑的那些特性,如操作符重载、多继承、自动的强制类型转换。特别地,Java 语言不使用指针,而是引用。并提供了自动分配和回收内存空间,使得程序员不必为内存管理而担忧。Java 语言是面向对象的:
Java 语言提供类、接口和继承等面向对象的特性,为了简单起见,只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制(关键字为 implements)。Java 语言全面支持动态绑定,而 C++语言只对虚函数使用动态绑定。总之,Java语言是一个纯的面向对象程序设计语言。Java语言是分布式的:
Java 语言支持 Internet 应用的开发,在基本的 Java 应用编程接口中有一个网络应用编程接口(java net),它提供了用于网络应用编程的类库,包括 URL、URLConnection、Socket、ServerSocket 等。Java 的 RMI(远程方法激活)机制也是开发分布式应用的重要手段。Java 语言是健壮的:
Java 的强类型机制、异常处理、垃圾的自动收集等是 Java 程序健壮性的重要保证。对指针的丢弃是 Java 的明智选择。Java 的安全检查机制使得 Java 更具健壮性。Java语言是安全的:
Java通常被用在网络环境中,为此,Java 提供了一个安全机制以防恶意代码的攻击。除了Java 语言具有的许多安全特性以外,Java 对通过网络下载的类具有一个安全防范机制(类 ClassLoader),如分配不同的名字空间以防替代本地的同名类、字节代码检查,并提供安全管理机制(类 SecurityManager)让 Java 应用设置安全哨兵。Java 语言是体系结构中立的:
Java 程序(后缀为 java 的文件)在 Java 平台上被编译为体系结构中立的字节码格式(后缀为 class 的文件),然后可以在实现这个 Java 平台的任何系统中运行。这种途径适合于异构的网络环境和软件的分发。Java 语言是可移植的:
这种可移植性来源于体系结构中立性,另外,Java 还严格规定了各个基本数据类型的长度。Java 系统本身也具有很强的可移植性,Java 编译器是用 Java 实现的,Java 的运行环境是用 ANSI C 实现的。Java 语言是解释型的:
如前所述,Java 程序在 Java 平台上被编译为字节码格式,然后可以在实现这个 Java 平台的任何系统中运行。在运行时,Java 平台中的 Java 解释器对这些字节码进行解释执行,执行过程中需要的类在联接阶段被载入到运行环境中。Java 是高性能的:
与那些解释型的高级脚本语言相比,Java 的确是高性能的。事实上,Java 的运行速度随着 JIT(Just-In-Time)编译器技术的发展越来越接近于 C++。Java 语言是多线程的:
在 Java 语言中,线程是一种特殊的对象,它必须由 Thread 类或其子(孙)类来创建。通常有两种方法来创建线程:其一,使用型构为 Thread(Runnable) 的构造子类将一个实现了 Runnable 接口的对象包装成一个线程,其二,从 Thread 类派生出子类并重写 run 方法,使用该子类创建的对象即为线程。值得注意的是 Thread 类已经实现了 Runnable 接口,因此,任何一个线程均有它的 run 方法,而 run 方法中包含了线程所要运行的代码。线程的活动由一组方法来控制。Java 语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为 synchronized)。Java 语言是动态的:
Java 语言的设计目标之一是适应于动态变化的环境。Java 程序需要的类能够动态地被载入到运行环境,也可以通过网络来载入所需要的类。这也有利于软件的升级。另外,Java 中的类有一个运行时刻的表示,能进行运行时刻的类型检查。
Java的版本和体系
三个版本
- Java SE:Standard Edition
- Java EE:Enterprise Edition
- Java ME:Micro Edition
Java SE就是标准版,包含标准的JVM和标准库,而Java EE是企业版,它只是在Java SE的基础上加上了大量的API和库,以便方便开发Web应用、数据库、消息服务等,Java EE的应用使用的虚拟机和Java SE完全相同。
Java ME就和Java SE不同,它是一个针对嵌入式设备的“瘦身版”,Java SE的标准库无法在Java ME上使用,Java ME的虚拟机也是“瘦身版”。
Java的体系架构
JVM
Java Virtual Machine(JVM)是Java编程语言的核心组件之一,它是运行Java程序的运行时环境。JVM是平台无关的,这是Java语言“编译一次,到处运行”的关键所在。以下是JVM的基础知识:
1. JVM的基本概念
- 虚拟机:JVM是一个抽象计算机,提供运行Java程序所需的指令集和执行环境。它负责将编译后的Java字节码(.class文件)解释或编译为特定平台的机器码并执行。
- 平台无关性:Java源代码编译成字节码后,这些字节码可以在任何安装了相应JVM的设备上运行,而不需要重新编译。
2. JVM的主要组件
- 类加载器(Class Loader):负责将字节码加载到JVM中。类加载器可以从文件系统、网络或其他位置加载.class文件,并将其转换为JVM可以理解的类对象。
- 运行时数据区(Runtime Data Area):
- 方法区(Method Area):存储已加载的类信息、常量、静态变量和方法字节码。
- 堆(Heap):存储Java对象实例,是垃圾回收器(GC)管理的主要区域。
- 栈(Stack):每个线程都有自己的栈,栈中保存了局部变量、操作数和方法调用的返回地址。
- 程序计数器(PC Register):记录当前线程执行的字节码指令地址。
- 本地方法栈(Native Method Stack):用于执行本地方法(通常是C或C++实现的)。
3. JVM的工作过程
- 类加载:通过类加载器将字节码加载到内存中。
- 字节码校验:确保字节码符合JVM的规范和安全要求。
- 解释与执行:JVM解释或即时编译(Just-In-Time, JIT)字节码,将其转化为机器码并执行。
- 垃圾回收:自动管理堆内存,通过垃圾回收机制回收不再使用的对象。
4. JVM的调优与管理
- 垃圾回收(GC):JVM自动管理内存,但不同的GC算法(如串行GC、并行GC、G1 GC等)适用于不同的应用场景。合理配置GC可以提升应用性能。
- JVM参数调优:通过设置JVM启动参数(如
-Xms
、-Xmx
、-XX:PermSize
等),可以优化内存使用、GC行为和性能表现。 - 监控工具:Java提供了多种监控工具,如JConsole、VisualVM、JMC(Java Mission Control),用于监控JVM的性能、内存使用、线程状态等。
5. JVM与多线程
- 线程模型:JVM原生支持多线程,每个Java线程对应于操作系统的一个线程。JVM通过多线程机制提高程序执行效率,特别是在多核处理器上。
- 同步与锁:JVM提供了内置锁(monitor)和同步机制,确保多线程访问共享资源时的线程安全。
6. 常见JVM问题与调试
- 内存泄漏:尽管JVM有垃圾回收机制,内存泄漏仍可能发生。调试工具如MAT(Memory Analyzer Tool)可以帮助查找和解决内存泄漏问题。
- 性能瓶颈:性能调优通常涉及垃圾回收、内存分配和线程管理。通过性能监控工具,可以识别和解决JVM性能瓶颈。
JVM不仅仅是Java程序的运行时环境,它还通过跨平台能力、高效的内存管理和强大的多线程支持。
Java开发环境
windows开发环境
IDE
基础语法
一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作。下面简要介绍下类、对象、方法和实例变量的概念。
- 对象:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
- 类:类是一个模板,它描述一类对象的行为和状态。
- 方法:方法就是行为,一个类可以有很多方法。逻辑运算、数据修改以及所有动作都是在方法中完成的。
- 实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定。
hello world
public class HelloWorld {
/* 第一个Java程序
* 它将输出字符串 Hello World
*/
public static void main(String[] args) {
System.out.println("Hello World"); // 输出 Hello World
}
}
基本规则
大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的。 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为 .java。(如果文件名和类名不相同则会导致编译错误)。 主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行。
标识符
Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。
关于 Java 标识符,有以下几点需要注意:
- 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始
- 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线(_)或数字的任何字符组合
- 关键字不能用作标识符
- 标识符是大小写敏感的
- 合法标识符举例:age、$salary、_value、__1_value
- 非法标识符举例:123abc、-salary
修饰符
像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
- 访问控制修饰符 : default, public , protected, private
- 非访问控制修饰符 : final, abstract, static, synchronized
变量
Java 中主要有如下几种类型的变量
- 局部变量
- 类变量(静态变量)
- 成员变量(非静态变量)
关键字
注释
Java 注释主要有三种类型:
- 单行注释
- 多行注释
- 文档注释
单行注释
单行注释以双斜杠 // 开始:
// 这是一个单行注释
int x = 10; // 初始化一个变量x为10
多行注释
多行注释以 /*开始,以 */结束:
/*
这是一个多行注释
可以用来注释多行代码
*/
int y = 20; // 初始化一个变量y为20
文档注释
文档注释以 /** 开始,以 */ 结束,通常出现在类、方法、字段等的声明前面,用于生成代码文档,这种注释可以被工具提取并生成 API 文档,如 JavaDoc。
/**
* 这是一个文档注释示例
* 它通常包含有关类、方法或字段的详细信息
*/
public class MyClass {
// 类的成员和方法
}
文档注释的格式通常包含一些特定的标签,如 @param 用于描述方法参数,@return 用于描述返回值,@throws 用于描述可能抛出的异常等等,这些标签有助于生成清晰的API文档,以便其他开发者能够更好地理解和使用你的代码。
Java编译运行
基本数据类型
Java 中有八种基本数据类型,它们分为四类:整数类型、浮点类型、字符类型和布尔类型。
1. 整数类型 (Integer Types)
- byte: 8 位有符号整数,取值范围为 -128 到 127。
- short: 16 位有符号整数,取值范围为 -32,768 到 32,767。
- int: 32 位有符号整数,取值范围为 -2^31 到 2^31-1(即 -2,147,483,648 到 2,147,483,647)。
- long: 64 位有符号整数,取值范围为 -2^63 到 2^63-1。
2. 浮点类型 (Floating-Point Types)
- float: 32 位单精度浮点数。适合存储小数位数较少的数据。
- double: 64 位双精度浮点数。适合存储大部分浮点数。
3. 字符类型 (Character Type)
- char: 16 位字符,表示一个 Unicode 字符,取值范围为 '\u0000' (即 0) 到 '\uffff' (即 65,535)。
4. 布尔类型 (Boolean Type)
- boolean: 只有两个取值:
true
和false
。通常用于条件判断。
类型默认值
引用类型
- 在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。
- 对象、数组都是引用数据类型。
- 所有引用类型的默认值都是null。
- 一个引用变量可以用来引用任何与之兼容的类型。
- 例子:
Site site = new Site("Java")。
常量
在Java中,常量和转义字符是编程中经常使用的概念。下面是对这两个概念的详细介绍:
- 常量(Constants) 常量是指在程序运行过程中其值保持不变的量。Java中常量通常使用
final
关键字来定义。常见的常量类型包括:
- 整数常量:如
100
、0
、-25
等。 - 浮点数常量:如
3.14
、0.001
等。 - 字符常量:单个字符用单引号包围,如
'A'
、'b'
、'3'
等。 - 字符串常量:一串字符用双引号包围,如
"Hello, World!"
、"Java"
等。 - 布尔常量:
true
或false
。
final int MAX_VALUE = 100; // 整数常量
final double PI = 3.14159; // 浮点数常量
final char NEWLINE = '\n'; // 字符常量
final String GREETING = "Hello"; // 字符串常量
final boolean FLAG = true; // 布尔常量
- 转义字符(Escape Characters) 转义字符用于表示某些不能直接打印的字符或具有特殊含义的字符。它们通常由反斜杠
\
后跟一个字符来表示。常见的转义字符包括:
\n
:换行符,表示光标移到下一行的开头。\t
:制表符,表示光标移动到下一个水平制表位。\\
:反斜杠字符本身。\'
:单引号字符。\"
:双引号字符。\r
:回车符,表示光标移到本行的开头。\b
:退格符,表示光标向前移动一个字符。\f
:换页符,表示光标移动到下一页。
public class Main {
public static void main(String[] args) {
System.out.println("Hello\nWorld!"); // 输出带换行符的字符串
System.out.println("Tab\tCharacter"); // 输出带制表符的字符串
System.out.println("A single quote: \'"); // 输出带单引号的字符串
System.out.println("A backslash: \\"); // 输出反斜杠
}
}
输出结果:
Hello
World!
Tab Character
A single quote: '
A backslash: \
类型转换
在Java中,数据类型转换是指将一种数据类型的值转换为另一种数据类型的过程。数据类型的转换主要分为两类:自动类型转换(隐式转换)和强制类型转换(显式转换)。
1. 自动类型转换(Implicit Casting)
自动类型转换是指将一种较小范围的数据类型自动转换为较大范围的数据类型。由于这种转换是安全的,Java会在需要时自动执行。例如,将一个int
类型的值赋给long
类型的变量。
规则:
- 从小范围到大范围的数据类型可以自动转换。
- 自动类型转换顺序:
byte
->short
->int
->long
->float
->double
示例:
int intVal = 100;
long longVal = intVal; // int自动转换为long
float floatVal = longVal; // long自动转换为float
double doubleVal = floatVal; // float自动转换为double
2. 强制类型转换(Explicit Casting)
强制类型转换是将一种较大范围的数据类型显式转换为较小范围的数据类型。这种转换可能会导致数据精度丢失,因此需要使用显式的转换操作。
语法:
targetType variableName = (targetType) value;
规则:
- 需要手动指定目标类型。
- 可能会导致数据精度丢失或溢出。
示例:
double doubleVal = 100.99;
float floatVal = (float) doubleVal; // double强制转换为float
long longVal = (long) floatVal; // float强制转换为long
int intVal = (int) longVal; // long强制转换为int
short shortVal = (short) intVal; // int强制转换为short
3. 特殊类型转换
字符与数值类型的转换
字符可以通过其对应的ASCII码值与数值类型相互转换。
示例:
char charVal = 'A';
int intVal = (int) charVal; // 'A' 转换为 65
char anotherChar = (char) (intVal + 1); // 66 转换为 'B'
字符串与基本数据类型的转换
- 字符串转换为基本类型:使用包装类的
parseXXX()
方法。 - 基本类型转换为字符串:使用
String.valueOf()
方法或直接与空字符串相加。
示例:
String numberStr = "123";
int intVal = Integer.parseInt(numberStr); // 字符串转换为int
double doubleVal = Double.parseDouble(numberStr); // 字符串转换为double
int num = 456;
String strVal = String.valueOf(num); // int转换为字符串
String anotherStr = num + ""; // int转换为字符串
4. 类型转换的注意事项
- 数据溢出:在强制类型转换时,如果超出了目标类型的范围,可能会发生数据溢出。
- 精度丢失:浮点数转换为整数时,小数部分会被截断。
示例:
int largeInt = 100000;
byte smallByte = (byte) largeInt; // 可能发生溢出
double largeDouble = 123.456;
int truncatedInt = (int) largeDouble; // 小数部分会被截断,结果为123
变量
在 Java 中,变量是存储数据的容器,可以用于存储各种数据类型的值。Java 变量需要在使用前先声明,声明变量时必须指定变量的类型。根据变量的作用域和生命周期,Java 变量可以分为三种类型:局部变量、实例变量(也称为成员变量或字段)和类变量(也称为静态变量)。
1. 局部变量 (Local Variables)
- 定义:局部变量是在方法、构造方法或代码块中声明的变量。
- 作用域:局部变量的作用域只限于其声明所在的块或方法,方法结束后变量会被销毁。
- 默认值:局部变量在声明后不会被自动初始化,因此在使用之前必须显式地初始化。
- 示例:
public void myMethod() { int age = 25; // age 是一个局部变量 System.out.println(age); }
2. 实例变量 (Instance Variables)
- 定义:实例变量是类中声明,但在方法、构造方法或块之外的变量。每个对象都有自己的一份实例变量的拷贝。
- 作用域:实例变量的作用域是整个类,存在于对象被创建的内存中,直到对象被垃圾回收。
- 默认值:实例变量会有默认值,例如,整型变量的默认值是 0,布尔型变量的默认值是
false
,对象的默认值是null
。 - 示例:
public class Person { String name; // name 是一个实例变量 int age; public void display() { System.out.println(name + " is " + age + " years old."); } }
3. 类变量 (Class Variables)
- 定义:类变量使用
static
关键字声明,是类的所有对象共享的变量。 - 作用域:类变量的作用域是整个类,且存在于所有对象之间共享。它们在类加载时初始化,并在类卸载时销毁。
- 默认值:类变量也会有默认值,和实例变量类似。
- 示例:
public class Person { static int population; // population 是一个类变量 String name; int age; public Person(String name, int age) { this.name = name; this.age = age; population++; } }
变量的声明和初始化
- 声明:在声明变量时,必须指定变量的类型。
int count; // 变量声明
- 初始化:声明变量后,可以给变量赋值。
count = 10; // 变量初始化
- 同时声明和初始化:
int count = 10;
变量命名规则
- 变量名必须以字母、美元符号
$
或下划线_
开头,后续可以包含数字。 - 变量名区分大小写,如
myVar
和myvar
是两个不同的变量。 - 变量名不能是 Java 的关键字,如
class
、public
、static
等。
修饰符
在Java中,修饰符(Modifiers)用于定义类、方法、变量等的可见性、行为或特性。修饰符主要分为两大类:访问修饰符和非访问修饰符。以下是详细介绍:
1. 访问修饰符(Access Modifiers)
访问修饰符控制类、方法、构造函数、和变量的访问级别,即它们在其他类中的可见性。主要有四种访问修饰符:
public
:- 类:可以被所有类访问。
- 方法/变量:可以被所有类访问,无论是在同一包内还是在不同包中。
public class MyClass { public int number; public void show() { // 方法体 } }
protected
:- 方法/变量:可以被同一包中的类访问,也可以被不同包中子类访问。不能用于修饰类。
class MyClass { protected int number; protected void show() { // 方法体 } }
default
(无修饰符):- 类/方法/变量:只有在同一包内的类可以访问,不能被不同包中的类访问。默认访问级别,即不显式指定修饰符时使用此级别。
class MyClass { int number; // 默认访问级别 void show() { // 方法体 } }
private
:- 方法/变量:只能在同一个类中访问,不能被其他类访问。不能用于修饰类。
class MyClass { private int number; private void show() { // 方法体 } }
2. 非访问修饰符(Non-Access Modifiers)
非访问修饰符用于实现类、方法、和变量的其他特性,如静态特性、不可变性、多态性等。主要包括以下几种:
static
:- 方法/变量:表明该成员属于类,而不属于类的实例,可以通过类名直接访问。
static
变量在类的所有实例之间共享。
class MyClass { static int count = 0; // 静态变量 static void show() { // 静态方法 // 方法体 } }
- 方法/变量:表明该成员属于类,而不属于类的实例,可以通过类名直接访问。
final
:- 类:表示该类不能被继承。
- 方法:表示该方法不能被子类重写。
- 变量:表示该变量的值在初始化后不能被修改,必须在声明时或通过构造函数初始化。
final class MyClass { // 该类不能被继承 final int MAX_VALUE = 100; // 常量 final void display() { // 该方法不能被重写 // 方法体 } }
abstract
:- 类:表示该类是抽象类,不能直接实例化,需要通过子类实现其抽象方法。
- 方法:表示该方法没有实现,需要在子类中实现。
abstract class MyClass { abstract void display(); // 抽象方法 } class SubClass extends MyClass { void display() { // 实现抽象方法 } }
synchronized
:- 方法:用于多线程环境,保证在同一时刻只能有一个线程执行该方法,常用于线程安全控制。
class MyClass { synchronized void increment() { // 线程安全的代码 } }
volatile
:- 变量:表示该变量在多个线程间可见,防止线程缓存变量的副本,确保变量的修改能够被其他线程立即看到。
class MyClass { volatile int sharedVariable; }
transient
:- 变量:用于序列化时,表示该变量不需要被序列化(即不会保存到序列化的对象状态中)。
class MyClass implements Serializable { transient int tempValue; // 不会被序列化 }
native
:- 方法:用于声明本地方法,该方法在Java中没有实现,通常用C/C++语言实现。
class MyClass { native void nativeMethod(); // 声明本地方法 }
strictfp
:- 类/方法:用于在浮点运算中强制执行严格的IEEE 754标准,实现跨平台的一致性。
strictfp class MyClass { strictfp void calculate() { // 浮点计算 } }
修饰符的组合
修饰符可以组合使用,以满足特定的访问控制和特性需求。例如:
public final class MyClass {
private static final int MAX_VALUE = 100;
public synchronized void safeMethod() {
// 方法体
}
}
在这个例子中:
MyClass
是public
和final
的,表示它可以被所有类访问,但不能被继承。MAX_VALUE
是private
、static
和final
的,表示它是一个静态常量,只能在本类中访问。safeMethod
是public
和synchronized
的,表示它是一个线程安全的方法,所有类都可以访问。
通过合理使用Java修饰符,可以控制类和成员的可见性、行为和特性,确保代码的安全性、可维护性和扩展性。
运算符
Java运算符用于执行各种操作,如算术运算、比较操作、逻辑判断等。Java中的运算符可以分为以下几大类:
1. 算术运算符(Arithmetic Operators)
这些运算符用于执行基本的数学运算。
运算符 | 描述 | 示例 |
---|---|---|
+ | 加法 | a + b |
- | 减法 | a - b |
* | 乘法 | a * b |
/ | 除法 | a / b |
% | 取模(求余数) | a % b |
++ | 自增(增加1) | a++ 或 ++a |
-- | 自减(减少1) | a-- 或 --a |
++a
(前缀自增)先增加后使用,a++
(后缀自增)先使用后增加。同理,--a
和a--
也是类似的。
2. 赋值运算符(Assignment Operators)
赋值运算符用于将值赋给变量。
运算符 | 描述 | 示例 |
---|---|---|
= | 赋值 | a = b |
+= | 加后赋值 | a += b 相当于 a = a + b |
-= | 减后赋值 | a -= b 相当于 a = a - b |
*= | 乘后赋值 | a *= b 相当于 a = a * b |
/= | 除后赋值 | a /= b 相当于 a = a / b |
%= | 取模后赋值 | a %= b 相当于 a = a % b |
3. 比较运算符(Relational Operators)
比较运算符用于比较两个值的关系,返回一个布尔值(true
或false
)。
运算符 | 描述 | 示例 |
---|---|---|
== | 等于 | a == b |
!= | 不等于 | a != b |
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于等于 | a >= b |
<= | 小于等于 | a <= b |
4. 逻辑运算符(Logical Operators)
逻辑运算符用于执行布尔逻辑操作。
运算符 | 描述 | 示例 |
---|---|---|
&& | 逻辑与(AND) | a && b |
|| | 逻辑或(OR) | a || b |
! | 逻辑非(NOT) | !a |
&&
:如果两个操作数都为true
,结果才为true
。\|\|
:如果两个操作数中至少有一个为true
,结果就为true
。!
:对操作数进行逻辑取反。
5. 位运算符(Bitwise Operators)
位运算符用于对整数类型的二进制位进行操作。
运算符 | 描述 | 示例 |
---|---|---|
& | 按位与(AND) | a & b |
| | 按位或(OR) | a | b |
^ | 按位异或(XOR) | a ^ b |
~ | 按位取反(NOT) | ~a |
<< | 左移运算 | a << 2 |
>> | 右移运算 | a >> 2 |
>>> | 无符号右移 | a >>> 2 |
&
:按位与,两个对应的二进制位都为1,结果才为1。|
:按位或,两个对应的二进制位中有一个为1,结果为1。^
:按位异或,对应的二进制位相同为0,不同为1。~
:按位取反,二进制位取反,0变1,1变0。<<
:左移,二进制位整体左移,低位补0。>>
:右移,二进制位整体右移,符号位保持不变(正数补0,负数补1)。>>>
:无符号右移,二进制位整体右移,高位补0。
6. 三元运算符(Ternary Operator)
三元运算符是一种简洁的条件语句,语法为条件表达式 ? 表达式1 : 表达式2
。如果条件表达式为true
,则返回表达式1的值,否则返回表达式2的值。
int result = (a > b) ? a : b;
7. instanceof运算符
instanceof
运算符用于测试对象是否为特定类的实例。
if (obj instanceof MyClass) {
// 执行代码
}
8. 字符串连接运算符
+
运算符在字符串连接时,也用于将字符串连接在一起。
String result = "Hello, " + "world!";
语句
在Java编程中,循环和分支语句是控制程序流程的基本构造。它们允许你根据条件执行不同的代码块或重复执行某段代码。
1. 分支语句
分支语句根据条件的真或假来决定执行哪一段代码。Java中主要的分支语句有if-else
、switch
。
1.1 if-else
语句
if-else
语句用于在条件为true
时执行某段代码,为false
时执行另一段代码。
int number = 10;
if (number > 0) {
System.out.println("Number is positive");
} else if (number < 0) {
System.out.println("Number is negative");
} else {
System.out.println("Number is zero");
}
if
:条件为真时执行。else if
:可以有多个,用于检查其他条件。else
:当所有if
和else if
条件都为假时执行。
1.2 switch
语句
switch
语句用于基于一个变量的值来执行多个代码分支。
int day = 3;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
default:
System.out.println("Invalid day");
break;
}
case
:与switch
表达式的值匹配时执行对应的代码块。break
:用于退出switch
语句,防止执行下一个case
块。default
:当没有case
匹配时执行。
2. 循环语句
循环语句用于重复执行某段代码,直到满足某个条件。Java中主要的循环语句有for
、while
和do-while
。
2.1 for
循环
for
循环通常用于当循环次数已知时。
for (int i = 0; i < 5; i++) {
System.out.println("i = " + i);
}
- 初始化:在循环开始前执行一次,通常用来初始化循环变量。
- 条件:在每次循环迭代前检查,如果条件为
true
,则继续循环。 - 迭代:在每次循环迭代结束后执行,通常用来更新循环变量。
2.2 增强型for
循环(for-each)
增强型for
循环用于遍历数组或集合。
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
System.out.println(number);
}
2.3 while
循环
while
循环在条件为true
时重复执行某段代码。
int i = 0;
while (i < 5) {
System.out.println("i = " + i);
i++;
}
- 条件:在每次循环前检查,如果条件为
true
,则继续循环。
2.4 do-while
循环
do-while
循环类似于while
循环,但它会先执行一次循环体,然后再检查条件。
int i = 0;
do {
System.out.println("i = " + i);
i++;
} while (i < 5);
- 执行顺序:先执行循环体,再检查条件,这意味着循环体至少会执行一次。
3. 控制循环的语句
Java还提供了一些控制循环执行的语句。
3.1 break
break
语句用于立即退出当前循环。
for (int i = 0; i < 10; i++) {
if (i == 5) {
break; // 退出循环
}
System.out.println(i);
}
3.2 continue
continue
语句用于跳过当前循环的剩余部分,并立即开始下一次迭代。
for (int i = 0; i < 5; i++) {
if (i == 2) {
continue; // 跳过剩余循环体
}
System.out.println(i);
}
4. 嵌套循环和分支
你可以将循环和分支语句嵌套使用,以处理更复杂的逻辑。
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i == j) {
continue; // 跳过当i等于j时的循环
}
System.out.println("i = " + i + ", j = " + j);
}
}
5. 总结
- 分支语句 (
if-else
,switch
) 用于根据条件执行不同的代码块。 - 循环语句 (
for
,while
,do-while
) 用于重复执行代码,直到满足某个条件。 - 控制循环的语句 (
break
,continue
) 用于控制循环的执行流程。
掌握这些语句后,你可以构建出复杂的程序逻辑,处理各种不同的编程任务。
函数(方法)
在Java中,方法(Method)是代码块的封装,用于执行特定任务。方法可以接受参数并返回结果,具有代码重用、简化程序结构的作用。
1. 方法的定义和调用
1.1 定义方法
在Java中,方法的定义通常包括以下几个部分:
- 访问修饰符:如
public
、private
,控制方法的访问范围。 - 返回类型:方法返回的值的数据类型;如果方法不返回值,使用
void
。 - 方法名:用于调用方法的名称。
- 参数列表:方法可以接受的输入,位于括号内,用逗号分隔多个参数。
- 方法体:位于大括号内,包含方法执行的代码。
public class MyClass {
// 无返回值的方法
public void sayHello() {
System.out.println("Hello, World!");
}
// 有返回值的方法
public int add(int a, int b) {
return a + b;
}
}
1.2 调用方法
方法可以通过对象来调用(非静态方法),或者直接调用(静态方法)。
public class Main {
public static void main(String[] args) {
MyClass myClass = new MyClass();
// 调用无返回值的方法
myClass.sayHello();
// 调用有返回值的方法
int result = myClass.add(5, 3);
System.out.println("Result: " + result);
}
}
2. 方法的参数
方法可以接受零个或多个参数,参数列表的定义类似于变量的声明,类型和名称成对出现。
2.1 参数传递
Java中的参数传递是值传递(pass-by-value),即方法接收到的是参数的副本,而不是原始变量。
public void modifyValue(int x) {
x = 10; // 只修改了副本,不会影响原始变量
}
2.2 可变参数
使用...
表示可变参数,这样方法可以接受任意数量的参数(但必须是相同类型)。
public void printNumbers(int... numbers) {
for (int number : numbers) {
System.out.println(number);
}
}
3. 返回值
方法可以返回一个值,使用return
关键字来返回值并结束方法的执行。
3.1 返回基本数据类型
返回值的类型要与方法定义中的返回类型一致。
public int square(int x) {
return x * x;
}
3.2 返回引用数据类型
方法也可以返回对象或数组等引用类型。
public String getGreeting() {
return "Hello, World!";
}
4. 方法的重载
方法的重载(Overloading)指在同一个类中定义多个方法,这些方法具有相同的名称但不同的参数列表(参数类型或参数个数不同)。
public class MyClass {
// 重载方法,接受不同参数类型
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
// 重载方法,接受不同数量的参数
public int add(int a, int b, int c) {
return a + b + c;
}
}
5. 静态方法
静态方法属于类,而不属于实例,可以直接通过类名调用。静态方法不能访问非静态成员变量或调用非静态方法。
public class MathUtils {
public static int multiply(int a, int b) {
return a * b;
}
}
// 调用静态方法
int result = MathUtils.multiply(5, 3);
6. 递归方法
递归方法是指一个方法在其内部调用自身,用于解决一些递归定义的问题,如阶乘、斐波那契数列。
public int factorial(int n) {
if (n == 1) {
return 1;
}
return n * factorial(n - 1);
}
7. 方法的作用域
方法中声明的变量是局部变量,它们只能在方法内访问。方法的参数也被视为局部变量。
public void myMethod() {
int x = 10; // x是局部变量,只能在myMethod中使用
}
8. 方法的修饰符
除了public
和private
等访问修饰符外,方法还可以使用其他修饰符:
static
:静态方法,属于类本身。final
:最终方法,不能被子类重写。abstract
:抽象方法,没有方法体,需要在子类中实现。
9. 总结
Java方法是构建程序功能的基本单位,通过方法可以实现代码重用、结构化编程。掌握方法的定义、调用、参数传递、返回值、重载以及修饰符的使用是学习Java编程的重要部分。
数组
Java数组是存储相同类型数据的容器,通过使用数组,你可以方便地处理大量数据。Java数组具有固定的大小和类型,一旦定义就不能更改。
1. 创建数组
数组可以通过以下方式创建:
1.1 声明和初始化
// 声明一个数组
int[] myArray;
// 分配内存并初始化数组
myArray = new int[5]; // 创建一个长度为5的int数组
或者同时声明和初始化:
int[] myArray = new int[5]; // 创建一个长度为5的int数组
1.2 使用数组字面量初始化
int[] myArray = {1, 2, 3, 4, 5}; // 创建一个包含5个元素的int数组
2. 访问数组元素
数组元素的访问通过索引进行,索引从0
开始。
int[] myArray = {1, 2, 3, 4, 5};
int firstElement = myArray[0]; // 访问第一个元素,值为1
myArray[2] = 10; // 修改第三个元素的值,将其改为10
3. 数组的长度
数组的长度是固定的,可以使用length
属性获取数组的长度。
int[] myArray = {1, 2, 3, 4, 5};
int length = myArray.length; // 数组长度为5
4. 遍历数组
可以使用for
循环或for-each
循环遍历数组中的元素。
4.1 使用for
循环
int[] myArray = {1, 2, 3, 4, 5};
for (int i = 0; i < myArray.length; i++) {
System.out.println(myArray[i]);
}
4.2 使用for-each
循环
int[] myArray = {1, 2, 3, 4, 5};
for (int element : myArray) {
System.out.println(element);
}
5. 多维数组
Java支持多维数组,即数组的数组。
5.1 创建和初始化二维数组
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
或者分步骤创建:
int[][] matrix = new int[3][3]; // 创建一个3x3的二维数组
matrix[0][0] = 1; // 初始化数组元素
5.2 访问和遍历二维数组
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
6. Java中的数组操作
6.1 数组的复制
Java提供了多种方式来复制数组,例如使用System.arraycopy()
方法:
int[] original = {1, 2, 3};
int[] copy = new int[original.length];
System.arraycopy(original, 0, copy, 0, original.length);
6.2 数组的排序
使用Arrays.sort()
方法可以对数组进行排序:
import java.util.Arrays;
int[] numbers = {5, 3, 8, 1, 2};
Arrays.sort(numbers); // 数组将被排序为 [1, 2, 3, 5, 8]
6.3 搜索数组中的元素
可以使用Arrays.binarySearch()
方法在有序数组中搜索元素:
int[] numbers = {1, 2, 3, 5, 8};
int index = Arrays.binarySearch(numbers, 3); // 返回3所在的索引,值为2
7. 常见问题
- 数组越界:访问不存在的索引会抛出
ArrayIndexOutOfBoundsException
异常。
int[] numbers = {1, 2, 3};
int x = numbers[5]; // 会抛出ArrayIndexOutOfBoundsException
- 数组的类型:数组只能存储与声明类型相同的元素。如果尝试存储不同类型的元素,编译时会报错。
int[] numbers = new int[5];
numbers[0] = "Hello"; // 编译错误:类型不匹配
8. 总结
Java数组是一种强大且基础的数据结构,用于存储和操作相同类型的数据。虽然数组大小在声明时是固定的,但它们在许多情况下都非常有用。通过熟练掌握数组的基本操作、遍历、排序和搜索等技能,可以有效地处理各种编程任务。
字符串
在Java中,字符串处理是非常常见的操作。Java提供了三个主要的类来处理字符串:String
、StringBuffer
和 StringBuilder
。每个类都有其特定的用途和特点。让我们详细了解它们的特性和用法。
1. String
类
1.1 特点
- 不可变性:
String
对象是不可变的,一旦创建就无法更改。如果对字符串进行任何修改操作,如拼接、替换,实际上是创建了一个新的字符串对象。 - 字符串常量池:Java中的
String
对象使用字符串常量池来减少内存消耗和提高性能。相同的字符串字面量会引用同一个对象。
1.2 常用方法
public class StringExample {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "World";
// 拼接字符串
String str3 = str1 + " " + str2;
System.out.println(str3); // 输出 "Hello World"
// 获取字符串长度
int length = str3.length();
System.out.println("Length: " + length); // 输出 "Length: 11"
// 字符串比较
boolean isEqual = str1.equals(str2);
System.out.println("Is Equal: " + isEqual); // 输出 "Is Equal: false"
// 查找字符位置
int index = str3.indexOf('o');
System.out.println("Index of 'o': " + index); // 输出 "Index of 'o': 4"
// 提取子字符串
String subStr = str3.substring(6);
System.out.println("Substring: " + subStr); // 输出 "Substring: World"
}
}
2. StringBuffer
类
2.1 特点
- 可变性:
StringBuffer
是可变的,即可以在不创建新对象的情况下修改字符串内容。 - 线程安全:
StringBuffer
是线程安全的,所有对字符串内容的操作都是同步的(synchronized),因此适合多线程环境。
2.2 常用方法
public class StringBufferExample {
public static void main(String[] args) {
StringBuffer buffer = new StringBuffer("Hello");
// 追加字符串
buffer.append(" World");
System.out.println(buffer.toString()); // 输出 "Hello World"
// 插入字符串
buffer.insert(6, "Java ");
System.out.println(buffer.toString()); // 输出 "Hello Java World"
// 替换部分字符串
buffer.replace(6, 10, "C++");
System.out.println(buffer.toString()); // 输出 "Hello C++ World"
// 反转字符串
buffer.reverse();
System.out.println(buffer.toString()); // 输出 "dlroW ++C olleH"
}
}
3. StringBuilder
类
3.1 特点
- 可变性:与
StringBuffer
类似,StringBuilder
也是可变的,可以修改其内容。 - 非线程安全:
StringBuilder
不是线程安全的,因此在单线程环境中使用性能更高。 - 更高性能:在单线程环境下,
StringBuilder
比StringBuffer
更快,因为它没有同步开销。
3.2 常用方法
StringBuilder
的用法与StringBuffer
几乎相同,唯一的区别是StringBuilder
的操作没有同步,因此更适合在性能关键的单线程应用中使用。
public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder builder = new StringBuilder("Hello");
// 追加字符串
builder.append(" World");
System.out.println(builder.toString()); // 输出 "Hello World"
// 插入字符串
builder.insert(6, "Java ");
System.out.println(builder.toString()); // 输出 "Hello Java World"
// 替换部分字符串
builder.replace(6, 10, "C++");
System.out.println(builder.toString()); // 输出 "Hello C++ World"
// 反转字符串
builder.reverse();
System.out.println(builder.toString()); // 输出 "dlroW ++C olleH"
}
}
4. String
vs StringBuffer
vs StringBuilder
- 不可变性:
String
是不可变的,StringBuffer
和StringBuilder
是可变的。 - 线程安全:
StringBuffer
是线程安全的,而String
和StringBuilder
不是。 - 性能:在涉及大量字符串修改的情况下,
StringBuilder
的性能最好,其次是StringBuffer
,String
性能最差(因为每次修改都会创建新对象)。
5. 选择使用哪种类
String
:用于不可变的字符串,或在字符串内容不频繁更改的情况下使用。StringBuffer
:用于多线程环境下频繁修改字符串内容的场景。StringBuilder
:用于单线程环境下需要高性能且频繁修改字符串的场景。
6. 总结
Java中提供的这三种类让开发者可以根据具体的需求选择最适合的字符串处理方式。了解每种类的特点和应用场景,有助于编写更加高效和线程安全的代码。
Number类
在Java中,Number
类是一个抽象类,位于java.lang
包中,是所有数值类的父类。这些数值类包括Integer
、Long
、Float
、Double
、Byte
、Short
等。这些子类为不同的数值类型提供了包装器,使得基本数据类型可以作为对象来处理。
1. Number
类概述
Number
类本身是抽象的,不能直接实例化。它定义了一些通用的方法,这些方法可以在其子类中重写,以便将不同的数值类型转换为其他数值类型。
1.1 常用方法
Number
类定义了将数值类型转换为其他类型的抽象方法,主要包括:
byteValue()
:将数值转换为byte
类型。shortValue()
:将数值转换为short
类型。intValue()
:将数值转换为int
类型。longValue()
:将数值转换为long
类型。floatValue()
:将数值转换为float
类型。doubleValue()
:将数值转换为double
类型。
这些方法在Number
类的子类中被实现,用于将数值转换为相应的基本数据类型。
2. Number
类的子类
Number
类有几个直接的子类,每个子类对应Java中的一个基本数据类型。它们分别是:
Byte
:用于包装byte
类型的值。Short
:用于包装short
类型的值。Integer
:用于包装int
类型的值。Long
:用于包装long
类型的值。Float
:用于包装float
类型的值。Double
:用于包装double
类型的值。
3. 示例代码
以下是使用Number
类及其子类的简单示例:
public class NumberExample {
public static void main(String[] args) {
Integer intValue = 100; // Integer 是 Number 的子类
Double doubleValue = 55.55; // Double 是 Number 的子类
// 使用 Number 类的方法转换类型
System.out.println("Integer as byte: " + intValue.byteValue());
System.out.println("Integer as double: " + intValue.doubleValue());
System.out.println("Double as int: " + doubleValue.intValue());
System.out.println("Double as float: " + doubleValue.floatValue());
// 自动装箱和拆箱示例
int primitiveInt = intValue; // 自动拆箱
Integer newIntValue = primitiveInt; // 自动装箱
System.out.println("Primitive int: " + primitiveInt);
System.out.println("Integer object: " + newIntValue);
}
}
4. 自动装箱和拆箱
- 自动装箱(Autoboxing):Java自动将基本数据类型转换为其对应的包装类型。例如,将
int
转换为Integer
。 - 自动拆箱(Unboxing):Java自动将包装类型转换为其对应的基本数据类型。例如,将
Integer
转换为int
。
Integer intObj = 10; // 自动装箱,将 int 转换为 Integer 对象
int intValue = intObj; // 自动拆箱,将 Integer 对象转换为 int
5. 数值类的用法
Number
类的子类非常有用,尤其是在需要将基本数据类型作为对象处理时。例如,在使用集合(如ArrayList
、HashMap
)时,基本数据类型不能直接存储在集合中,因此需要将它们转换为对应的包装类型。
6. 总结
Number
类是所有数值类型的父类,定义了一些通用的转换方法。Number
类的子类包括Integer
、Double
、Float
等,这些类为基本数据类型提供了包装器,使得它们可以作为对象处理。- 自动装箱和拆箱使得基本数据类型与其包装类型之间的转换更加方便。
通过理解和利用Number
类及其子类,开发者可以更灵活地处理Java中的数值数据。
Math类
Math
类是Java标准库中的一个工具类,位于java.lang
包中,提供了一系列静态方法用于进行数学计算。Math
类的所有方法都是静态的,因此无需创建Math
类的实例即可直接调用这些方法。
1. Math
类概述
1.1 特性
- 静态方法:所有方法都是静态的,意味着可以通过
Math
类直接调用,无需创建对象。 - 常量:提供了一些常用的数学常量,如
Math.PI
和Math.E
。
2. 常用方法
2.1 基本数学运算
Math.abs(x)
:返回x
的绝对值。Math.max(a, b)
:返回a
和b
中的较大值。Math.min(a, b)
:返回a
和b
中的较小值。Math.addExact(a, b)
:返回a
和b
的和,若溢出则抛出异常。Math.subtractExact(a, b)
:返回a
和b
的差,若溢出则抛出异常。Math.multiplyExact(a, b)
:返回a
和b
的积,若溢出则抛出异常.Math.toIntExact(a)
:将long
类型转换为int
,若超出范围则抛出异常。
public class MathExample {
public static void main(String[] args) {
System.out.println("Absolute value of -10: " + Math.abs(-10)); // 10
System.out.println("Max of 5 and 10: " + Math.max(5, 10)); // 10
System.out.println("Min of 5 and 10: " + Math.min(5, 10)); // 5
System.out.println("AddExact(5, 10): " + Math.addExact(5, 10)); // 15
}
}
2.2 三角函数
Math.sin(angle)
:返回角度angle
的正弦值。Math.cos(angle)
:返回角度angle
的余弦值。Math.tan(angle)
:返回角度angle
的正切值。Math.asin(x)
:返回x
的反正弦值。Math.acos(x)
:返回x
的反余弦值。Math.atan(x)
:返回x
的反正切值。Math.toRadians(degrees)
:将角度转换为弧度。Math.toDegrees(radians)
:将弧度转换为角度。
public class TrigonometryExample {
public static void main(String[] args) {
double angle = Math.toRadians(45); // 角度转换为弧度
System.out.println("sin(45 degrees): " + Math.sin(angle));
System.out.println("cos(45 degrees): " + Math.cos(angle));
System.out.println("tan(45 degrees): " + Math.tan(angle));
}
}
2.3 对数和幂运算
Math.exp(x)
:返回e
的x
次幂。Math.log(x)
:返回x
的自然对数。Math.log10(x)
:返回x
的以10为底的对数。Math.pow(base, exponent)
:返回base
的exponent
次幂。Math.sqrt(x)
:返回x
的平方根。
public class LogPowerExample {
public static void main(String[] args) {
System.out.println("e^2: " + Math.exp(2)); // 7.3890560989306495
System.out.println("log(100): " + Math.log(100)); // 4.605170185988092
System.out.println("log10(100): " + Math.log10(100)); // 2.0
System.out.println("2^3: " + Math.pow(2, 3)); // 8.0
System.out.println("Square root of 16: " + Math.sqrt(16)); // 4.0
}
}
2.4 随机数生成
Math.random()
:返回一个范围在[0.0, 1.0)
之间的伪随机double
值。
public class RandomExample {
public static void main(String[] args) {
System.out.println("Random number between 0 and 1: " + Math.random());
}
}
3. 常量
Math.PI
:圆周率π的值。Math.E
:自然对数的底数e的值。
public class ConstantsExample {
public static void main(String[] args) {
System.out.println("Value of PI: " + Math.PI);
System.out.println("Value of E: " + Math.E);
}
}
4. Math
类的使用场景
- 数学计算:
Math
类提供了丰富的数学函数,适用于各种数学计算任务,如科学计算、工程应用等。 - 统计和概率:用于计算随机数、对数、幂等。
- 几何和物理:用于计算角度、距离、物理公式中的数学运算等。
5. 总结
Math
类提供了一系列静态方法用于基本的数学运算,包括三角函数、对数、幂运算和随机数生成等。Math
类的方法不需要创建对象,可以直接调用,且常用的数学常量PI
和E
也包含在其中。- 了解和掌握
Math
类的使用,可以帮助在编程中更高效地进行各种数学计算。
日期时间
在Java中,日期和时间的处理是一个重要的主题,尤其是在涉及到各种时间计算和格式化时。Java提供了多种类来处理日期和时间,主要分为旧的java.util.Date
和java.util.Calendar
类,以及新的java.time
包中的类。
1. java.util.Date
和 java.util.Calendar
1.1 Date
类
java.util.Date
类用于表示一个具体的时刻,精确到毫秒。然而,它已经不推荐使用,因为它设计上存在一些缺陷,如不易处理时区和格式问题。建议使用java.time
包中的类代替。
常用方法:
Date()
:创建一个表示当前时间的Date
对象。Date(long date)
:创建一个表示从1970年1月1日00:00:00 GMT起的毫秒数的Date
对象。getTime()
:返回从1970年1月1日00:00:00 GMT起的毫秒数。setTime(long time)
:设置从1970年1月1日00:00:00 GMT起的毫秒数。
示例代码:
import java.util.Date;
public class DateExample {
public static void main(String[] args) {
Date now = new Date(); // 当前时间
System.out.println("Current date and time: " + now);
long timeInMillis = now.getTime(); // 获取时间戳
System.out.println("Time in milliseconds since January 1, 1970: " + timeInMillis);
Date specificDate = new Date(1000000000000L); // 从1970年1月1日00:00:00 GMT起的秒数
System.out.println("Specific date: " + specificDate);
}
}
1.2 Calendar
类
java.util.Calendar
类提供了对日期和时间的更全面的操作,包括日期的计算和格式化。Calendar
类是抽象类,通常使用其子类GregorianCalendar
。
常用方法:
get(int field)
:获取指定字段的值。set(int field, int value)
:设置指定字段的值。add(int field, int amount)
:增加或减少指定字段的值。getTime()
:获取表示当前日期和时间的Date
对象。
示例代码:
import java.util.Calendar;
public class CalendarExample {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance(); // 获取当前时间的日历对象
System.out.println("Current date and time: " + calendar.getTime());
calendar.add(Calendar.MONTH, 1); // 增加一个月
System.out.println("Date after one month: " + calendar.getTime());
calendar.set(Calendar.YEAR, 2025); // 设置年份
System.out.println("Date in 2025: " + calendar.getTime());
}
}
2. java.time
包
Java 8引入了java.time
包,该包提供了更强大和灵活的日期时间API。主要类包括LocalDate
、LocalTime
、LocalDateTime
、ZonedDateTime
、Duration
和Period
等。
2.1 LocalDate
、LocalTime
和 LocalDateTime
LocalDate
:表示没有时区的日期(年、月、日)。LocalTime
:表示没有时区的时间(时、分、秒)。LocalDateTime
:表示没有时区的日期时间(年、月、日、时、分、秒)。
示例代码:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
public class LocalDateTimeExample {
public static void main(String[] args) {
LocalDate today = LocalDate.now(); // 当前日期
System.out.println("Today's date: " + today);
LocalTime now = LocalTime.now(); // 当前时间
System.out.println("Current time: " + now);
LocalDateTime dateTime = LocalDateTime.now(); // 当前日期时间
System.out.println("Current date and time: " + dateTime);
LocalDate specificDate = LocalDate.of(2024, 8, 19); // 创建指定日期
System.out.println("Specific date: " + specificDate);
}
}
2.2 ZonedDateTime
ZonedDateTime
表示带有时区的日期时间。
示例代码:
import java.time.ZonedDateTime;
import java.time.ZoneId;
public class ZonedDateTimeExample {
public static void main(String[] args) {
ZonedDateTime zonedDateTime = ZonedDateTime.now(); // 当前时区的日期时间
System.out.println("Current date and time with time zone: " + zonedDateTime);
ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC")); // UTC时区的日期时间
System.out.println("UTC date and time: " + utcDateTime);
}
}
2.3 Duration
和 Period
Duration
:表示时间段(以秒和纳秒为单位)。Period
:表示日期段(以年、月、日为单位)。
示例代码:
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Period;
public class DurationPeriodExample {
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.now();
LocalDateTime end = start.plus(Duration.ofHours(5)); // 增加5小时
Duration duration = Duration.between(start, end);
System.out.println("Duration: " + duration.toHours() + " hours");
LocalDateTime today = LocalDateTime.now();
LocalDateTime nextWeek = today.plus(Period.ofWeeks(1)); // 增加一周
Period period = Period.between(today.toLocalDate(), nextWeek.toLocalDate());
System.out.println("Period: " + period.getDays() + " days");
}
}
3. 日期时间格式化
DateTimeFormatter
类用于格式化和解析LocalDate
、LocalTime
、LocalDateTime
等日期时间对象。
示例代码:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterExample {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDate = now.format(formatter);
System.out.println("Formatted date and time: " + formattedDate);
String dateStr = "2024-08-19 12:34:56";
LocalDateTime parsedDate = LocalDateTime.parse(dateStr, formatter);
System.out.println("Parsed date and time: " + parsedDate);
}
}
4. 总结
java.util.Date
和java.util.Calendar
:旧的日期时间类,Date
表示特定时刻,Calendar
提供了更全面的日期时间操作,但它们已经不推荐使用。java.time
包:Java 8引入的新日期时间API,提供了更强大、易用的日期时间操作功能,包括LocalDate
、LocalTime
、LocalDateTime
、ZonedDateTime
等类。DateTimeFormatter
:用于格式化和解析日期时间字符串。
新的java.time
包提供了更好的日期时间处理能力,建议使用java.time
包中的类来处理日期时间问题。
正则表达式
在Java中,正则表达式(regular expressions)用于模式匹配和文本处理。Java的正则表达式功能由java.util.regex
包提供,其中最主要的类包括Pattern
、Matcher
和PatternSyntaxException
。
1. 基本概念
- 正则表达式(Regex):一种文本模式,用于匹配和操作字符串。
- 模式(Pattern):定义了要搜索的文本模式。
- 匹配器(Matcher):用于执行匹配操作,检查文本是否符合模式。
2. 常用正则表达式语法
2.1 元字符
.
:匹配任何单个字符(除了行结束符)。\d
:匹配任何数字,相当于[0-9]
。\D
:匹配任何非数字字符,相当于[^0-9]
。\w
:匹配任何字母数字字符,相当于[a-zA-Z0-9_]
。\W
:匹配任何非字母数字字符,相当于[^a-zA-Z0-9_]
。\s
:匹配任何空白字符,包括空格、制表符、换行符等。\S
:匹配任何非空白字符。^
:匹配输入的开始位置。$
:匹配输入的结束位置。[]
:定义一个字符类,匹配其中的任何一个字符。例如,[abc]
匹配字符a
、b
或c
。|
:逻辑或运算符。例如,a|b
匹配字符a
或b
。()
:分组运算符,用于将模式分组。
2.2 量词
*
:匹配前面的子表达式零次或多次。+
:匹配前面的子表达式一次或多次。?
:匹配前面的子表达式零次或一次。{n}
:匹配前面的子表达式恰好n
次。{n,}
:匹配前面的子表达式至少n
次。{n,m}
:匹配前面的子表达式至少n
次,但不超过m
次。
3. 使用 Pattern
和 Matcher
类
3.1 Pattern
类
Pattern
类是正则表达式的编译表示,提供了与正则表达式相关的操作。
常用方法:
compile(String regex)
:编译正则表达式。matcher(CharSequence input)
:创建一个匹配器来匹配给定的输入序列。
3.2 Matcher
类
Matcher
类用于执行匹配操作。
常用方法:
find()
:尝试查找与正则表达式匹配的子字符串。matches()
:检查整个输入序列是否与正则表达式匹配。group()
:返回最近匹配的子字符串。replaceAll(String replacement)
:用给定的替换字符串替换所有匹配的子字符串。
示例代码:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexExample {
public static void main(String[] args) {
String text = "The price is $123.45";
String regex = "\\$\\d+\\.\\d{2}"; // 匹配货币格式
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println("Found a match: " + matcher.group());
}
// 替换操作
String replacedText = matcher.replaceAll("$100.00");
System.out.println("Replaced text: " + replacedText);
}
}
4. 常见应用场景
- 验证输入:如验证电子邮件地址、电话号码等。
- 文本搜索和替换:在文本中查找和替换符合某些模式的内容。
- 数据提取:从文本中提取特定格式的数据。
5. 示例:验证电子邮件地址
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class EmailValidator {
public static void main(String[] args) {
String email = "example@example.com";
String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
Pattern pattern = Pattern.compile(emailRegex);
Matcher matcher = pattern.matcher(email);
if (matcher.matches()) {
System.out.println(email + " is a valid email address.");
} else {
System.out.println(email + " is not a valid email address.");
}
}
}
6. 总结
- Java中的正则表达式功能由
java.util.regex
包提供,包括Pattern
和Matcher
类。 - 正则表达式用于文本匹配和处理,通过元字符、量词等定义匹配模式。
Pattern
类用于编译正则表达式,Matcher
类用于执行匹配操作。- 正则表达式广泛应用于输入验证、文本搜索和替换等场景。
输入输出
在Java中,用户输入输出(I/O)操作主要包括从用户获取输入和将输出显示给用户。常用的方式有使用Scanner
类来读取用户输入,以及使用System.out
来输出信息。以下是详细的介绍和示例代码:
1. 使用 Scanner
类读取用户输入
Scanner
类是Java提供的一种用于从各种输入源(如键盘、文件等)读取数据的便利工具。它可以读取不同类型的数据,包括整数、浮点数、字符串等。
1.1 基本用法
import java.util.Scanner;
public class ScannerExample {
public static void main(String[] args) {
// 创建Scanner对象来读取输入
Scanner scanner = new Scanner(System.in);
// 读取一个字符串
System.out.print("Enter your name: ");
String name = scanner.nextLine();
System.out.println("Hello, " + name + "!");
// 读取一个整数
System.out.print("Enter your age: ");
int age = scanner.nextInt();
System.out.println("You are " + age + " years old.");
// 读取一个浮点数
System.out.print("Enter your height in meters: ");
double height = scanner.nextDouble();
System.out.println("Your height is " + height + " meters.");
// 关闭Scanner
scanner.close();
}
}
1.2 Scanner
常用方法
next()
: 读取下一个标记(空格分隔)。nextLine()
: 读取整行输入。nextInt()
: 读取下一个整数。nextDouble()
: 读取下一个双精度浮点数。nextBoolean()
: 读取下一个布尔值。
2. 使用 System.out
输出信息
System.out
是 PrintStream
类的一个静态实例,用于输出数据到控制台。常用的方法包括 print()
, println()
, 和 printf()
。
2.1 基本用法
public class PrintStreamExample {
public static void main(String[] args) {
// 输出字符串
System.out.println("Hello, World!");
// 输出整数
int age = 25;
System.out.println("Age: " + age);
// 格式化输出
double height = 1.75;
System.out.printf("Height: %.2f meters%n", height);
}
}
2.2 System.out
常用方法
print()
: 输出指定的内容,不会换行。println()
: 输出指定的内容,并换行。printf()
: 格式化输出,类似于C语言的printf()
函数。
3. 综合示例:用户输入输出
结合使用Scanner
和System.out
来读取用户输入并显示输出:
import java.util.Scanner;
public class UserInputOutputExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取用户输入
System.out.print("Enter your name: ");
String name = scanner.nextLine();
System.out.print("Enter your age: ");
int age = scanner.nextInt();
System.out.print("Enter your height in meters: ");
double height = scanner.nextDouble();
// 输出用户输入的信息
System.out.println("User Information:");
System.out.println("Name: " + name);
System.out.println("Age: " + age);
System.out.printf("Height: %.2f meters%n", height);
scanner.close();
}
}
4. 异常处理
在处理用户输入时,可能会遇到异常,例如用户输入了非整数值而你期望的是整数。可以通过异常处理机制来捕捉这些错误:
import java.util.InputMismatchException;
import java.util.Scanner;
public class InputExceptionHandlingExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int age = 0;
while (true) {
System.out.print("Enter your age: ");
try {
age = scanner.nextInt();
break; // 成功读取整数,退出循环
} catch (InputMismatchException e) {
System.out.println("Invalid input. Please enter a valid integer.");
scanner.next(); // 清除无效输入
}
}
System.out.println("You entered age: " + age);
scanner.close();
}
}
5. 总结
Scanner
类:用于从控制台读取用户输入,可以读取各种数据类型。System.out
:用于将信息输出到控制台,支持基本输出、格式化输出等。- 异常处理:用于处理用户输入错误,确保程序的健壮性。
这些工具和方法可以帮助你处理用户的输入输出需求,并使程序更具交互性和用户友好性。
文件IO
Java中的输入输出(I/O)操作是处理数据读写的重要组成部分。Java提供了一系列类和接口来进行文件和数据流的操作,包括字符流和字节流。以下是Java I/O的基础知识和一些常用的操作示例。
1. 字符流 vs. 字节流
- 字符流:处理字符数据,使用
Reader
和Writer
类。适用于文本文件的读取和写入。 - 字节流:处理原始的字节数据,使用
InputStream
和OutputStream
类。适用于二进制文件的读取和写入。
2. 字符流
2.1 FileReader
和 FileWriter
FileReader
:用于读取字符文件。FileWriter
:用于写入字符文件。
示例代码:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileReaderWriterExample {
public static void main(String[] args) {
// 写入文件
try (FileWriter writer = new FileWriter("example.txt")) {
writer.write("Hello, World!");
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件
try (FileReader reader = new FileReader("example.txt")) {
int ch;
while ((ch = reader.read()) != -1) {
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.2 BufferedReader
和 BufferedWriter
BufferedReader
:用于高效地读取字符数据,提供了缓冲功能。BufferedWriter
:用于高效地写入字符数据,提供了缓冲功能。
示例代码:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedReaderWriterExample {
public static void main(String[] args) {
// 写入文件
try (BufferedWriter writer = new BufferedWriter(new FileWriter("example.txt"))) {
writer.write("Hello, Buffered World!");
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件
try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 字节流
3.1 FileInputStream
和 FileOutputStream
FileInputStream
:用于读取文件的字节数据。FileOutputStream
:用于写入文件的字节数据。
示例代码:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileInputOutputStreamExample {
public static void main(String[] args) {
// 写入文件
try (FileOutputStream fos = new FileOutputStream("example.bin")) {
fos.write("Hello, Binary World!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件
try (FileInputStream fis = new FileInputStream("example.bin")) {
int b;
while ((b = fis.read()) != -1) {
System.out.print((char) b);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.2 BufferedInputStream
和 BufferedOutputStream
BufferedInputStream
:用于高效地读取字节数据,提供了缓冲功能。BufferedOutputStream
:用于高效地写入字节数据,提供了缓冲功能。
示例代码:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedInputOutputStreamExample {
public static void main(String[] args) {
// 写入文件
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("example.bin"))) {
bos.write("Hello, Buffered Binary World!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("example.bin"))) {
int b;
while ((b = bis.read()) != -1) {
System.out.print((char) b);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. 文件操作
4.1 File
类
File
类用于表示文件和目录,并提供了对文件和目录的基本操作。
常用方法:
exists()
:检查文件或目录是否存在。createNewFile()
:创建新文件。delete()
:删除文件或目录。renameTo(File dest)
:重命名文件或目录。listFiles()
:列出目录中的文件和子目录。
示例代码:
import java.io.File;
import java.io.IOException;
public class FileExample {
public static void main(String[] args) {
File file = new File("example.txt");
// 创建新文件
try {
if (file.createNewFile()) {
System.out.println("File created: " + file.getName());
} else {
System.out.println("File already exists.");
}
} catch (IOException e) {
e.printStackTrace();
}
// 检查文件是否存在
if (file.exists()) {
System.out.println("File exists.");
} else {
System.out.println("File does not exist.");
}
// 删除文件
if (file.delete()) {
System.out.println("Deleted the file: " + file.getName());
} else {
System.out.println("Failed to delete the file.");
}
}
}
5. NIO (New I/O)
Java 7引入了java.nio
包,提供了更高效的I/O操作。java.nio
包括了Path
、Files
、ByteBuffer
等类,提供了更强大的文件处理和数据操作能力。
示例代码:
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
public class NIOExample {
public static void main(String[] args) {
Path path = Paths.get("example.txt");
// 写入文件
try {
Files.write(path, "Hello, NIO World!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件
try {
byte[] bytes = Files.readAllBytes(path);
System.out.println(new String(bytes));
} catch (IOException e) {
e.printStackTrace();
}
}
}
6. 总结
- 字符流(
Reader
和Writer
):用于处理字符数据,适用于文本文件。 - 字节流(
InputStream
和OutputStream
):用于处理原始字节数据,适用于二进制文件。 - 缓冲流(
BufferedReader
、BufferedWriter
、BufferedInputStream
、BufferedOutputStream
):提供了缓存功能,提高了I/O效率。 File
类:用于基本的文件和目录操作。- NIO:提供了更高效的I/O操作,包括
Path
、Files
等类。
这些I/O操作和类可以帮助你高效地处理文件和数据流,根据需求选择合适的类和方法进行操作。
异常处理
在Java中,异常处理是管理程序运行时错误的重要机制。通过异常处理,程序可以捕获、处理和恢复错误,防止程序崩溃。Java的异常处理机制基于try-catch
语句块、throw
关键字和自定义异常类。
1. 基本概念
- 异常(Exception):表示程序运行时发生的错误或不正常的情况。
- 异常类(Exception Class):Java的异常是
Throwable
类的子类,主要有Exception
和Error
两类。 - 捕获(Catch):处理异常的过程。
- 抛出(Throw):将异常传递给调用者的过程。
2. 异常处理语法
2.1 try-catch
语句
try
块中包含可能引发异常的代码,catch
块用于捕获和处理这些异常。
示例代码:
public class ExceptionHandlingExample {
public static void main(String[] args) {
try {
int result = 10 / 0; // 可能会引发ArithmeticException
} catch (ArithmeticException e) {
System.out.println("An error occurred: " + e.getMessage());
}
}
}
2.2 finally
语句
finally
块中的代码无论是否发生异常都会执行,通常用于释放资源。
示例代码:
public class FinallyExample {
public static void main(String[] args) {
try {
int result = 10 / 2;
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("An error occurred: " + e.getMessage());
} finally {
System.out.println("This block is always executed.");
}
}
}
2.3 throw
关键字
throw
用于显式地抛出一个异常。
示例代码:
public class ThrowExample {
public static void checkAge(int age) {
if (age < 18) {
throw new IllegalArgumentException("Age must be 18 or older.");
}
}
public static void main(String[] args) {
try {
checkAge(15);
} catch (IllegalArgumentException e) {
System.out.println("Caught exception: " + e.getMessage());
}
}
}
2.4 自定义异常
你可以创建自定义异常类来表示特定的错误条件。自定义异常通常继承Exception
类或其子类。
示例代码:
// 自定义异常类
class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
public class CustomExceptionExample {
public static void test() throws CustomException {
throw new CustomException("This is a custom exception.");
}
public static void main(String[] args) {
try {
test();
} catch (CustomException e) {
System.out.println("Caught custom exception: " + e.getMessage());
}
}
}
3. 异常分类
3.1 检查异常(Checked Exception)
检查异常是在编译时检查的异常。必须要么捕获这些异常,要么在方法签名中声明它们。常见的检查异常包括IOException
、SQLException
等。
3.2 非检查异常(Unchecked Exception)
非检查异常是在运行时检查的异常,不需要在代码中显式地处理或声明。包括RuntimeException
及其子类,例如NullPointerException
、ArrayIndexOutOfBoundsException
等。
4. 异常处理最佳实践
- 只捕获需要处理的异常:不要捕获所有异常,应该只捕获那些你能处理的异常。
- 记录异常信息:在处理异常时,记录详细的异常信息,以便调试。
- 使用自定义异常:对于业务逻辑中的特定错误,可以创建自定义异常类。
- 保持代码清晰:避免过度使用异常,异常应该用来处理意外情况,而不是控制程序流。
5. 总结
try-catch
:用于捕获和处理异常。finally
:用于无论是否发生异常都执行的代码块。throw
:用于显式地抛出异常。- 自定义异常:可以创建特定的异常类来表示特定的错误条件。
- 异常分类:检查异常和非检查异常分别在编译时和运行时处理。
通过适当地使用Java的异常处理机制,可以提高程序的稳定性和可维护性,确保在出现错误时能够优雅地处理问题。