Java 是一种广泛使用的编程语言,具有简单、面向对象、安全、可移植、高性能等特点。以下是 Java 的一些基础语法介绍:
基本结构
Java 程序的基本结构包括类(class)和方法(method)。每个 Java 程序至少有一个类和一个 main
方法,这是程序的入口点。
数据类型
Java 有两种数据类型:原始数据类型(Primitive Data Types)和引用数据类型(Reference Data Types)。
原始数据类型(Primitive Data Types)
数据类型 | 大小 | 默认值 | 范围 |
---|
byte | 8-bit | 0 | -128 到 127 |
short | 16-bit | 0 | -32,768 到 32,767 |
int | 32-bit | 0 | -2^31 到 2^31-1 |
long | 64-bit | 0L | -2^63 到 2^63-1 |
float | 32-bit | 0.0f | IEEE 754 标准浮点数 |
double | 64-bit | 0.0d | IEEE 754 标准浮点数 |
char | 16-bit | ’\u0000’ | 0 到 65,535(字符类型用 Unicode 编码表示) |
boolean | 1-bit | false | 只有两个取值:true 和 false |
引用数据类型(Reference Data Types)
引用数据类型的大小不固定,取决于具体实现和系统架构。常见的引用数据类型包括类、接口和数组。
数据类型 | 描述 |
---|
String | 字符串类型,用于存储文本 |
Array | 数组类型,用于存储相同类型的数据 |
Class | 类类型,用于创建对象 |
Interface | 接口类型,用于定义类的行为规范 |
示例代码
类型转换
在 Java 中,类型转换(Type Casting)是将一种数据类型转换为另一种数据类型的过程。类型转换分为两种:自动类型转换(implicit conversion,也称为 widening conversion)和强制类型转换(explicit conversion,也称为 narrowing conversion)。
1. 自动类型转换
自动类型转换是指将一个较小的数据类型转换为较大的数据类型,这种转换是安全的,不会丢失数据。Java 会自动完成这种类型转换。
示例
自动类型转换规则
byte
→ short
→ int
→ long
→ float
→ double
char
→ int
→ long
→ float
→ double
2. 强制类型转换
强制类型转换是指将一个较大的数据类型转换为较小的数据类型,这种转换可能会导致数据丢失。需要使用显式的类型转换操作符(即在需要转换的值前加上目标类型的括号)。
示例
3. 类型转换中的注意事项
- 数据丢失:强制类型转换时,可能会发生数据丢失。例如,将
double
转换为 int
会丢失小数部分。
- 类型不兼容:某些类型之间的转换是不兼容的,例如不能将
boolean
类型转换为任何其他基本数据类型。
4. 对象类型转换
在 Java 中,对象类型转换主要用于父类与子类之间的转换,分为向上转型(upcasting)和向下转型(downcasting)。
向上转型(Upcasting)
向上转型是指将子类对象转换为父类类型。向上转型是安全的,自动进行。
向下转型(Downcasting)
向下转型是指将父类引用转换为子类类型。向下转型需要显式进行,并且在运行时可能会导致 ClassCastException
,因此需要使用 instanceof
进行类型检查。
5. 字符串与基本数据类型之间的转换
Java 提供了多种方法将字符串转换为基本数据类型,反之亦然。
字符串转换为基本数据类型
可以使用包装类的静态方法实现,如 Integer.parseInt()
、Double.parseDouble()
等。
基本数据类型转换为字符串
可以使用 String.valueOf()
方法或使用字符串连接运算符。
6. 包装类类型转换
Java 提供了对应于每种基本数据类型的包装类,如 Integer
、Double
等。包装类提供了丰富的方法进行类型转换和操作。
基本类型与包装类之间的转换
自动装箱和拆箱是 Java 提供的简化基本类型与包装类之间转换的机制。
字符串格式化
在Java中,字符串格式化可以通过多种方式实现,以下是几种常见的方法:
这是Java中最常用的字符串格式化方法,类似于C语言中的 printf
。
2. 使用 System.out.printf()
这种方法适用于直接输出格式化的字符串。
MessageFormat
类提供了另一种格式化字符串的方法,尤其适用于本地化消息。
4. 使用 StringBuilder
或 StringBuffer
对于更复杂的字符串构建,可以使用 StringBuilder
或 StringBuffer
。
5. 使用 +
运算符进行字符串拼接
对于简单的字符串拼接,可以直接使用 +
运算符,但这种方式在性能上不如 StringBuilder
。
变量
变量是内存中的存储位置,用于存储数据。变量必须先声明后使用。
操作符
以下是 Java 中常见的操作符表格,涵盖了算术操作符、关系操作符、逻辑操作符、位操作符、赋值操作符和其他操作符:
算术操作符(Arithmetic Operators)
操作符 | 描述 | 示例 | 结果 |
---|
+ | 加法 | a + b | a 加 b |
- | 减法 | a - b | a 减 b |
* | 乘法 | a * b | a 乘 b |
/ | 除法 | a / b | a 除以 b |
% | 取模 | a % b | a 除以 b 的余数 |
关系操作符(Relational Operators)
操作符 | 描述 | 示例 | 结果 |
---|
== | 等于 | a == b | 如果 a 等于 b ,则为 true 否则为 false |
!= | 不等于 | a != b | 如果 a 不等于 b ,则为 true 否则为 false |
> | 大于 | a > b | 如果 a 大于 b ,则为 true 否则为 false |
< | 小于 | a < b | 如果 a 小于 b ,则为 true 否则为 false |
>= | 大于等于 | a >= b | 如果 a 大于等于 b ,则为 true 否则为 false |
<= | 小于等于 | a <= b | 如果 a 小于等于 b ,则为 true 否则为 false |
逻辑操作符(Logical Operators)
操作符 | 描述 | 示例 | 结果 |
---|
&& | 逻辑与 | a && b | 如果 a 和 b 都为 true ,则为 true |
|| | 逻辑或 | a || b | 如果 a 或 b 有一个为 true ,则为 true |
! | 逻辑非 | !a | 如果 a 为 true ,则为 false 反之亦然 |
位操作符(Bitwise Operators)
操作符 | 描述 | 示例 | 结果 |
---|
& | 位与 | a & b | 按位与 |
| | 位或 | a | b | 按位或 |
^ | 位异或 | a ^ b | 按位异或 |
~ | 位非 | ~a | 按位取反 |
<< | 左移 | a << 2 | 左移两位 |
>> | 右移 | a >> 2 | 右移两位 |
>>> | 无符号右移 | a >>> 2 | 无符号右移两位 |
赋值操作符(Assignment Operators)
操作符 | 描述 | 示例 | 结果 |
---|
= | 赋值 | a = b | 将 b 的值赋给 a |
+= | 加后赋值 | 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 |
&= | 位与后赋值 | a &= b | a = a & b |
|= | 位或后赋值 | a |= b | a = a | b |
^= | 位异或后赋值 | a ^= b | a = a ^ b |
<<= | 左移后赋值 | a <<= 2 | a = a << 2 |
>>= | 右移后赋值 | a >>= 2 | a = a >> 2 |
>>>= | 无符号右移后赋值 | a >>>= 2 | a = a >>> 2 |
其他操作符(Other Operators)
操作符 | 描述 | 示例 | 结果 |
---|
?: | 三元操作符 | a ? b : c | 如果 a 为 true ,则结果为 b 否则为 c |
instanceof | 类型检查 | obj instanceof Class | 如果 obj 是 Class 类的实例,则为 true |
示例代码
控制结构
条件语句
if
语句
if-else
语句
switch
语句
循环语句
for
循环
while
循环
do-while
循环
数组
数组是存储相同类型数据的容器。
方法
方法是执行特定任务的代码块。
Lambda 表达式
在 Java 中,匿名函数主要通过 Lambda 表达式来实现。Lambda 表达式是一种简洁的函数表示法,允许你在不需要定义明确类和方法的情况下传递行为。
Lambda 表达式的语法
Lambda 表达式的基本语法如下:
或
示例和用法
以下是一些使用 Lambda 表达式的常见场景和示例:
1. 使用 Lambda 表达式实现接口
通常,Lambda 表达式用于实现只有一个抽象方法的接口(即函数式接口)。Java 提供了几个内置的函数式接口,例如 Runnable
,Callable
,Comparator
等。
示例:使用 Runnable
接口
2. 使用 Lambda 表达式进行集合操作
Lambda 表达式与 Java 8 引入的 Stream API
结合使用,可以简化对集合的操作。
示例:对列表进行过滤和迭代
3. 使用自定义函数式接口
你可以创建自己的函数式接口,并使用 Lambda 表达式来实现它们。
示例:自定义函数式接口
4. 使用内置函数式接口
Java 8 提供了一些通用的函数式接口,如 Predicate
,Function
,Consumer
,Supplier
等。
示例:使用 Predicate
进行过滤
面向对象编程(OOP)
Java 是一种面向对象编程语言,主要包括以下概念:
- 类(Class):描述对象的蓝图。
- 对象(Object):类的实例。
- 继承(Inheritance):一个类可以继承另一个类的属性和方法。
- 多态(Polymorphism):对象可以以多种形式出现。
- 封装(Encapsulation):隐藏对象的实现细节。
- 抽象(Abstraction):只暴露对象的功能,而隐藏实现细节。
单继承
Java 中的类只能有一个直接父类,也就是说 Java 不支持多继承。每个类只能继承一个类,但可以实现多个接口。
访问修饰符的继承规则
- public:公共成员可以被任何类访问和继承。
- protected:受保护成员可以被同一包中的类和任何子类访问和继承。
- default(无修饰符):默认成员仅限于同一包中的类访问和继承。
- private:私有成员不能被其他类访问和继承,即使是子类也不能直接访问父类的私有成员,但可以通过公共或保护的方法访问。
final 关键字
使用 final
关键字修饰的类不能被继承,使用 final
关键字修饰的方法不能被子类重写。
构造器的继承
构造器不能被继承,但是子类的构造器可以调用父类的构造器。调用父类构造器使用 super
关键字,必须在子类构造器的第一行。
多重继承的替代:接口
虽然 Java 不支持类的多重继承,但可以通过接口来实现。一个类可以实现多个接口,从而在一定程度上达到多重继承的效果。
抽象类和抽象方法
- 抽象类:不能被实例化,只能被继承。抽象类可以包含抽象方法(没有方法体的方法)和非抽象方法。
方法的重写(Override)
子类可以重写父类的方法,但必须保持方法签名(方法名称和参数列表)一致,同时不能缩小访问权限。
泛型编程
泛型类
泛型类是具有一个或多个类型参数的类。类型参数用尖括号 <>
括起来,并且可以在类声明中使用。
在上述代码中,GenericBox
是一个泛型类,T
是类型参数。可以创建不同类型的 GenericBox
实例,如 GenericBox<Integer>
和 GenericBox<String>
。
泛型方法
泛型方法是在方法声明中使用类型参数的方法。类型参数可以用在方法的返回类型和参数列表中。
在上述代码中,printArray
方法是一个泛型方法,<T>
是类型参数,方法可以处理任何类型的数组。
有界类型参数
有界类型参数允许你限制类型参数必须是某种类型的子类(或实现某个接口)。可以使用关键字 extends
定义有界类型参数。
在上述代码中,printNumber
方法的类型参数 T
被限制为 Number
类或其子类。
泛型接口
泛型接口是具有类型参数的接口。实现泛型接口的类可以指定具体的类型参数。
在上述代码中,GenericInterface
是一个泛型接口,GenericClass
实现了该接口。
通配符
通配符(wildcards)用于表示不确定的类型,有三种常见的使用方式:
- 有界通配符(上界)
<? extends T>
:表示类型是 T
或 T
的子类。
- 有界通配符(下界)
<? super T>
:表示类型是 T
或 T
的父类。
泛型的类型擦除
Java 的泛型在编译时会进行类型擦除,这意味着在运行时,所有的类型参数都会被替换为它们的上界(如果没有指定上界,则替换为 Object
)。因此,无法在运行时获取泛型的实际类型参数。
反射
Java 的反射机制允许在运行时检查和操作类、方法、字段和构造器等。这使得程序能够在运行时动态地发现和使用类的成员。反射主要用于框架、工具、库等需要动态加载和操作类的场景。以下是 Java 反射的一些关键概念和用法:
获取类对象
反射的起点是获取 Class
对象,可以通过以下三种方式之一获得:
创建实例
使用反射创建类的实例:
获取和操作字段
通过反射获取类的字段并操作它们:
获取和调用方法
通过反射获取类的方法并调用它们:
获取和调用构造器
通过反射获取类的构造器并调用它们:
获取类信息
通过反射获取类的基本信息,如字段、方法、构造器和父类等。
获取私有属性和方法
在 Java 中,通过反射可以访问和操作私有属性和方法。为了访问私有属性和方法,需要将其设置为可访问状态。以下是详细的示例,展示了如何使用反射获取和操作私有属性和方法:
示例类
获取和操作私有属性
获取和调用私有方法
异常处理
在 Java 中,异常处理是确保程序在运行时能够正确处理错误和异常情况的重要机制。通过使用异常处理,可以在错误发生时提供适当的反馈和采取相应的措施,而不是让程序崩溃。
异常处理的基本概念
- 异常:异常是指程序执行过程中发生的异常情况,可能是程序错误、用户输入错误或其他无法预见的情况。
- 异常类:所有异常类都继承自
java.lang.Throwable
。异常类分为两类:Error
和 Exception
。
Error
:表示严重错误,通常由 JVM 抛出,程序不应该捕获这些错误。
Exception
:表示程序可以捕获并处理的异常。
捕获和处理异常
Java 提供了 try
、catch
、finally
和 throw
关键字来捕获和处理异常。
基本语法
示例代码
自定义异常
可以通过继承 Exception
类来创建自定义异常。
自定义异常类
抛出自定义异常
使用 throws
声明异常
如果一个方法可能会抛出异常,但不处理它,可以使用 throws
关键字在方法声明中指出该异常。