java笔记

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语言定义函数

09bea80e-c30b-4f20-9032-c30b6d3ace9f

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; // 第二行
    }
}

运算符优先级(从高到低):

c4557228-bdcf-4081-9b1f-99e3099571ad

循环,条件语句,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 创建的字符串对象在堆上,池会查重复用,堆不会。

b9c220ce-db52-4abd-b733-cd8958c62509

获取字符串长度:

例:

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 方法:

SN(序号) 方法描述
1 char charAt(int index)
返回指定索引处的 char 值。
2 int compareTo(Object o)
把这个字符串和另一个对象比较。
3 int compareTo(String anotherString)
按字典顺序比较两个字符串。
4 int compareToIgnoreCase(String str)
按字典顺序比较两个字符串,不考虑大小写。
5 String concat(String str)
将指定字符串连接到此字符串的结尾。
6 boolean contentEquals(StringBuffer sb)
当且仅当字符串与指定的StringBuffer有相同顺序的字符时候返回真。
7 static String copyValueOf(char[] data)
返回指定数组中表示该字符序列的 String。
8 static String copyValueOf(char[] data, int offset, int count)
返回指定数组中表示该字符序列的 String。
9 boolean endsWith(String suffix)
测试此字符串是否以指定的后缀结束。
10 boolean equals(Object anObject)
将此字符串与指定的对象比较。
11 boolean equalsIgnoreCase(String anotherString)
将此 String 与另一个 String 比较,不考虑大小写。
12 byte[] getBytes()
 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
13 byte[] getBytes(String charsetName)
使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
14 void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
将字符从此字符串复制到目标字符数组。
15 int hashCode()
返回此字符串的哈希码。
16 int indexOf(int ch)
返回指定字符在此字符串中第一次出现处的索引。
17 int indexOf(int ch, int fromIndex)
返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。
18 int indexOf(String str)
 返回指定子字符串在此字符串中第一次出现处的索引。
19 int indexOf(String str, int fromIndex)
返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
20 String intern()
 返回字符串对象的规范化表示形式。
21 int lastIndexOf(int ch)
 返回指定字符在此字符串中最后一次出现处的索引。
22 int lastIndexOf(int ch, int fromIndex)
返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。
23 int lastIndexOf(String str)
返回指定子字符串在此字符串中最右边出现处的索引。
24 int lastIndexOf(String str, int fromIndex)
 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
25 int length()
返回此字符串的长度。
26 boolean matches(String regex)
告知此字符串是否匹配给定的正则表达式。
27 boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
测试两个字符串区域是否相等。
28 boolean regionMatches(int toffset, String other, int ooffset, int len)
测试两个字符串区域是否相等。
29 String replace(char oldChar, char newChar)
返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
30 String replaceAll(String regex, String replacement)
使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
31 String replaceFirst(String regex, String replacement)
 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
32 String[] split(String regex)
根据给定正则表达式的匹配拆分此字符串。
33 String[] split(String regex, int limit)
根据匹配给定的正则表达式来拆分此字符串。
34 boolean startsWith(String prefix)
测试此字符串是否以指定的前缀开始。
35 boolean startsWith(String prefix, int toffset)
测试此字符串从指定索引开始的子字符串是否以指定前缀开始。
36 CharSequence subSequence(int beginIndex, int endIndex)
 返回一个新的字符序列,它是此序列的一个子序列。
37 String substring(int beginIndex)
返回一个新的字符串,它是此字符串的一个子字符串。
38 String substring(int beginIndex, int endIndex)
返回一个新字符串,它是此字符串的一个子字符串。
39 char[] toCharArray()
将此字符串转换为一个新的字符数组。
40 String toLowerCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
41 String toLowerCase(Locale locale)
 使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。
42 String toString()
 返回此对象本身(它已经是一个字符串!)。
43 String toUpperCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
44 String toUpperCase(Locale locale)
使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。
45 String trim()
返回字符串的副本,忽略前导空白和尾部空白。
46 static String valueOf(primitive data type x)
返回给定data type类型x参数的字符串表示形式。
47 contains(CharSequence chars)
判断是否包含指定的字符系列。
48 isEmpty()
判断字符串是否为空。

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 原生数据类型(如 intfloatboolean)。
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();
    }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇