java基础
一些基本的:
1:java中文件名要与类名一致
2:编译文件:Java文件运行前需要先编译为 class 字节码文件,如:
$ javac HelloWorld.java //使用javac指令编译,运行javac命令后,如果成功编译没有错误的话,会出现一个 HelloWorld.class 的文件
3:运行文件:用java指令,java后面跟的是类名而不是文件名,如:
$ java HelloWorld //运行编译好的class文件
基础语法:
一个简单程序:
public class HelloWorld {
/* 第一个Java程序
* 它将输出字符串 Hello World
*/
public static void main(String[] args) {
System.out.println("Hello World"); // 输出 Hello World
}
}
1:java中对于方法的定义:
例:
public static void main(String[] args)
规则:类似c语言定义函数

2:大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的。
3:类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。
4:方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
5:源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为 .java。(如果文件名和类名不相同则会导致编译错误)。
6:主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行。
Java 标识符:
Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。
关于 Java 标识符,有以下几点需要注意:
- 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始
- 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线(_)或数字的任何字符组合
- 关键字不能用作标识符
- 标识符是大小写敏感的
- 合法标识符举例:age、$salary、_value、__1_value
- 非法标识符举例:123abc、-salary
Java修饰符
像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
- 访问控制修饰符 : default, public , protected, private
- 非访问控制修饰符 : final, abstract, static, synchronized
在后面的章节中我们会深入讨论 Java 修饰符。
Java 变量
Java 中主要有如下几种类型的变量
- 局部变量
- 类变量(静态变量)
- 成员变量(非静态变量)
Java 数组
数组是储存在堆上的对象,可以保存多个同类型变量。在后面的章节中,我们将会学到如何声明、构造以及初始化一个数组。
Java 枚举
Java 5.0引入了枚举,枚举限制变量只能是预先设定好的值。使用枚举可以减少代码中的 bug。
例如,我们为果汁店设计一个程序,它将限制果汁为小杯、中杯、大杯。这就意味着它不允许顾客点除了这三种尺寸外的果汁。
例:
class FreshJuice {
enum FreshJuiceSize{ SMALL, MEDIUM , LARGE }
FreshJuiceSize size;
}
public class FreshJuiceTest {
public static void main(String[] args){
FreshJuice juice = new FreshJuice();
juice.size = FreshJuice.FreshJuiceSize.MEDIUM ;
}
}
Java 关键字
下面列出了 Java 关键字。这些保留字不能用于常量、变量、和任何标识符的名称。
| 类别/关键字 | 说明 |
|---|---|
| 访问控制 | |
| private | 私有的 |
| protected | 受保护的 |
| public | 公共的 |
| default | 默认 |
| 类、方法和变量修饰符 | |
| abstract | 声明抽象 |
| class | 类 |
| extends | 扩充、继承 |
| final | 最终值、不可改变的 |
| implements | 实现(接口) |
| interface | 接口 |
| native | 本地、原生方法(非 Java 实现) |
| new | 创建 |
| static | 静态 |
| strictfp | 严格浮点、精准浮点 |
| synchronized | 线程、同步 |
| transient | 短暂 |
| volatile | 易失 |
| 程序控制语句 | |
| break | 跳出循环 |
| case | 定义一个值以供 switch 选择 |
| continue | 继续 |
| do | 运行 |
| else | 否则 |
| for | 循环 |
| if | 如果 |
| instanceof | 实例 |
| return | 返回 |
| switch | 根据值选择执行 |
| while | 循环 |
| 错误处理 | |
| assert | 断言表达式是否为真 |
| catch | 捕捉异常 |
| finally | 有没有异常都执行 |
| throw | 抛出一个异常对象 |
| throws | 声明一个异常可能被抛出 |
| try | 捕获异常 |
| 包相关 | |
| import | 引入 |
| package | 包 |
| 基本类型 | |
| boolean | 布尔型 |
| byte | 字节型 |
| char | 字符型 |
| double | 双精度浮点 |
| float | 单精度浮点 |
| int | 整型 |
| long | 长整型 |
| short | 短整型 |
| 变量引用 | |
| super | 父类、超类 |
| this | 本类 |
| void | 无返回值 |
| 保留关键字 | |
| goto | 是关键字,但不能使用 |
| const | 是关键字,但不能使用 |
注意:Java 的 null 不是关键字,类似于 true 和 false,它是一个字面常量,不允许作为标识符使用。
注释:
单行://
多行:/**/
继承(New):
在 Java 中,一个类可以由其他类派生。如果你要创建一个类,而且已经存在一个类具有你所需要的属性或方法,那么你可以将新创建的类继承该类。
利用继承的方法,可以重用已存在类的方法和属性,而不用重写这些代码。被继承的类称为超类(super class),派生类称为子类(sub class)。
接口:
在 Java 中,接口可理解为对象间相互通信的协议。接口在继承中扮演着很重要的角色。
接口只定义派生要用到的方法,但是方法的具体实现完全取决于派生类。
对象和类:
java支持对象和类,其中类定义对象蓝图(模板),有属性和方法,对象是类的实例,有状态和行为
类的类型变量:
- 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
- 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
- 类变量:类变量也声明在类中,方法体之外,但必须声明为 static 类型。
方法:
- 定义类的行为,包含在类中的函数。
- 示例:
public void displayInfo() { System.out.println("Info"); }
构造方法:用于在创建对象时为其初始化。一个类都至少有一个以上的构造方法,若未显式定义,那么Java 编译器将会为该类提供一个默认构造方法。在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名。
例:
public class Puppy{
public Puppy(){
}
public Puppy(String name){
// 这个构造器仅有一个参数:name
}
}
创建对象:
对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:
- 声明:声明一个对象,包括对象名称和对象类型。
- 实例化:使用关键字 new 来创建一个对象。
- 初始化:使用 new 创建对象时,会调用构造方法初始化对象。
例:
public class Puppy{
public Puppy(String name){
//这个构造器仅有一个参数:name
System.out.println("小狗的名字是 : " + name );
}
public static void main(String[] args){
// 下面的语句将创建一个Puppy对象
Puppy myPuppy = new Puppy( "tommy" );
}
}
封装:将对象的状态私有化,然后通过公共方法私有化
例:
private String name;
public String getName() { return name; }
多态:
方法可以表现为多种形态,主要通过方法重载和方法重写实现
方法重载:在同一个类中,允许存在多个同名方法,但这些方法的参数列表必须不同(参数类型、参数个数或参数顺序不同)。
例:
public class Calculator {
// 1. 参数个数不同
public int add(int a, int b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
// 2. 参数类型不同
public double add(double a, double b) {
return a + b;
}
public String add(String a, String b) {
return a + b;
}
// 3. 参数顺序不同(注意:只有当参数类型不同时才有意义)
public void printInfo(String name, int age) {
System.out.println("Name: " + name + ", Age: " + age);
}
public void printInfo(int age, String name) {
System.out.println("Age: " + age + ", Name: " + name);
}
}
方法重写:子类重新定义父类中已有的方法,方法名、参数列表和返回类型都必须相同,但方法体(实现)不同。
例:
// 父类
class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
// 可被重写的方法
public void makeSound() {
System.out.println(name + " makes a sound");
}
public Object getInfo() {
return "Animal: " + name;
}
// private方法不能被重写
private void secretMethod() {
System.out.println("This is secret");
}
// final方法不能被重写
public final void sleep() {
System.out.println(name + " is sleeping");
}
// static方法不能被重写(但可以被隐藏)
public static void eat() {
System.out.println("Animal is eating");
}
}
// 子类
class Dog extends Animal {
public Dog(String name) {
super(name);
}
// ✅ 正确重写:访问权限相同
@Override
public void makeSound() {
System.out.println(name + " barks: Woof! Woof!");
}
// ✅ 协变返回类型:返回类型是父类返回类型的子类
@Override
public String getInfo() {
return "Dog: " + name;
}
// ✅ 访问权限更宽松
@Override
protected void makeSound() { // ❌ 错误!不能更严格,但可以更宽松
// 实际上这里会编译错误,因为从public改为protected是更严格了
}
// ❌ 错误示例:参数列表不同(这是重载,不是重写)
public void makeSound(String sound) {
System.out.println(name + " makes sound: " + sound);
}
// static方法的"重写"实际上是隐藏
public static void eat() {
System.out.println("Dog is eating bones");
}
}
抽象类和接口:
抽象类:
定义:用 abstract 关键字修饰的类,称为抽象类。 它不能被直接实例化(不能用 new Shape() 创建对象)。
特点:
1:可以包含 抽象方法(只有声明,没有方法体)
2:也可以包含 具体方法(有完整实现)
3:可以有字段、构造器、静态方法等
4:子类必须 重写(override)所有抽象方法,否则子类也必须声明为 abstract
例:
public abstract class Shape {
// 抽象方法:没有方法体,以分号结束
abstract void draw();
// 具体方法(可选)
public void display() {
System.out.println("This is a shape.");
}
}
// ❌ 错误:不能直接创建抽象类的对象
// Shape s = new Shape(); // 编译错误!
// ✅ 正确:创建子类并实现抽象方法
class Circle extends Shape {
@Override
void draw() {
System.out.println("Drawing a circle.");
}
}
// 测试
public class Main {
public static void main(String[] args) {
Shape circle = new Circle(); // 向上转型
circle.draw(); // 输出: Drawing a circle.
circle.display(); // 输出: This is a shape.
}
}
接口:
定义:接口是一个完全抽象的类,用于定义一组行为规范。
特点:
1:所有方法默认是 public abstract(即使不写)
2:所有字段默认是 public static final(即常量)
3:可以有 default 方法(带实现)
4:可以有 static 方法(带实现)
5:一个类可以实现多个接口(解决 Java 单继承的限制)
例:
public interface Animal {
// 抽象方法(隐式 public abstract)
void eat();
// 常量(隐式 public static final)
String CATEGORY = "Living Being";
// 默认方法(Java 8+)
default void breathe() {
System.out.println("Animal is breathing.");
}
}
class Dog implements Animal {
@Override
public void eat() {
System.out.println("Dog eats bones.");
}
// breathe() 方法可以直接使用,无需重写
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // 输出: Dog eats bones.
dog.breathe(); // 输出: Animal is breathing.
System.out.println(Animal.CATEGORY); // 输出: Living Being
}
}
反射:
Java 反射(Reflection)是一个强大的特性,它允许程序在运行时查询、访问和修改类、接口、字段和方法的信息。反射提供了一种动态地操作类的能力,这在很多框架和库中被广泛使用,例如Spring框架的依赖注入。
反射 API:
Java 的反射 API 提供了一系列的类和接口来操作 Class 对象。主要的类包括:
java.lang.Class:表示类的对象。提供了方法来获取类的字段、方法、构造函数等。java.lang.reflect.Field:表示类的字段(属性)。提供了访问和修改字段的能力。java.lang.reflect.Method:表示类的方法。提供了调用方法的能力。java.lang.reflect.Constructor:表示类的构造函数。提供了创建对象的能力。
流程:获取class对象->获取成员信息->操作成员
获取class对象(三种方法):
通过类字面量
Class<?> clazz = String.class;
通过对象实例:
String str = "Hello";
Class<?> clazz = str.getClass();
通过 Class.forName() 方法:
Class<?> clazz = Class.forName("java.lang.String");
//<?>:无界通配符,表示可以引用任意类型的类对象
创建对象:
Class<?> clazz = Class.forName("java.lang.String");
Object obj = clazz.getDeclaredConstructor().newInstance();
访问字段:
Class<?> clazz = Person.class;
Field field = clazz.getDeclaredField("name");//此时filed代表name键本身
field.setAccessible(true); // 如果字段是私有的,需要设置为可访问
Object value = field.get(personInstance); // 获取Person类的实例personInstance对象的name字段值,用value储存
field.set(personInstance, "New Name"); // 设置personInstance对象name键新的字段值
调用方法:
Class<?> clazz = Person.class;
Method method = clazz.getMethod("sayHello");
method.invoke(personInstance);//在该实例上执行sayHello方法
Method methodWithArgs = clazz.getMethod("greet", String.class);
methodWithArgs.invoke(personInstance, "World");//用World参数执行greet方法
获取构造参数:
Class<?> clazz = Person.class;
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);//告知参数类型
Object obj = constructor.newInstance("John", 30);
获取接口和父类:
Class<?> clazz = Person.class;
// 获取所有接口
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> i : interfaces) {
System.out.println("Interface: " + i.getName());
}
// 获取父类
Class<?> superClass = clazz.getSuperclass();
System.out.println("Superclass: " + superClass.getName());
java.lang.reflect 包中的主要类和接口的详细介绍:
1. Class 类
- 功能:表示类的对象,提供了获取类信息的方法,如字段、方法、构造函数等。
- 主要方法:
getFields():获取所有公共字段。getDeclaredFields():获取所有声明的字段,包括私有字段。getMethods():获取所有公共方法。getDeclaredMethods():获取所有声明的方法,包括私有方法。getConstructors():获取所有公共构造函数。getDeclaredConstructors():获取所有声明的构造函数,包括私有构造函数。getSuperclass():获取类的父类。getInterfaces():获取类实现的所有接口。
2. Field 类
- 功能:表示类的字段(属性),提供了访问和修改字段值的方法。
- 主要方法:
get(Object obj):获取指定对象的字段值。set(Object obj, Object value):设置指定对象的字段值。getType():获取字段的数据类型。getModifiers():获取字段的修饰符(如 public、private)。
3. Method 类
- 功能:表示类的方法,提供了调用方法的能力。
- 主要方法:
invoke(Object obj, Object... args):调用指定对象的方法。getReturnType():获取方法的返回类型。getParameterTypes():获取方法的参数类型。getModifiers():获取方法的修饰符(如 public、private)。
4. Constructor 类
- 功能:表示类的构造函数,提供了创建对象的能力。
- 主要方法:
newInstance(Object... initargs):创建一个新实例,使用指定的构造函数参数。getParameterTypes():获取构造函数的参数类型。getModifiers():获取构造函数的修饰符(如 public、private)。
用反射动态执行shell:
Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")),"cmd /c start");
//获取Runtime类的exec方法并调用,由于exec是实例方法,必须依附于对象运行,故传入一个调用Runtime的getRuntime方法得到的runtime单例,同时传入要执行的命令参数
利用反射修改final修饰字段:
class Example {
private final String message = "Initial Value";
public String getMessage() {
return message;
}
}
public class ModifyFinalField {
public static void main(String[] args) throws Exception {
Example example = new Example();
// 输出原始值
System.out.println("Before modification: " + example.getMessage());
// 获取 Example 类中 message 字段的 Field 对象
Field messageField = Example.class.getDeclaredField("message");
// 设置为可访问
messageField.setAccessible(true);
// 修改 final 字段的值
Field modifiersField = Field.class.getDeclaredField("modifiers");
//这个 modifiers 字段存储了当前字段的所有修饰符标志位(如 private=2, final=16, static=8 等的二进制组合)。
modifiersField.setAccessible(true);
// 清除 final 修饰符的影响
modifiersField.setInt(messageField, messageField.getModifiers() & ~java.lang.reflect.Modifier.FINAL);
//按位与运算。这将保留其他所有标志位,但强制将 FINAL 对应的那一位变成 0,修改字段值修改字段值后不在再被认为是final
messageField.set(example, "Modified Value");
// 输出修改后的值
System.out.println("After modification: " + example.getMessage());
}
}
源文件声明规则:
最后,我们将学习源文件的声明规则。当在一个源文件中定义多个类,并且还有 import 语句和 package 语句时,要特别注意这些规则。
- 一个源文件中只能有一个 public 类
- 一个源文件可以有多个非 public 类
- 源文件的名称应该和 public 类的类名保持一致。例如:源文件中 public 类的类名是 Employee,那么源文件应该命名为Employee.java。
- 如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。
- 如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面。
- import 语句和 package 语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。
类有若干种访问级别,并且类也分不同的类型:抽象类和 final 类等。这些将在访问控制章节介绍。
除了上面提到的几种类型,Java 还有一些特殊的类,如:内部类、匿名类。
基本数据类型:
整数:
byte:-128到127
例:byte a = 100,byte b = -50
short:-32768到32767
例:short s = 1000,short r = -20000
int:-2,147,483,648到2,147,483,647
例:int a = 100000, int b = -200000
long:-9,223,372,036,854,775,808到9,223,372,036,854,775,807
例:long a = 100000L,long b = -200000L
浮点数:
float:1.17549435e-38 到 3.4028235e38
例:float f1 = 234.5f
double:2.2250738585072014 × 10⁻³⁰⁸到1.7976931348623157 × 10³⁰⁸
例:double d3 = 8.0d
boolean:布尔值,只有true/false,默认为false
char:略
变量:
在 Java 语言中,所有的变量在使用前必须声明。
声明变量的基本格式如下:
type identifier = value;
格式说明:
- type — 数据类型。
- identifier — 是变量名,可以使用逗号 , 隔开来声明多个同类型变量。
例:
int a, b, c; // 声明三个int型整数:a、 b、c
int d = 3, e = 4, f = 5; // 声明三个整数并赋予初值
byte z = 22; // 声明并初始化 z
String s = "runoob"; // 声明并初始化字符串 s
double pi = 3.14159; // 声明了双精度浮点型变量 pi
char x = 'x'; // 声明变量 x 的值是字符 'x'。
Java 语言支持的变量类型有:
局部变量(Local Variables):局部变量是在方法、构造函数或块内部声明的变量,它们在声明的方法、构造函数或块执行结束后被销毁,局部变量在声
明时需要初始化,否则会导致编译错误。
实例变量(Instance Variables):实例变量是在类中声明,但在方法、构造函数或块之外,它们属于类的实例,每个类的实例都有自己的副本,如果不明
确初始化,实例变量会被赋予默认值(数值类型为0,boolean类型为false,对象引用类型为null)。
静态变量或类变量(Class Variables):类变量是在类中用 static 关键字声明的变量,它们属于类而不是实例,所有该类的实例共享同一个类变量的值,
类变量在类加载时被初始化,而且只初始化一次。
参数变量(Parameters):参数是方法或构造函数声明中的变量,用于接收调用该方法或构造函数时传递的值,参数变量的作用域只限于方法内部。
修饰符:
访问修饰符:
类型:
-
default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
-
private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
-
public : 对所有类可见。使用对象:类、接口、变量、方法
-
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
访问修饰符的继承:
-
父类中声明为 public 的方法在子类中也必须为 public。
-
父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
-
父类中声明为 private 的方法,不能够被子类继承。
非访问修饰符:
-
static 修饰符,用来修饰类方法和类变量。
-
静态变量:
static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。 -
静态方法:
static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。
-
-
final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
-
abstract 修饰符,用来创建抽象类和抽象方法。
-
synchronized 和 volatile 修饰符,主要用于线程的编程。
-
synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。
-
volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
-
synchronized 和 volatile 修饰符的例子:
//synchronized
public synchronized void showDetails(){
.......
}
//volatile
public class MyRunnable implements Runnable
{
private volatile boolean active;
public void run()
{
active = true;
while (active) // 第一行
{
// 代码
}
}
public void stop()
{
active = false; // 第二行
}
}
运算符优先级(从高到低):

循环,条件语句,switch case:略(跟c一样,while,do while那些)
Number & Math 类:
Number类:
一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte、int、long、double 等。但我们实际开发常会用到对象,Java 语言为每一个内置数据类型提供了对应的包装类。所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类 Number 的子类。Number 是一个抽象基类(不能直接实例化,所有抽象类都不能),用于统一所有数值类型的公共行为,实现“多态”和“泛化编程”
包装类的功能:
-
用于集合和泛型
-
支持 null 值
-
提供丰富的工具方法
-
支持反射和注释
-
实现多态和继承
类型:
| 类名 | 对应基本类型 | 描述 |
|---|---|---|
| Byte | byte | 字节型包装类 |
| Short | short | 短整型包装类 |
| Integer | int | 整型包装类 |
| Long | long | 长整型包装类 |
| Float | float | 单精度浮点型包装类 |
| Double | double | 双精度浮点型包装类 |
| BigInteger | – | 不可变任意精度整数 |
| BigDecimal | – | 不可变任意精度有符号十进制数 |
统一方法:
转换方法:
实现:
public abstract class Number implements Serializable {
// 抽象方法
public abstract int intValue();
public abstract long longValue();
public abstract float floatValue();
public abstract double doubleValue();
// Java 8 新增
public byte byteValue() {
return (byte)intValue();
}
public short shortValue() {
return (short)intValue();
}
}
这样强制各个子类实现转换的方法
例:
Number num = 1234.56; // 实际是Double类型
System.out.println(num.intValue()); // 1234 (截断小数)
System.out.println(num.longValue()); // 1234
System.out.println(num.floatValue()); // 1234.56
System.out.println(num.doubleValue()); // 1234.56
自动装箱与拆箱:
当内置数据类型被当作对象使用的时候,编译器会把内置类型装箱为包装类。相似的,编译器也可以把一个对象拆箱为内置类型。这个过程是自动的
例:
public class Test{
public static void main(String[] args){
Integer x = 5;
x = x + 10;
System.out.println(x);
}
}
//以上实例编译运行结果:15
当 x 被赋为整型值时,由于x是一个对象,所以编译器要对x进行装箱。然后,为了使x能进行加运算,所以要对x进行拆箱。
// 自动装箱
Integer autoBoxed = 42; // 编译器转换为 Integer.valueOf(42)
// 自动拆箱
int autoUnboxed = autoBoxed; // 编译器转换为 autoBoxed.intVal
数值比较:
例:
java
Integer x = 10;
Double y = 10.0;
// 正确比较方式:转换为同一类型后比较
System.out.println(x.doubleValue() == y.doubleValue()); // true
处理大数:
BigInteger bigInt = new BigInteger("12345678901234567890");
BigDecimal bigDec = new BigDecimal("1234567890.1234567890");
// 大数运算
BigInteger sum = bigInt.add(new BigInteger("1"));
BigDecimal product = bigDec.multiply(new BigDecimal("2"));
数值格式化:
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(2);
System.out.println(nf.format(1234.5678)); // "1,234.57"
Math类:
Math 类是 Java 提供的数学工具类,位于 java.lang 包中,包含执行基本数值运算的静态方法。
Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。
Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用。
正余弦:
public class Test {
public static void main (String []args)
{
System.out.println("90 度的正弦值:" + Math.sin(Math.PI/2));
System.out.println("0度的余弦值:" + Math.cos(0));
System.out.println("60度的正切值:" + Math.tan(Math.PI/3));
System.out.println("1的反正切值: " + Math.atan(1));
System.out.println("π/2的角度值:" + Math.toDegrees(Math.PI/2));
System.out.println(Math.PI);
}
}
指数对数运算:
Math.exp(1); // e^1 ≈ 2.718
Math.log(Math.E); // ln(e) = 1
Math.log10(100); // log10(100) = 2
随机数生成:
// 生成[0.0, 1.0)之间的随机数
double random = Math.random();
// 生成[1, 100]的随机整数
int randomInt = (int)(Math.random() * 100) + 1;
其他运算:
Math.hypot(3, 4); // 计算sqrt(x²+y²) → 5.0
Math.IEEEremainder(10, 3); // IEEE余数 → 1.0
常量字段:
Math.PI; // π ≈ 3.141592653589793
Math.E; // 自然对数底数e ≈ 2.718281828459045
Number & Math 类方法:
下面的表中列出的是 Number & Math 类常用的一些方法:
| 序号 | 方法与描述 |
|---|---|
| 1 | xxxValue()将 Number 对象转换为xxx数据类型的值并返回。 |
| 2 | compareTo()将number对象与参数比较。 |
| 3 | equals()判断number对象是否与参数相等。 |
| 4 | valueOf()返回一个 Number 对象指定的内置数据类型 |
| 5 | toString()以字符串形式返回值。 |
| 6 | parseInt()将字符串解析为int类型。 |
| 7 | abs()返回参数的绝对值。 |
| 8 | ceil()返回大于等于( >= )给定参数的的最小整数,类型为双精度浮点型。 |
| 9 | floor()返回小于等于(<=)给定参数的最大整数 。 |
| 10 | rint()返回与参数最接近的整数。返回类型为double。 |
| 11 | round()它表示四舍五入,算法为 Math.floor(x+0.5),即将原来的数字加上 0.5 后再向下取整,所以,Math.round(11.5) 的结果为12,Math.round(-11.5) 的结果为-11。 |
| 12 | min()返回两个参数中的最小值。 |
| 13 | max()返回两个参数中的最大值。 |
| 14 | exp()返回自然数底数e的参数次方。 |
| 15 | log()返回参数的自然数底数的对数值。 |
| 16 | pow()返回第一个参数的第二个参数次方。 |
| 17 | sqrt()求参数的算术平方根。 |
| 18 | sin()求指定double类型参数的正弦值。 |
| 19 | cos()求指定double类型参数的余弦值。 |
| 20 | tan()求指定double类型参数的正切值。 |
| 21 | asin()求指定double类型参数的反正弦值。 |
| 22 | acos()求指定double类型参数的反余弦值。 |
| 23 | atan()求指定double类型参数的反正切值。 |
| 24 | atan2()将笛卡尔坐标转换为极坐标,并返回极坐标的角度值。 |
| 25 | toDegrees()将参数转化为角度。 |
| 26 | toRadians()将角度转换为弧度。 |
| 27 | random()返回一个随机数。 |
Character 类:
Character 类用于对单个字符进行操作。
Character 类在对象中包装一个基本类型 char 的值
char实例:
char ch = 'a';
// Unicode 字符表示形式
char uniChar = 'u039A';
// 字符数组
char[] charArray ={ 'a', 'b', 'c', 'd', 'e' };
然而,在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情况。为了解决这个问题,Java语言为内置数据类型char提供了包装类Character类(具体类)。
自动装箱拆箱:
// 原始字符 'a' 装箱到 Character 对象 ch 中
Character ch = 'a';
// 原始字符 'x' 用 test 方法装箱
// 返回拆箱的值到 'c'
char c = test('x');
特殊转义字符:
一些字符转义后有特殊含义:
| 转义序列 | 作用 |
|---|---|
| t | 在文中该处插入一个tab键 |
| b | 在文中该处插入一个后退键 |
| n | 在文中该处换行 |
| r | 在文中该处插入回车 |
| f | 在文中该处插入换页符 |
| ‘ | 在文中该处插入单引号 |
| " | 在文中该处插入双引号 |
| 在文中该处插入反斜杠 |
例:
public class Test {
public static void main(String[] args) {
System.out.println("访问"菜鸟教程!"");
}
}
Character 方法:
| 序号 | 方法与描述 |
|---|---|
| 1 | isLetter():是否是一个字母 |
| 2 | isDigit():是否是一个数字字符 |
| 3 | isWhitespace():是否是一个空白字符 |
| 4 | isUpperCase():是否是大写字母 |
| 5 | isLowerCase():是否是小写字母 |
| 6 | toUpperCase():指定字母的大写形式 |
| 7 | toLowerCase():指定字母的小写形式 |
| 8 | toString():返回字符的字符串形式,字符串的长度仅为1 |
String 类:
字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。
创建字符串最简单的方式如下:
String str = "Runoob";
或者也可以:
String str2=new String("Runoob");
String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上,池会查重复用,堆不会。

获取字符串长度:
例:
public class StringDemo {
public static void main(String args[]) {
String site = "www.runoob.com";
int len = site.length();
System.out.println( "菜鸟教程网址长度 : " + len );
}
}
连接字符串:
concat连接(可以用于字符串常量)
例:
"我的名字是 ".concat("Runoob");
string1.concat(string2);
‘+’运算符连接:
"Hello," + " runoob" + "!"
System.out.println("1、" + string1 + "www.runoob.com");
格式化字符串:
格式化数字可以使用 printf() 和 format() 方法
printf()用于直接输出到控制台
format()返回一个格式化的字符串对象
例:
System.out.printf("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
"is %s", floatVar, intVar, stringVar);
String fs;
fs = String.format("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
" %s", floatVar, intVar, stringVar);
String 方法:
Java StringBuffer 和 StringBuilder 类:
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。
例:
public class RunoobTest{
public static void main(String[] args){
StringBuilder sb = new StringBuilder(10);
sb.append("Runoob..");
System.out.println(sb);
sb.append("!");
System.out.println(sb);
sb.insert(8, "Java");
System.out.println(sb);
sb.delete(5,8);
System.out.println(sb);
}
}
//Runoob..
//Runoob..!
//Runoob..Java!
//RunooJava!
public class Test{
public static void main(String[] args){
StringBuffer sBuffer = new StringBuffer("菜鸟教程官网:");
sBuffer.append("www");
sBuffer.append(".runoob");
sBuffer.append(".com");
System.out.println(sBuffer);
}
}
//菜鸟教程官网:www.runoob.com
StringBuffer 方法:
| 1 | public StringBuffer append(String s) 将指定的字符串追加到此字符序列。 |
|---|---|
| 2 | public StringBuffer reverse() 将此字符序列用其反转形式取代。 |
| 3 | public delete(int start, int end) 移除此序列的子字符串中的字符。 |
| 4 | public insert(int offset, int i) 将 int 参数的字符串表示形式插入此序列中。 |
| 5 | insert(int offset, String str) 将 str 参数的字符串插入此序列中。 |
| 6 | replace(int start, int end, String str) 使用给定 String 中的字符替换此序列的子字符串中的字符。 |
| 1 | int capacity() 返回当前容量。 |
|---|---|
| 2 | char charAt(int index) 返回此序列中指定索引处的 char 值。 |
| 3 | void ensureCapacity(int minimumCapacity) 确保容量至少等于指定的最小值。 |
| 4 | void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 将字符从此序列复制到目标字符数组 dst。 |
| 5 | int indexOf(String str) 返回第一次出现的指定子字符串在该字符串中的索引。 |
| 6 | int indexOf(String str, int fromIndex) 从指定的索引处开始,返回第一次出现的指定子字符串在该字符串中的索引。 |
| 7 | int lastIndexOf(String str) 返回最右边出现的指定子字符串在此字符串中的索引。 |
| 8 | int lastIndexOf(String str, int fromIndex) 返回 String 对象中子字符串最后出现的位置。 |
| 9 | int length() 返回长度(字符数)。 |
| 10 | void setCharAt(int index, char ch) 将给定索引处的字符设置为 ch。 |
| 11 | void setLength(int newLength) 设置字符序列的长度。 |
| 12 | CharSequence subSequence(int start, int end) 返回一个新的字符序列,该字符序列是此序列的子序列。 |
| 13 | String substring(int start) 返回一个新的 String,它包含此字符序列当前所包含的字符子序列。 |
| 14 | String substring(int start, int end) 返回一个新的 String,它包含此序列当前所包含的字符子序列。 |
| 15 | String toString() 返回此序列中数据的字符串表示形式。 |
数组:
Java 语言中提供的数组是用来存储固定大小的同类型元素
首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:
dataType[] arrayRefVar; // 首选的方法
或
dataType arrayRefVar[]; // 效果相同,但不是首选方法
创建数组:
arrayRefVar = new dataType[arraySize];
//先使用 dataType[arraySize] 创建了一个数组
//再把新创建的数组的引用赋值给变量 arrayRefVar
合在一起完成:
dataType[] arrayRefVar = new dataType[arraySize];
也可以:
dataType[] arrayRefVar = {value0, value1, ..., valuek};
For-Each 循环:
JDK 1.5 引进了一种新的循环类型,被称为 For-Each 循环或者加强型循环,它能在不使用下标的情况下遍历数组。
例:
public class TestArray {
public static void main(String[] args) {
double[] myList = {1.9, 2.9, 3.4, 3.5};
// 打印所有数组元素
for (double element: myList) {
System.out.println(element);
}
}
}
多维数组:
示例:
type[][] typeName = new type[typeLength1][typeLength2];
也可以从最高维开始,分别为每一维分配空间,例如:
String[][] s = new String[2][];
s[0] = new String[2];
s[1] = new String[3];
s[0][0] = new String("Good");
s[0][1] = new String("Luck");
s[1][0] = new String("to");
s[1][1] = new String("you");
s[1][2] = new String("!");
Arrays 类:
java.util.Arrays 类能方便地操作数组,它提供的所有方法都是静态的。
具有以下功能:
- 给数组赋值:通过 fill 方法。
- 对数组排序:通过 sort 方法,按升序。
- 比较数组:通过 equals 方法比较数组中元素值是否相等。
- 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
具体说明请查看下表:
| 序号 | 方法和说明 |
|---|---|
| 1 | public static int binarySearch(Object[] a, Object key) 用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) – 1)。 |
| 2 | public static boolean equals(long[] a, long[] a2) 如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
| 3 | public static void fill(int[] a, int val) 将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
| 4 | public static void sort(Object[] a) 对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
正则:
java.util.regex 包是 Java 标准库中用于支持正则表达式操作的包。
java.util.regex 包主要包括以下三个类:
-
Pattern 类:
pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。 -
Matcher 类:
Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。 -
PatternSyntaxException:
PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
例:
import java.util.regex.*;
class RegexExample1{
public static void main(String[] args){
String content = "I am noob " +
"from runoob.com.";
String pattern = ".*runoob.*";
boolean isMatch = Pattern.matches(pattern, content);
System.out.println("字符串中是否包含了 'runoob' 子字符串? " + isMatch);
}
}
捕获组:略
正则语法:
在其他语言中,\ 表示:我想要在正则表达式中插入一个普通的(字面上的)反斜杠,请不要给它任何特殊的意义。
在 Java 中,\表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。
java中一个代表转义,同时在正则中会先经过java编译器再给正则引擎,所以如果想让正则引擎接收到d,即一个转义的d,需要写\d,经过java编译器后会识别一个为转义字符所以变成d传递给正则引擎
| 字符 | 说明 |
|---|---|
| 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如, n匹配字符 n。n 匹配换行符。序列 \ 匹配 ,( 匹配 (。 | |
| ^ | 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与"n"或"r"之后的位置匹配。 |
| $ | 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与"n"或"r"之前的位置匹配。 |
| * | 零次或多次匹配前面的字符或子表达式。例如,zo 匹配"z"和"zoo"。 等效于 {0,}。 |
| + | 一次或多次匹配前面的字符或子表达式。例如,"zo+"与"zo"和"zoo"匹配,但与"z"不匹配。+ 等效于 {1,}。 |
| ? | 零次或一次匹配前面的字符或子表达式。例如,"do(es)?"匹配"do"或"does"中的"do"。? 等效于 {0,1}。 |
| {n} | n 是非负整数。正好匹配 n 次。例如,"o{2}"与"Bob"中的"o"不匹配,但与"food"中的两个"o"匹配。 |
| {n,} | n 是非负整数。至少匹配 n 次。例如,"o{2,}"不匹配"Bob"中的"o",而匹配"foooood"中的所有 o。"o{1,}"等效于"o+"。"o{0,}"等效于"o*"。 |
| {n,m} | m 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,"o{1,3}"匹配"fooooood"中的头三个 o。’o{0,1}’ 等效于 ‘o?’。注意:您不能将空格插入逗号和数字之间。 |
| ? | 当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。例如,在字符串"oooo"中,"o+?"只匹配单个"o",而"o+"匹配所有"o"。 |
| . | 匹配除"rn"之外的任何单个字符。若要匹配包括"rn"在内的任意字符,请使用诸如"[sS]"之类的模式。 |
| (pattern) | 匹配 pattern 并捕获该匹配的子表达式。可以使用 $0…$9 属性从结果"匹配"集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用"("或者")"。 |
| (?:pattern) | 匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"or"字符 (|) 组合模式部件的情况很有用。例如,’industr(?:y|ies) 是比 ‘industry|industries’ 更经济的表达式。 |
| (?=pattern) | 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,’Windows (?=95|98|NT|2000)’ 匹配"Windows 2000"中的"Windows",但不匹配"Windows 3.1"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。 |
| (?!pattern) | 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,’Windows (?!95|98|NT|2000)’ 匹配"Windows 3.1"中的 "Windows",但不匹配"Windows 2000"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。 |
| x|y | 匹配 x 或 y。例如,’z|food’ 匹配"z"或"food"。'(z|f)ood’ 匹配"zood"或"food"。 |
| [xyz] | 字符集。匹配包含的任一字符。例如,"[abc]"匹配"plain"中的"a"。 |
| [^xyz] | 反向字符集。匹配未包含的任何字符。例如,"[^abc]"匹配"plain"中"p","l","i","n"。 |
| [a-z] | 字符范围。匹配指定范围内的任何字符。例如,"[a-z]"匹配"a"到"z"范围内的任何小写字母。 |
| [^a-z] | 反向范围字符。匹配不在指定的范围内的任何字符。例如,"[^a-z]"匹配任何不在"a"到"z"范围内的任何字符。 |
| b | 匹配一个字边界,即字与空格间的位置。例如,"erb"匹配"never"中的"er",但不匹配"verb"中的"er"。 |
| B | 非字边界匹配。"erB"匹配"verb"中的"er",但不匹配"never"中的"er"。 |
| cx | 匹配 x 指示的控制字符。例如,cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是"c"字符本身。 |
| d | 数字字符匹配。等效于 [0-9]。 |
| D | 非数字字符匹配。等效于 [^0-9]。 |
| f | 换页符匹配。等效于 x0c 和 cL。 |
| n | 换行符匹配。等效于 x0a 和 cJ。 |
| r | 匹配一个回车符。等效于 x0d 和 cM。 |
| s | 匹配任何空白字符,包括空格、制表符、换页符等。与 [ fnrtv] 等效。 |
| S | 匹配任何非空白字符。与 [^ fnrtv] 等效。 |
| t | 制表符匹配。与 x09 和 cI 等效。 |
| v | 垂直制表符匹配。与 x0b 和 cK 等效。 |
| w | 匹配任何字类字符,包括下划线。与"[A-Za-z0-9_]"等效。 |
| W | 与任何非单词字符匹配。与"[^A-Za-z0-9_]"等效。 |
| xn | 匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,"x41"匹配"A"。"x041"与"x04"&"1"等效。允许在正则表达式中使用 ASCII 代码。 |
| num | 匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,"(.)1"匹配两个连续的相同字符。 |
| n | 标识一个八进制转义码或反向引用。如果 _n_ 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码。 |
| nm | 标识一个八进制转义码或反向引用。如果 _nm_ 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 _nm_ 前面至少有 n 个捕获,则 n 是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 _nm_ 匹配八进制值 nm,其中 n 和 m 是八进制数字 (0-7)。 |
| nml | 当 n 是八进制数 (0-3),m 和 l 是八进制数 (0-7) 时,匹配八进制转义码 nml。 |
| un | 匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,u00A9 匹配版权符号 (©)。 |
Matcher 类的方法:
索引方法:
| 序号 | 方法及说明 |
|---|---|
| 1 | public int start()返回以前匹配的初始索引。 |
| 2 | public int start(int group) 返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引 |
| 3 | public int end()返回最后匹配字符之后的偏移量。 |
| 4 | public int end(int group)返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。 |
注:group(0)指整个匹配的字符串
例:
import java.util.regex.*;
public class MatcherPositionDemo1 {
public static void main(String[] args) {
String text = "Hello runoob World";
Pattern pattern = Pattern.compile("runoob");
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
System.out.println("匹配内容: " + matcher.group()); // runoob
System.out.println("start(): " + matcher.start()); // 6
System.out.println("end(): " + matcher.end()); // 12
System.out.println("匹配片段: " + text.substring(matcher.start(), matcher.end())); // runoob
}
}
}
public class MatcherPositionDemo2 {
public static void main(String[] args) {
String text = "Email: user@example.com";
// 捕获组1: 用户名, 捕获组2: 域名
Pattern pattern = Pattern.compile("([a-z]+)@([a-z]+\.com)");
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
System.out.println("整个匹配: " + matcher.group(0)); // user@example.com
System.out.println(" start(0): " + matcher.start(0) + ", end(0): " + matcher.end(0)); // 7, 23
System.out.println("组1 (用户名): " + matcher.group(1)); // user
System.out.println(" start(1): " + matcher.start(1) + ", end(1): " + matcher.end(1)); // 7, 11
System.out.println("组2 (域名): " + matcher.group(2)); // example.com
System.out.println(" start(2): " + matcher.start(2) + ", end(2): " + matcher.end(2)); // 12, 23
}
}
}
替换方法:
替换方法是替换输入字符串里文本的方法:
| 序号 | 方法及说明 |
|---|---|
| 1 | public Matcher appendReplacement(StringBuffer sb, String replacement) 实现非终端添加和替换步骤。 |
| 2 | public StringBuffer appendTail(StringBuffer sb) 实现终端添加和替换步骤。 |
| 3 | public String replaceAll(String replacement) 替换模式与给定替换字符串相匹配的输入序列的每个子序列。 |
| 4 | public String replaceFirst(String replacement) 替换模式与给定替换字符串匹配的输入序列的第一个子序列。 |
| 5 | public static String quoteReplacement(String s) 返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement 方法一个字面字符串一样工作。 |
例:
import java.util.regex.*;
public class SimpleReplaceDemo {
public static void main(String[] args) {
String text = "Price: $99, Discount: $20";
// 替换所有数字为 [数字]
String replacedAll = text.replaceAll("\$(\d+)", "[$1]");
System.out.println("replaceAll: " + replacedAll);
// 输出: Price: [99], Discount: [20]
// 仅替换第一个价格
String replacedFirst = text.replaceFirst("\$(\d+)", "[$1]");
System.out.println("replaceFirst: " + replacedFirst);
// 输出: Price: [99], Discount: $20
}
}
//$1 是反向引用,表示第一个捕获组的内容(即 d+ 匹配的数字)
public class AdvancedReplaceDemo {
public static void main(String[] args) {
String text = "ID: 1001, ID: 1002, ID: 1003";
Pattern pattern = Pattern.compile("\b(\d{4})\b");
Matcher matcher = pattern.matcher(text);
StringBuffer result = new StringBuffer();
int count = 0;
while (matcher.find()) {
count++;
String masked = "*".repeat(matcher.group(1).length() - 1) + matcher.group(1).charAt(3);
matcher.appendReplacement(result,masked); // 保留最后一位
}
matcher.appendTail(result);
//这是 Matcher 类中完成替换流程的最后关键步骤,负责将最后一次匹配之后剩余的未匹配文本追加到结果中。
//必须在 while (matcher.find()) 循环结束后调用
System.out.println("原始: " + text);
System.out.println("脱敏: " + result.toString());
System.out.println("共替换 " + count + " 处");
}
}
matches 和 lookingAt 方法:
matches 和 lookingAt 方法都用来尝试匹配一个输入序列模式。它们的不同是 matches 要求整个序列都匹配,而lookingAt 不要求。
lookingAt 方法虽然不需要整句都匹配,但是需要从第一个字符开始匹配。
例:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
private static final String REGEX = "foo";
private static final String INPUT = "fooooooooooooooooo";
private static final String INPUT2 = "ooooofoooooooooooo";
private static Pattern pattern;
private static Matcher matcher;
private static Matcher matcher2;
public static void main( String[] args ){
pattern = Pattern.compile(REGEX);
matcher = pattern.matcher(INPUT);
matcher2 = pattern.matcher(INPUT2);
System.out.println("Current REGEX is: "+REGEX);
System.out.println("Current INPUT is: "+INPUT);
System.out.println("Current INPUT2 is: "+INPUT2);
System.out.println("lookingAt(): "+matcher.lookingAt());
System.out.println("matches(): "+matcher.matches());
System.out.println("lookingAt(): "+matcher2.lookingAt());
}
}
结果:
Current REGEX is: foo
Current INPUT is: fooooooooooooooooo
Current INPUT2 is: ooooofoooooooooooo
lookingAt(): true
matches(): false
lookingAt(): false
replaceFirst 和 replaceAll 方法:
replaceFirst 和 replaceAll 方法用来替换匹配正则表达式的文本。不同的是,replaceFirst 替换首次匹配,replaceAll 替换所有匹配。前面给了例子,就不再给了。
appendReplacement 和 appendTail 方法:
也是文本替换,看之前的例子就好
PatternSyntaxException 类的方法:
PatternSyntaxException 是一个非强制异常类,它指示一个正则表达式模式中的语法错误。
PatternSyntaxException 类提供了下面的方法来帮助我们查看发生了什么错误。
| 序号 | 方法及说明 |
|---|---|
| 1 | public String getDescription() 获取错误的描述。 |
| 2 | public int getIndex() 获取错误的索引。 |
| 3 | public String getPattern() 获取错误的正则表达式模式。 |
| 4 | public String getMessage() 返回多行字符串,包含语法错误及其索引的描述、错误的正则表达式模式和模式中错误索引的可视化指示。 |
例:
import java.util.regex.*;
public class Demo {
public static void main(String[] args) {
try {
Pattern.compile("[a-"); // 故意写错:未闭合字符类(缺少 ])
} catch (PatternSyntaxException e) {
// 1. 错误类型描述
System.out.println("getDescription: " + e.getDescription());
// 2. 错误位置索引(从0开始)
System.out.println("getIndex: " + e.getIndex());
// 3. 原始错误正则表达式
System.out.println("getPattern: " + e.getPattern());
// 4. 完整错误报告(含可视化指示)
System.out.println("getMessage:n" + e.getMessage());
}
}
}
构造方法:
只举点例子,之前已经有过讲解
public class Person {
String name;
int age;
public Person() {
this.name = "Unknown";
this.age = 0;
}
public Person(String name) {
this.name = name;
this.age = 0;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
this 关键字:
1、引用当前对象的属性或方法:当构造方法的参数名与类属性名相同时,使用 this 来区分类属性和参数。例如:
public Person(String name, int age) {
this.name = name; // this.name 表示类的属性
this.age = age;
}
2、调用另一个构造方法:可以使用 this() 调用当前类的其他构造方法,常用于避免重复代码,但必须放在构造方法的第一行。
public Person(String name) {
this(name, 0); // 调用另一个双参数的构造方法
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
Java 中的流(Stream)、文件(File)和 IO(输入输出):
读取控制台输入:
Java 的控制台输入由 System.in 完成。
为了获得一个绑定到控制台的字符流,你可以把 System.in 包装在一个 BufferedReader 对象中来创建一个字符流。
下面是创建 BufferedReader 的基本语法:
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
从 BufferedReader 对象读取一个字符要使用 read() 方法,每次调用 read() 方法,它从输入流读取一个字符并把该字符作为整数值返回。 当流结束的时候返回 -1。该方法抛出 IOException。
下面的程序示范了用 read() 方法从控制台不断读取字符直到用户输入 q:
//使用 BufferedReader 在控制台读取字符
import java.io.*;
public class BRRead {
public static void main(String[] args) throws IOException {
char c;
// 使用 System.in 创建 BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入字符, 按下 'q' 键退出。");
// 读取字符
do {
c = (char) br.read();
System.out.println(c);
} while (c != 'q');
}
}
读取字符串:
使用 BufferedReader 的 readLine() 方法
例:
//使用 BufferedReader 在控制台读取字符
import java.io.*;
public class BRReadLines {
public static void main(String[] args) throws IOException {
// 使用 System.in 创建 BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str;
System.out.println("Enter lines of text.");
System.out.println("Enter 'end' to quit.");
do {
str = br.readLine();
System.out.println(str);
} while (!str.equals("end"));
}
}
控制台输出:
使用println()或print()完成,前者会在打印结束后多一个换行符,后者不会,或者write()也行,但是不常用
write()例:
//使用 BufferedReader 在控制台读取字符
import java.io.*;
public class BRReadLines {
public static void main(String[] args) throws IOException {
// 使用 System.in 创建 BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str;
System.out.println("Enter lines of text.");
System.out.println("Enter 'end' to quit.");
do {
str = br.readLine();
System.out.println(str);
} while (!str.equals("end"));
}
}
输入输出流:
java中输入流(input)用于读取数据,输出流(output)用于输出数据,同时有字符流( 处理文本数据)与字节流( 处理二进制数据)的区别,
下面是类表
| 类名 | 类型 | 描述 |
|---|---|---|
InputStream |
抽象类 (输入流) | 所有字节输入流的超类,处理字节的输入操作。 |
OutputStream |
抽象类 (输出流) | 所有字节输出流的超类,处理字节的输出操作。 |
FileInputStream |
输入流 | 从文件中读取字节数据。 |
FileOutputStream |
输出流 | 将字节数据写入文件。 |
BufferedInputStream |
输入流 | 为字节输入流提供缓冲功能,提高读取效率。 |
BufferedOutputStream |
输出流 | 为字节输出流提供缓冲功能,提高写入效率。 |
ByteArrayInputStream |
输入流 | 将内存中的字节数组作为输入源。 |
ByteArrayOutputStream |
输出流 | 将数据写入到内存中的字节数组。 |
DataInputStream |
输入流 | 允许从输入流中读取 Java 原生数据类型(如 int、float、boolean)。 |
DataOutputStream |
输出流 | 允许向输出流中写入 Java 原生数据类型。 |
ObjectInputStream |
输入流 | 从输入流中读取序列化对象。 |
ObjectOutputStream |
输出流 | 将对象序列化并写入输出流中。 |
PipedInputStream |
输入流 | 用于在管道中读取字节数据,通常与 PipedOutputStream 配合使用。 |
PipedOutputStream |
输出流 | 用于在管道中写入字节数据,通常与 PipedInputStream 配合使用。 |
FilterInputStream |
输入流 | 字节输入流的包装类,用于对其他输入流进行过滤处理。 |
FilterOutputStream |
输出流 | 字节输出流的包装类,用于对其他输出流进行过滤处理。 |
SequenceInputStream |
输入流 | 将多个输入流串联为一个输入流进行处理。 |
| 类名 | 类型 | 描述 |
|---|---|---|
Reader |
抽象类 (输入流) | 所有字符输入流的超类,处理字符的输入操作。 |
Writer |
抽象类 (输出流) | 所有字符输出流的超类,处理字符的输出操作。 |
FileReader |
输入流 | 从文件中读取字符数据。 |
FileWriter |
输出流 | 将字符数据写入文件。 |
BufferedReader |
输入流 | 为字符输入流提供缓冲功能,支持按行读取,提高读取效率。 |
BufferedWriter |
输出流 | 为字符输出流提供缓冲功能,支持按行写入,提高写入效率。 |
CharArrayReader |
输入流 | 将字符数组作为输入源。 |
CharArrayWriter |
输出流 | 将数据写入到字符数组。 |
StringReader |
输入流 | 将字符串作为输入源。 |
StringWriter |
输出流 | 将数据写入到字符串缓冲区。 |
PrintWriter |
输出流 | 便捷的字符输出流,支持自动刷新和格式化输出。 |
PipedReader |
输入流 | 用于在管道中读取字符数据,通常与 PipedWriter 配合使用。 |
PipedWriter |
输出流 | 用于在管道中写入字符数据,通常与 PipedReader 配合使用。 |
LineNumberReader |
输入流 | 带行号的缓冲字符输入流,允许跟踪读取的行号。 |
PushbackReader |
输入流 | 允许在读取字符后将字符推回流中,以便再次读取。 |
辅助类(其他重要类):
| 类名 | 类型 | 描述 |
|---|---|---|
File |
文件和目录操作 | 用于表示文件或目录,并提供文件操作,如创建、删除、重命名等。 |
RandomAccessFile |
随机访问文件 | 支持文件的随机访问,可以从文件的任意位置读写数据。 |
Console |
控制台输入输出 | 提供对系统控制台的输入和输出支持。 |
FileInputStream:
该类从文件读取数据,是具体类可用new创建
例:
InputStream f = new FileInputStream("C:/java/hello");
File f = new File("C:/java/hello");
InputStream in = new FileInputStream(f);
方法:
| 方法 | 描述 | 示例代码 |
|---|---|---|
int read() |
读取一个字节的数据,返回值为 0 到 255 之间的整数。如果到达流的末尾,返回 -1。 | int data = inputStream.read(); |
int read(byte[] b) |
从输入流中读取字节,并将其存储在字节数组 b 中,返回实际读取的字节数。如果到达流的末尾,返回 -1。 |
byte[] buffer = new byte[1024]; int bytesRead = inputStream.read(buffer); |
int read(byte[] b, int off, int len) |
从输入流中读取最多 len 个字节,并将它们存储在字节数组 b 的 off 偏移位置,返回实际读取的字节数。如果到达流的末尾,返回 -1。 |
byte[] buffer = new byte[1024]; int bytesRead = inputStream.read(buffer, 0, buffer.length); |
long skip(long n) |
跳过并丢弃输入流中的 n 个字节,返回实际跳过的字节数。 |
long skippedBytes = inputStream.skip(100); |
int available() |
返回可以读取的字节数(不阻塞)。 | int availableBytes = inputStream.available(); |
void close() |
关闭输入流并释放与该流相关的所有资源。 | inputStream.close(); |
void mark(int readlimit) |
在流中的当前位置设置标记,readlimit 是可以读取的字节数上限。 |
inputStream.mark(1024); |
void reset() |
将流重新定位到上次标记的位置,如果没有标记或标记失效,抛出 IOException。 |
inputStream.reset(); |
boolean markSupported() |
检查当前输入流是否支持 mark() 和 reset() 操作。 |
boolean isMarkSupported = inputStream.markSupported(); |
FileOutputStream:
跟前面的差不多,一样的创建方法
| 方法 | 描述 | 示例代码 |
|---|---|---|
void write(int b) |
将指定的字节写入输出流,b 的低 8 位将被写入流中。 |
outputStream.write(255); |
void write(byte[] b) |
将字节数组 b 中的所有字节写入输出流。 |
byte[] data = "Hello".getBytes(); outputStream.write(data); |
void write(byte[] b, int off, int len) |
将字节数组 b 中从偏移量 off 开始的 len 个字节写入输出流。 |
byte[] data = "Hello".getBytes(); outputStream.write(data, 0, data.length); |
void flush() |
刷新输出流并强制写出所有缓冲的数据,确保数据被立即写入目标输出。 | outputStream.flush(); |
void close() |
关闭输出流并释放与该流相关的所有资源。关闭后不能再写入。 | outputStream.close(); |
输入输出流实例:
import java.io.*;
public class fileStreamTest {
public static void main(String[] args) {
try {
byte bWrite[] = { 11, 21, 3, 40, 5 };
OutputStream os = new FileOutputStream("test.txt");
for (int x = 0; x < bWrite.length; x++) {
os.write(bWrite[x]); // writes the bytes
}
os.close();
InputStream is = new FileInputStream("test.txt");
int size = is.available();
for (int i = 0; i < size; i++) {
System.out.print((char) is.read() + " "); //每次read()后指针自动偏移一位下次读取下一个字节
}
is.close();
} catch (IOException e) {
System.out.print("Exception");
}
}
}
但这样是二进制写入,可能出现乱码,下面给出解决方案
//文件名 :fileStreamTest2.java
import java.io.*;
public class fileStreamTest2 {
public static void main(String[] args) throws IOException {
File f = new File("a.txt");
FileOutputStream fop = new FileOutputStream(f);
// 构建FileOutputStream对象,文件不存在会自动新建
OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
// 构建OutputStreamWriter对象,参数可以指定编码,默认为操作系统默认编码,windows上是gbk
writer.append("中文输入");
// 写入到缓冲区
writer.append("rn");
// 换行
writer.append("English");
// 刷新缓存冲,写入到文件,如果下面已经没有写入的内容了,直接close也会写入
writer.close();
// 关闭写入流,同时会把缓冲区内容写入文件,所以上面的注释掉
fop.close();
// 关闭输出流,释放系统资源
FileInputStream fip = new FileInputStream(f);
// 构建FileInputStream对象
InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
// 构建InputStreamReader对象,编码与写入相同
StringBuffer sb = new StringBuffer();
while (reader.ready()) {
sb.append((char) reader.read());
// 转成char加到StringBuffer对象中
}
System.out.println(sb.toString());
reader.close();
// 关闭读取流
fip.close();
// 关闭输入流,释放系统资源
}
}
文件目录操作:
- mkdir( )方法创建一个文件夹,成功则返回true,失败则返回false。失败表明File对象指定的路径已经存在,或者由于整个路径还不存在,该文件夹不能被创建。
- mkdirs()方法创建一个文件夹和它的所有父文件夹。
- delete()方法删除文件
例子:
创建目录:
import java.io.File;
public class CreateDir {
public static void main(String[] args) {
String dirname = "/tmp/user/java/bin";
File d = new File(dirname);
//仅仅创建对象作为路径引导,下面创建目录
d.mkdirs();
}
}
读取目录:
import java.io.File;
public class DirList {
public static void main(String args[]) {
String dirname = "/tmp";
File f1 = new File(dirname);
if (f1.isDirectory()) {
System.out.println("目录 " + dirname);
String s[] = f1.list();
for (int i = 0; i < s.length; i++) {
File f = new File(dirname + "/" + s[i]);
if (f.isDirectory()) {
System.out.println(s[i] + " 是一个目录");
} else {
System.out.println(s[i] + " 是一个文件");
}
}
} else {
System.out.println(dirname + " 不是一个目录");
}
}
}
删除目录/文件(使用递归):
import java.io.File;
public class DeleteFileDemo {
public static void main(String[] args) {
// 这里修改为自己的测试目录
File folder = new File("/tmp/java/");
deleteFolder(folder);
}
// 删除文件及目录
public static void deleteFolder(File folder) {
File[] files = folder.listFiles();
if (files != null) {
for (File f : files) {
if (f.isDirectory()) {
deleteFolder(f);
} else {
f.delete();
}
}
}
folder.delete();
}
}
Scanner 类:
java可用通过Scanner类读取输入
创建Scanner对象:
Scanner s = new Scanner(System.in);
方法:
主要是next()和nextLine(),区别如下:
next():
- 1、一定要读取到有效字符后才可以结束输入。
- 2、对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
- 3、只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
- next() 不能得到带有空格的字符串。
nextLine():
- 1、以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
- 2、可以获得空白。
其他方法:
构造方法:
Scanner(File source) |
从文件创建 Scanner |
|---|---|
Scanner(InputStream source) |
从输入流创建 Scanner |
Scanner(String source) |
从字符串创建 Scanner |
基本输入方法:
boolean hasNext() |
检查是否有下一个标记(以空格分隔) |
|---|---|
String next() |
读取下一个标记(字符串) |
boolean hasNextLine() |
检查是否有下一行 |
String nextLine() |
读取下一行内容 |
类型检查方法:
boolean hasNextInt() |
检查下一个标记是否为整数 |
|---|---|
boolean hasNextDouble() |
检查下一个标记是否为双精度浮点数 |
boolean hasNextBoolean() |
检查下一个标记是否为布尔值 |
类型读取方法:
int nextInt() |
读取下一个整数 |
|---|---|
double nextDouble() |
读取下一个双精度浮点数 |
boolean nextBoolean() |
读取下一个布尔值 |
long nextLong() |
读取下一个长整数 |
float nextFloat() |
读取下一个单精度浮点数 |
short nextShort() |
读取下一个短整数 |
byte nextByte() |
读取下一个字节 |
分隔符控制:
Scanner useDelimiter(String pattern) |
设置分隔符模式 |
|---|---|
Scanner useDelimiter(Pattern pattern) |
使用正则表达式设置分隔符 |
String delimiter() |
返回当前使用的分隔符模式 |
其他方法:
void close() |
关闭扫描器 |
|---|---|
Scanner skip(Pattern pattern) |
跳过匹配指定模式的输入 |
Scanner skip(String pattern) |
跳过匹配指定字符串的输入 |
String findInLine(Pattern pattern) |
在当前行中查找指定模式 |
String findInLine(String pattern) |
在当前行中查找指定字符串 |
Scanner reset() |
重置扫描器 |
Locale locale() |
返回扫描器当前使用的区域设置 |
Scanner useLocale(Locale locale) |
设置扫描器的区域设置 |
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 从键盘接收数据
int i = 0;
float f = 0.0f;
System.out.print("输入整数:");
if (scan.hasNextInt()) {
// 判断输入的是否是整数
i = scan.nextInt();
// 接收整数
System.out.println("整数数据:" + i);
} else {
// 输入错误的信息
System.out.println("输入的不是整数!");
}
System.out.print("输入小数:");
if (scan.hasNextFloat()) {
// 判断输入的是否是小数
f = scan.nextFloat();
// 接收小数
System.out.println("小数数据:" + f);
} else {
// 输入错误的信息
System.out.println("输入的不是小数!");
}
scan.close();
}
}
class RunoobTest {
public static void main(String[] args) {
System.out.println("请输入数字:");
Scanner scan = new Scanner(System.in);
double sum = 0;
int m = 0;
while (scan.hasNextDouble()) {
double x = scan.nextDouble();
m = m + 1;
sum = sum + x;
}
System.out.println(m + "个数的和为" + sum);
System.out.println(m + "个数的平均值是" + (sum / m));
scan.close();
}
}