一.public class

public class 是用来定义一个公共类的关键字组合,例如,当你创建了一个名叫main的java类,你可以使用public class 定义它

public class main{
    //此处填写Java语句
}

通过该方法即定义一个可以在整个应用程序中被访问的类main,这对于构建可重用的组件和库至关重要。



二.public static void main(String args[])

public static void main(String args[]) 是Java程序的入口点。当你运行一个Java程序时,JVM(Java虚拟机)会寻找这个特定的方法来开始执行程序。这个方法必须被声明为public(公共的,以便JVM可以访问它),static(静态的,意味着它属于类本身而不是类的实例),void(因为它不返回任何值),并且接受一个类型为String[]的参数args(用于接收命令行参数)。

以下是main方法的详细解释:

public: 允许JVM访问这个方法。
static: 意味着这个方法可以直接通过类名调用,而不需要创建类的实例。
void: 表示这个方法不返回任何值。
main: 方法名,JVM会寻找这个名字的方法作为程序的入口。
String[] args: 一个数组,用于接收从命令行传递给程序的参数。
public static void main(String args[])通常在public class后使用,例如

public class Main {
    public static void main(String[] args) {
        //Java语句
    }
}




三.System.out.println()和System.out.print()

System.out.println()和System.out.print()都是用于在控制台输出信息的方法,但它们之间存在一些关键的区别:
System.out.println():这个方法用于打印传递给它的参数,并在输出后自动添加一个换行符(\n)。
这意味着每次调用System.out.println()后,光标会移动到下一行的开始位置。
例如:

System.out.println("Hello");
System.out.println("World");

输出将是:

Hello
World

带变量输出:

public class Main {
    public static void main(String[] args) {
        int i = 1;
        System.out.println("hello!"+i);
    }
}

System.out.println("hello!"+i);语句表明首先在控制台输出一个“hello!”,然后再输出变量i的值
Java基础语句使用归类总结



System.out.print():
这个方法也用于打印传递给它的参数,但它不会在输出后添加换行符。
这意味着每次调用System.out.print()后,光标会停留在同一行上。
例如:

System.out.print("Hello");
System.out.print("World");

输出将是:

HelloWorld


System.out.print()同样支持带变量输出,此处不做展示



四.for语句

在Java中,for语句是一种常用的循环结构,它允许你重复执行一段代码,直到满足某个条件为止。for循环特别适合于已知循环次数的情况。for循环的基本语法如下:

for (初始化语句; 循环条件; 更新语句) {
    // 循环体
}

初始化语句:在循环开始前执行一次,通常用于初始化循环控制变量。
循环条件:在每次循环开始前检查,如果条件为true,则执行循环体;如果为false,则终止循环。
更新语句:在每次循环体执行完毕后执行,通常用于更新循环控制变量的值。
循环体:包含需要重复执行的代码块。
下面是一个简单的for循环示例,它打印从0到9的数字:

for (int i = 0; i < 10; i++) {
    System.out.println(i);
}

在这个例子中:

int i = 0是初始化语句,它声明并初始化了一个名为i的整型变量。
i < 10是循环条件,只要i小于10,循环就会继续。
i++是更新语句,它在每次循环迭代后将i的值增加1。
System.out.println(i);是循环体,它打印当前i的值。
for循环也可以包含多个初始化语句和更新语句,用逗号分隔,例如:

for (int i = 0, j = 10; i < 10; i++, j--) {
    System.out.println("i: " + i + ", j: " + j);
}

在这个例子中,for循环同时控制两个变量i和j,它们分别在每次迭代中增加和减少。

for循环是Java中非常强大和灵活的循环结构,适用于多种循环场景。


五.if语句

在Java中,if语句是一种条件控制结构,它允许你根据条件的真假来决定是否执行特定的代码块。if语句的基本语法如下:

if (条件) {
    // 如果条件为true,执行这里的代码块
}

条件:这是一个布尔表达式,它的值必须是true或false。
代码块:如果条件为true,则执行这个代码块。如果条件为false,则跳过这个代码块。
下面是一个简单的if语句示例,它检查一个数字是否大于10:

int number = 15;

if (number > 10) {
    System.out.println("Number is greater than 10");
}

在这个例子中,number > 10是条件表达式。如果number的值大于10,条件为true,那么System.out.println("Number is greater than 10");这行代码将被执行。
扩展的if语句
Java中的if语句可以与其他控制结构(如else和else if)结合使用,以处理更复杂的条件逻辑。

if-else语句:如果if条件为false,则执行else代码块。

int number = 5;

if (number > 10) {
    System.out.println("Number is greater than 10");
} else {
    System.out.println("Number is not greater than 10");
}

if-else if-else语句:用于处理多个条件。

int number = 5;

if (number > 10) {
    System.out.println("Number is greater than 10");
} else if (number < 10) {
    System.out.println("Number is less than 10");
} else {
    System.out.println("Number is equal to 10");
}

在这个例子中,如果number大于10,则执行第一个代码块;如果number小于10,则执行第二个代码块;否则,执行最后的else代码块。

if语句是Java中控制程序流程的基本工具之一,它允许程序根据不同的条件执行不同的操作。



多条件判断
如果if有多个条件进行判断,可以使用“&&”(代表和)、“||”(代表或),例如

public class main {
        public static void main(String[] args) {
            System.out.println("能被3整除又可以被7整除的1-1000范围内的数:");

            for (int i = 1; i <= 1000; i++) {
                // 检查数是否能同时被3和7整除
                if (i % 3 == 0 && i % 7 == 0) {
                    System.out.println(i);
                }
            }
        }
    }

或者

public class Main {
    public static void main(String[] args) {
        System.out.println("小于100或大于500的数:");

        for (int i = 1; i <= 1000; i++) {
            // 检查i是否小于100或大于500
            if (i <100 || i>500) {
                System.out.println(i);
            }
        }
    }
}




六.break语句和continue语句

在Java中,break和continue是控制流语句,它们用于改变循环(for、while、do-while)的正常行为。
break 语句
break语句用于立即终止最内层的循环或switch语句。当break被执行时,程序控制会跳出循环或switch语句,继续执行循环或switch语句后面的代码。

示例:

for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break; // 当i等于5时,终止循环
    }
    System.out.println(i);
}

在这个例子中,循环会在i等于5时终止,因此输出将是0到4的数字。

continue 语句
continue语句用于跳过当前循环迭代中的剩余代码,并立即开始下一次循环迭代。在for循环中,这意味着continue之后的代码不会被执行,而是会立即计算循环的增量表达式,然后开始下一次迭代。

示例:

for (int i = 0; i < 10; i++) {
    if (i == 5) {
        continue; // 当i等于5时,跳过本次迭代
    }
    System.out.println(i);
}

在这个例子中,当i等于5时,continue语句被执行,导致System.out.println(i);被跳过,因此输出将是0到9的数字,但不包括5。

总结:

break用于完全终止循环。
continue用于跳过当前迭代的剩余部分,开始下一次迭代。
这两种语句都提供了对循环行为的精细控制,允许程序根据特定条件改变其流程。


七.switch语句

在Java中,switch语句是一种多分支条件语句,它允许根据表达式的值来选择执行不同的代码块。switch语句特别适合于有多个可能值的情况,可以替代多个连续的if-else语句。switch语句的基本语法如下:

switch (表达式) {
    case 值1:
        // 代码块1
        break;
    case 值2:
        // 代码块2
        break;
    // 更多case...
    default:
        // 默认代码块
}

表达式:这个表达式的结果通常是一个整数类型(如byte、short、char、int)、枚举类型或字符串类型。从Java 7开始,也可以使用字符串。
case 值:每个case后面跟着一个可能的值,如果表达式的值与某个case的值匹配,那么该case后面的代码块将被执行。
break:在每个case代码块的末尾通常有一个break语句,它用于跳出switch语句。如果没有break,程序将继续执行下一个case的代码块,这称为“贯穿”(fall-through)。
default:如果没有任何case的值与表达式的值匹配,那么default代码块将被执行。default是可选的,可以放在switch语句的任何位置,但通常放在最后。
下面是一个使用switch语句的示例,它根据一个整数值输出不同的信息:

int number = 2;

switch (number) {
    case 1:
        System.out.println("Number is 1");
        break;
    case 2:
        System.out.println("Number is 2");
        break;
    case 3:
        System.out.println("Number is 3");
        break;
    default:
        System.out.println("Number is not 1, 2, or 3");
}

在这个例子中,如果number的值是1,则输出"Number is 1";如果是2,则输出"Number is 2";如果是3,则输出"Number is 3";否则,输出"Number is not 1, 2, or 3"。



八.Scanner

import java.util.Scanner; 是Java中用于导入Scanner类的语句。Scanner类位于java.util包中,它提供了一种简单的方法来读取用户输入,包括基本数据类型和字符串。
使用Scanner的基本步骤:
1.导入Scanner类:

import java.util.Scanner;

2.创建Scanner对象:

Scanner scanner = new Scanner(System.in);

这里System.in表示标准输入流,通常是键盘输入。
3.使用Scanner读取输入:
读取整数:

int number = scanner.nextInt();

读取浮点数:

double value = scanner.nextDouble();

读取字符串:

String text = scanner.nextLine(); // 读取一行
String word = scanner.next(); // 读取单词

读取字符:

char character = scanner.next().charAt(0);

4.关闭Scanner(可选):

scanner.close();

在不再需要Scanner对象时,关闭它可以释放资源。

示例代码:
下面是一个完整的示例,它使用Scanner来读取用户输入的整数和字符串,并输出它们:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // 创建Scanner对象
        Scanner scanner = new Scanner(System.in);

        // 提示用户输入
        System.out.println("请输入一个整数:");
        int number = scanner.nextInt();
        System.out.println("你输入的整数是:" + number);

        // 提示用户输入字符串
        System.out.println("请输入一个字符串:");
        String text = scanner.nextLine(); // 这里需要额外调用nextLine()来消耗掉nextInt()后的换行符
        text = scanner.nextLine(); // 实际读取字符串
        System.out.println("你输入的字符串是:" + text);

        // 关闭Scanner
        scanner.close();
    }
}

在这个示例中,nextInt()用于读取整数,而nextLine()用于读取字符串。注意,由于nextInt()不会读取输入末尾的换行符,所以在读取整数后立即读取字符串时,需要额外调用一次nextLine()来消耗掉这个换行符。

Scanner是Java中处理用户输入的常用工具,它使得从控制台读取数据变得简单和直观。


九.Float.parseFloat(String s)

Float.parseFloat(String s) 是Java中的一个静态方法,它属于Float类。这个方法用于将一个表示浮点数的字符串转换为float类型的数值。如果字符串表示的不是有效的浮点数,该方法会抛出NumberFormatException。
基本语法:

float floatValue = Float.parseFloat(stringValue);

stringValue:需要被解析的字符串,它应该表示一个有效的浮点数。
floatValue:解析后的float类型数值。
示例:

public class Main {
    public static void main(String[] args) {
        String str = "3.14159";
        float pi = Float.parseFloat(str);
        System.out.println("Parsed float value: " + pi);
    }
}

在这个示例中,Float.parseFloat("3.14159")将字符串"3.14159"转换为float类型的数值3.14159。
注意事项:
字符串必须精确地表示一个浮点数,包括小数点和可能的指数部分(如"1.23e-4")。
如果字符串表示的数值超出了float类型的表示范围,方法会返回正无穷大或负无穷大。
如果字符串为null,方法会抛出NullPointerException。
如果字符串表示的数值无法精确转换为float,可能会发生精度损失。



十.int()

在Python中,int()是一个内置函数,用于将一个值转换为整数。int()函数可以接受多种类型的参数,并根据参数的不同有不同的行为。

基本用法:
将字符串转换为整数:

str_value = "123"
int_value = int(str_value)
print(int_value)  # 输出: 123

如果字符串表示的不是有效的整数,会抛出ValueError。

将浮点数转换为整数(截断小数部分):

float_value = 123.45
int_value = int(float_value)
print(int_value)  # 输出: 123

注意,这里使用的是截断而不是四舍五入。
*指定进制转换字符串为整数:

hex_str = "1a"  # 十六进制表示
int_value = int(hex_str, 16)
print(int_value)  # 输出: 26

第二个参数指定了字符串的进制。
*创建一个不带参数的整数:

int_value = int()
print(int_value)  # 输出: 0

如果不提供参数,int()默认返回0。
示例:

# 字符串转换为整数
str_value = "123"
print(int(str_value))  # 输出: 123

# 浮点数转换为整数
float_value = 123.99
print(int(float_value))  # 输出: 123

# 指定进制转换字符串为整数
bin_str = "1101"  # 二进制表示
print(int(bin_str, 2))  # 输出: 13




十一.Random

在Java中,java.util.Random类用于生成伪随机数。这个类提供了多种方法来生成不同类型的随机数,包括整数、长整数、浮点数和双精度浮点数。
创建Random对象:

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        Random random = new Random();
        // 现在你可以使用random对象来生成随机数
    }
}

常用方法:
nextInt():生成一个随机的int值。

int randomInt = random.nextInt();

nextInt(int bound):生成一个介于0(包括)和bound(不包括)之间的随机int值。

int randomIntInRange = random.nextInt(10); // 生成0到9之间的随机数

nextLong():生成一个随机的long值。

long randomLong = random.nextLong();

nextFloat():生成一个介于0.0(包括)和1.0(不包括)之间的随机float值。

float randomFloat = random.nextFloat();

nextDouble():生成一个介于0.0(包括)和1.0(不包括)之间的随机double值。

double randomDouble = random.nextDouble();

nextBoolean():生成一个随机的boolean值(true或false)。

boolean randomBoolean = random.nextBoolean();

示例:

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        Random random = new Random();

        // 生成一个随机的int值
        int randomInt = random.nextInt();
        System.out.println("Random int: " + randomInt);

        // 生成一个0到99之间的随机int值
        int randomIntInRange = random.nextInt(100);
        System.out.println("Random int in range [0, 99]: " + randomIntInRange);

        // 生成一个随机的long值
        long randomLong = random.nextLong();
        System.out.println("Random long: " + randomLong);

        // 生成一个0.0到1.0之间的随机float值
        float randomFloat = random.nextFloat();
        System.out.println("Random float: " + randomFloat);

        // 生成一个0.0到1.0之间的随机double值
        double randomDouble = random.nextDouble();
        System.out.println("Random double: " + randomDouble);

        // 生成一个随机的boolean值
        boolean randomBoolean = random.nextBoolean();
        System.out.println("Random boolean: " + randomBoolean);
    }
}

在这个示例中,我们创建了一个Random对象,并使用它来生成不同类型的随机数。Random类是Java中生成随机数的基本工具之一,适用于多种场景,如模拟、游戏、测试等。


十二.while和do-while

while循环:
while循环在执行循环体之前检查条件。如果条件为true,则执行循环体;如果条件为false,则跳过循环体,继续执行循环后面的代码。

语法:

while (条件) {
    // 循环体
}

示例:

int i = 0;
while (i < 5) {
    System.out.println(i);
    i++;
}

在这个示例中,while循环会检查i是否小于5,如果是,则执行循环体,打印i的值并递增i。这个过程会一直重复,直到i不再小于5。
do-while循环:
do-while循环先执行循环体,然后检查条件。这意味着无论条件如何,循环体至少会被执行一次。如果条件为true,则再次执行循环体;如果条件为false,则退出循环。

语法:

do {
    // 循环体
} while (条件);

示例:

int i = 0;
do {
    System.out.println(i);
    i++;
} while (i < 5);

在这个示例中,do-while循环会先执行循环体,打印i的值并递增i,然后检查i是否小于5。如果条件满足,则再次执行循环体;如果不满足,则退出循环。

区别:
while循环可能一次都不执行循环体,如果条件一开始就为false。
do-while循环至少会执行一次循环体,因为条件检查是在执行循环体之后进行的。
选择使用while还是do-while取决于你的具体需求。如果你希望循环体至少执行一次,那么do-while是更好的选择。如果你希望根据条件决定是否执行循环体,那么while可能更合适。


十三.private和static

private:
作用:限制变量或方法的访问范围,使其只能在定义它的类内部访问。
示例:

class MyClass {
    private int myPrivateVariable = 10;

    public void someMethod() {
        System.out.println(myPrivateVariable); // 在类内部可以访问
    }
}

public class Main {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        // System.out.println(obj.myPrivateVariable); // 编译错误,无法访问private变量
        obj.someMethod(); // 通过类内部的方法访问private变量
    }
}

接下来通过一个详细的例子来解释如何通过obj.someMethod();调用方法,并在方法内部访问并操作myPrivateVariable。

首先,我们定义一个类MyClass,其中包含一个私有变量myPrivateVariable和一个非静态方法someMethod(),该方法可以访问并操作myPrivateVariable:

public class MyClass {
    // 私有变量,只能在MyClass类内部访问
    private int myPrivateVariable = 10;

    // 非静态方法,可以访问类的实例变量
    public void someMethod() {
        // 在方法内部访问并操作myPrivateVariable
        System.out.println("The value of myPrivateVariable before modification: " + myPrivateVariable);
        myPrivateVariable = 20; // 修改myPrivateVariable的值
        System.out.println("The value of myPrivateVariable after modification: " + myPrivateVariable);
    }
}

接下来,我们在另一个类Main中创建MyClass的实例,并调用someMethod()方法:

public class Main {
    public static void main(String[] args) {
        // 创建MyClass的实例
        MyClass obj = new MyClass();

        // 通过实例调用someMethod()方法
        obj.someMethod();
    }
}

当你运行Main类的main方法时,会发生以下步骤:

MyClass obj = new MyClass();创建了一个MyClass的实例,存储在变量obj中。
obj.someMethod();调用了obj实例的someMethod()方法。
在someMethod()方法内部,首先打印出myPrivateVariable的初始值(10)。
然后,方法将myPrivateVariable的值修改为20。
最后,方法再次打印出myPrivateVariable的新值(20)。
由于myPrivateVariable是MyClass类的私有变量,它只能在MyClass类内部访问。因此,someMethod()方法可以在其内部访问并修改myPrivateVariable的值,而外部代码无法直接访问或修改myPrivateVariable。

这就是通过实例方法访问和操作私有变量的方式。通过这种方式,类可以控制其内部状态的访问和修改,从而实现封装和数据隐藏。

static:
作用:使变量或方法属于类本身,而不是类的实例。这意味着你可以在没有创建类的实例的情况下访问这些变量或方法。
示例:

class MyClass {
    static int myStaticVariable = 20;

    public static void myStaticMethod() {
        System.out.println("This is a static method.");
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(MyClass.myStaticVariable); // 直接通过类名访问static变量
        MyClass.myStaticMethod(); // 直接通过类名调用static方法
    }
}




下面是联用方法:

public class MyClass {
    // 私有静态无返回值方法
    private static void myPrivateStaticMethod() {
        System.out.println("This is a private static method.");
    }

    public static void main(String[] args) {
        // 在同一个类中调用私有静态方法
        myPrivateStaticMethod();
    }
}

在这个例子中,myPrivateStaticMethod() 是一个私有静态方法,它只能在 MyClass 类内部被调用。在 main 方法中,我们可以直接调用这个方法,因为它们都属于同一个类。如果尝试在 MyClass 类外部调用 myPrivateStaticMethod(),将会导致编译错误,因为该方法的访问权限是私有的。


十四.System.exit(0)

System.exit(0); 是Java中的一个方法调用,用于终止当前正在运行的Java虚拟机(JVM)。这个方法属于java.lang.System类,它接受一个整数参数,通常称为退出状态码。

System.exit(0); 表示正常退出。状态码0通常被解释为程序成功执行完毕。
如果传递的是非零值,比如System.exit(1);或System.exit(-1);,则表示程序异常退出,非零状态码通常用于指示程序执行过程中遇到了错误或异常情况。
以下是一个简单的例子,展示了如何使用System.exit(0);:

public class Main {
    public static void main(String[] args) {
        System.out.println("Starting the program...");

        // 执行一些操作...

        System.out.println("Finishing the program...");
        System.exit(0); // 正常退出程序

        // 下面的代码不会被执行,因为程序已经退出
        System.out.println("This line will not be printed.");
    }
}

当你运行这个程序时,它会输出:

Starting the program...
Finishing the program...

然后程序会立即终止,不会执行System.exit(0);之后的任何代码。



十五.this方法

在Java中,this 是一个关键字,它代表当前对象的引用。this 可以用来引用当前对象的实例变量、方法,以及在构造方法中调用其他构造方法。下面是 this 关键字的几种常见用法:

引用当前对象的实例变量:
当实例变量和方法参数或局部变量同名时,可以使用 this 关键字来明确指定引用的是实例变量。

public class MyClass {
    private int x;

    public MyClass(int x) {
        this.x = x; // 使用 this 来区分实例变量 x 和参数 x
    }
}

调用当前对象的方法:
可以使用 this 关键字来调用当前对象的其他方法。

public class MyClass {
    private void print() {
        System.out.println("Hello, World!");
    }

    public void callPrint() {
        this.print(); // 调用当前对象的 print 方法
    }
}

在构造方法中调用其他构造方法:
在构造方法中,可以使用 this() 来调用同一个类的另一个构造方法,这称为构造方法链。this() 必须作为构造方法的第一条语句。

public class MyClass {
    private int x;

    public MyClass() {
        this(10); // 调用带有一个参数的构造方法
    }

    public MyClass(int x) {
        this.x = x;
    }
}

作为方法参数传递当前对象:
有时需要将当前对象作为参数传递给其他方法。

public class MyClass {
    public void method() {
        OtherClass.doSomething(this); // 将当前对象传递给 OtherClass 的方法
    }
}

返回当前对象的引用:
在方法中,可以使用 this 关键字返回当前对象的引用。

public class MyClass {
    public MyClass getThis() {
        return this; // 返回当前对象的引用
    }
}

this 关键字在Java中非常有用,它可以帮助我们清晰地区分实例变量和局部变量,以及在对象内部进行方法调用和构造方法链的实现。


十六.getter 和 setter 方法

在Java中,getter和setter方法是一种常见的编程实践,用于封装类的属性(成员变量)。这种封装有助于保护数据,防止外部代码直接修改类的内部状态,同时提供了一种控制和检查属性访问的方式。

Getter方法:

Getter方法用于获取(读取)类的属性值。它通常以get开头,后面跟着属性名,属性名首字母大写。例如,如果有一个名为name的属性,其getter方法通常命名为getName。
Setter方法:

Setter方法用于设置(写入)类的属性值。它通常以set开头,后面跟着属性名,属性名首字母大写。例如,如果有一个名为age的属性,其setter方法通常命名为setAge。
下面是一个简单的例子,展示了如何定义和使用getter和setter方法:

public class Person {
    private String name; // 私有属性
    private int age;     // 私有属性

    // getter方法
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    // setter方法
    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        if (age >= 0) { // 简单的数据验证
            this.age = age;
        } else {
            System.err.println("Invalid age value");
        }
    }
}

在这个例子中,Person类有两个私有属性name和age。通过提供公共的getter和setter方法,外部代码可以访问和修改这些属性的值,但必须通过这些方法来进行。这种方式允许类内部控制如何设置和获取属性值,例如,可以在setter方法中添加数据验证逻辑。

使用getter和setter方法的好处包括:

封装:隐藏内部实现细节,只暴露必要的接口。
数据验证:在setter方法中可以添加逻辑来验证输入数据的有效性。
灵活性:可以在不改变外部接口的情况下,修改内部实现。
安全性:限制对属性的直接访问,防止不正确的数据修改。
在现代Java开发中,可以使用IDE(如IntelliJ IDEA或Eclipse)的自动生成功能来快速创建getter和setter方法,或者使用Lombok库的@Getter和@Setter注解来自动生成这些方法。



十七.super关键字

在Java中,super 关键字有两种主要用法:调用父类的构造方法和访问父类的成员(如方法和变量)。当提到 super() 方法时,通常是指在子类的构造方法中调用父类的构造方法。
调用父类的构造方法
在子类的构造方法中,可以使用 super() 来调用父类的构造方法。这是非常重要的,因为子类在实例化时需要确保父类也得到正确的初始化。super() 必须作为构造方法的第一条语句。

class Parent {
    int x;

    // 父类的构造方法
    public Parent(int x) {
        this.x = x;
    }
}

class Child extends Parent {
    int y;

    // 子类的构造方法
    public Child(int x, int y) {
        super(x); // 调用父类的构造方法
        this.y = y;
    }
}

在这个例子中,Child 类的构造方法 Child(int x, int y) 使用 super(x) 来调用父类 Parent 的构造方法,并将 x 参数传递给它。这样,父类的 x 属性就会被初始化。
访问父类的成员
除了调用构造方法,super 还可以用来访问父类的成员,如方法和变量。这在子类中覆盖(override)了父类的方法时特别有用,因为你可以使用 super 来调用父类的原始方法。

class Parent {
    public void print() {
        System.out.println("Parent's print method");
    }
}

class Child extends Parent {
    @Override
    public void print() {
        super.print(); // 调用父类的 print 方法
        System.out.println("Child's print method");
    }
}

在这个例子中,Child 类覆盖了 Parent 类的 print 方法,并在子类的 print 方法中使用 super.print() 来调用父类的 print 方法。

总结来说,super() 是用来在子类的构造方法中调用父类的构造方法的,而 super 关键字可以用来访问父类的成员。这两种用法都是为了在子类中正确地继承和扩展父类的行为。




十八.抽象类public abstract class

public abstract class 是 Java 编程语言中用于声明抽象类的一种方式。下面是对 public abstract class 的详细解释:

public: 这个访问修饰符表示该类是公开的,可以从任何其他类中访问。如果没有指定访问修饰符,则默认访问级别是包级私有(package-private),即只能在同一个包内访问。

abstract: 这个关键字用于声明一个抽象类。抽象类是不能被实例化的类,它主要用作其他类的基类。抽象类可以包含抽象方法(没有实现的方法)和具体方法(有实现的方法)。子类继承抽象类后,必须实现父类中的所有抽象方法,除非子类本身也是抽象的。

抽象类的特点包括:

不能被实例化: 你不能使用 new 关键字直接创建抽象类的实例。
可以包含抽象方法: 抽象方法是没有方法体的方法,只有方法签名,没有具体的实现。子类必须实现这些抽象方法。
可以包含具体方法: 抽象类中也可以包含已经实现的方法,这些方法可以被子类继承和使用。
可以包含属性: 抽象类可以包含各种类型的属性,包括私有属性、公共属性等。
可以有构造方法: 抽象类可以有构造方法,用于初始化抽象类中的属性。
抽象类的主要用途是提供一个通用的模板,定义一组相关的类应该具有的共同行为和属性。通过继承抽象类,子类可以重用代码并确保遵循一定的设计规范。

例如,在图形类的设计中,可以定义一个抽象类 Shape,其中包含抽象方法 area() 和 perimeter(),然后定义具体的子类如 Circle、Rectangle 等,这些子类必须实现 Shape 中的抽象方法来计算各自的面积和周长。
Shape.java

public abstract class Shape {
    private double length;
    private double width;
    private final double PI = 3.14;

    public Shape(double length,double width){
        this.length =length;
        this.width =width;
    }

    public abstract double area();//求面积
    public  abstract double perimeter();//求周长

    public void setLength(double length) {
        this.length = length;
    }

    public void setWidth(double width) {
        this.width = width;
    }

    public double getLength() {
        return length;
    }

    public double getWidth() {
        return width;
    }

    public double getPI() {
        return PI;
    }
}

Circle.Java

public class Circle extends Shape{

    public Circle(double length) {
        super(length, length);
    }

    @Override
    public double area() {
        return getPI()*Math.pow(getLength()/2,2);
    }

    @Override
    public double perimeter() {
        return getPI()*getLength();
    }
}

TestShape.java

public class TestShape {
    public static void main(String[] args) {
        Circle circle = new Circle(3);
        System.out.println("圆的面积是:"+circle.area());
        System.out.println("圆的周长是:"+circle.perimeter());
    }
}

这将输出

圆的面积是:7.065
圆的周长是:9.42




十九.protected

protected 是 Java 中的一个访问修饰符,用于控制类成员(如方法、构造函数、属性等)的可见性。当一个类成员被声明为 protected 时,它具有以下特性:

继承访问: 被声明为 protected 的成员可以被同一个包中的任何其他类访问,也可以被不同包中的该类的子类访问。这意味着,即使子类位于不同的包中,它仍然可以访问父类中的 protected 成员。

包内访问: 如果没有使用任何访问修饰符(即默认访问级别),成员可以在同一个包内被访问。protected 成员在这种情况下与默认访问级别的成员具有相同的可见性。

外部访问限制: 被声明为 protected 的成员不能被不同包中的非子类访问。这意味着,如果一个类不是另一个类的子类,即使它们位于不同的包中,也不能访问那个类的 protected 成员。

protected 修饰符在设计类层次结构时非常有用,因为它允许子类访问父类的实现细节,同时对外部世界隐藏这些细节。这有助于实现封装,同时允许子类重用和扩展父类的功能。

例如,考虑以下类定义:

package com.example.package1;

public class ParentClass {
    protected int protectedField;

    protected void protectedMethod() {
        // 实现细节
    }
}

在另一个包中,可以有以下子类:

package com.example.package2;

import com.example.package1.ParentClass;

public class ChildClass extends ParentClass {
    public void someMethod() {
        protectedField = 10; // 合法,子类可以访问父类的 protected 成员
        protectedMethod();    // 合法,子类可以调用父类的 protected 方法
    }
}

在这个例子中,ChildClass 可以访问 ParentClass 中的 protectedField 和 protectedMethod(),因为 ChildClass 是 ParentClass 的子类。然而,如果有一个非子类尝试访问这些 protected 成员,它将无法这样做,因为它们位于不同的包中。


二十.interface

在 Java 中,interface 是一种引用类型,它用于定义一组抽象方法,这些方法可以被任何类实现。接口在 Java 中扮演着重要的角色,因为它们支持多重继承(即一个类可以实现多个接口),并且它们提供了一种方式来定义类应该遵循的契约。

接口的主要特点:
抽象方法: 接口中的方法默认是抽象的,不需要使用 abstract 关键字。接口不能包含已实现的方法(Java 8 引入了默认方法和静态方法,允许接口包含实现)。

常量: 接口可以声明常量,这些常量默认是 public、static 和 final 的。

多重继承: 一个类可以实现多个接口,这允许类继承多个行为契约。

默认方法: 从 Java 8 开始,接口可以包含默认方法,这些方法有一个默认实现,实现类可以选择覆盖它们。

静态方法: 从 Java 8 开始,接口还可以包含静态方法,这些方法属于接口本身,可以直接通过接口名调用。

不能包含实例字段: 接口不能包含实例变量,只能包含常量。

实现: 类通过使用 implements 关键字来实现接口。实现接口的类必须提供接口中所有声明的方法的具体实现。

接口的声明示例:

public interface Drawable {
    void draw(); // 抽象方法

    default void erase() { // 默认方法
        System.out.println("Erasing the drawing...");
    }

    static void clearAll() { // 静态方法
        System.out.println("Clearing all drawings...");
    }

    int MAX_SIZE = 100; // 常量
}

类实现接口的示例:

public class Circle implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a circle...");
    }
}

在这个例子中,Circle 类实现了 Drawable 接口,并提供了 draw() 方法的具体实现。Circle 类还可以选择性地覆盖 erase() 方法,或者直接使用接口中定义的默认实现。

接口是 Java 中实现抽象和多态的重要工具,它们有助于构建灵活和可扩展的代码结构。


二十一.一维数组

在编程中,一维数组是最基本的数组结构,它代表了一个线性的元素序列,其中每个元素都有唯一的索引。在 Java 中,数组是用来存储固定大小的相同类型元素的集合。你可以通过指定索引(一个整数值)来访问数组中的任何元素。数组的索引通常是从 0 开始的,这意味着数组中第一个元素的索引是 0,最后一个元素的索引是数组大小减一。

声明一维数组
在 Java 中,你可以通过以下几种方式之一来声明一维数组:

int[] myArray1;
int myArray2[];

这两种声明方式都是合法的,但第一种方式(在类型后使用方括号)是更加推荐的做法,因为它的可读性更好。

初始化一维数组
一旦声明了数组,你还需要初始化它。有几种不同的方法可以初始化数组:

静态初始化
静态初始化是指在声明数组的同时指定每个元素的初始值:

int[] myArray = {1, 2, 3, 4, 5};

动态初始化
动态初始化是指声明数组后,通过数组的索引来分别设置每个元素的值:

int[] myArray = new int[5]; // 分配了包含5个整数的数组空间
myArray[0] = 1; // 设置第一个元素的值为1
myArray[1] = 2; // 设置第二个元素的值为2
// 以此类推

访问一维数组元素
你可以通过数组名称和元素的索引来访问数组中的元素:

int[] myArray = {1, 2, 3, 4, 5};
int firstElement = myArray[0]; // 访问第一个元素
int thirdElement = myArray[2]; // 访问第三个元素

遍历一维数组
遍历数组是指按顺序访问数组中的每个元素。这通常是通过使用循环实现的。以下是使用 for 循环遍历一维数组的示例:

int[] myArray = {1, 2, 3, 4, 5};
for (int i = 0; i < myArray.length; i++) {
    System.out.println(myArray[i]);
}

从 Java 5 开始,你也可以使用增强型 for 循环(也称为 "for-each" 循环)来遍历数组:

int[] myArray = {1, 2, 3, 4, 5};
for (int element : myArray) {
    System.out.println(element);
}

下面是一个完整的 Java 程序实例,展示了一维数组的声明、初始化、访问和遍历。这个示例程序创建了一个包含整数的数组,初始化数组元素,然后打印这些元素。

public class ArrayExample {
    public static void main(String[] args) {
        // 1. 声明一维数组
        int[] numbers;

        // 2. 动态初始化数组,分配包含5个整数的数组空间
        numbers = new int[5];

        // 3. 为数组元素赋值
        numbers[0] = 10;
        numbers[1] = 20;
        numbers[2] = 30;
        numbers[3] = 40;
        numbers[4] = 50;

        // 4. 访问和打印数组元素
        System.out.println("Array elements are:");
        for (int i = 0; i < numbers.length; i++) {
            System.out.println("Element at index " + i + ": " + numbers[i]);
        }

        // 5. 使用增强型 for 循环遍历数组
        System.out.println("\nUsing enhanced for loop:");
        for (int number : numbers) {
            System.out.println("Element: " + number);
        }
    }
}




java.util.Arrays库的使用
在 Java 中,使用基本的数组操作,如声明、初始化、访问以及遍历数组时,不需要导入 java.util.Arrays 或任何其它的库。这些操作是 Java 语言内置的功能,可以直接使用。
然而,java.util.Arrays 类提供了一些静态的方法来帮助进行更复杂的数组操作,比如排序数组、搜索数组元素以及转换数组为字符串等。如果你需要使用这些工具方法,那么就需要导入 java.util.Arrays。

例如:

import java.util.Arrays;

public class ArrayUtilitiesExample {
    public static void main(String[] args) {
        int[] numbers = {4, 2, 5, 1, 3};

        // 排序数组(升序)
        Arrays.sort(numbers);

        // 将数组转换为字符串输出
        System.out.println(Arrays.toString(numbers));
    }
}

在这个例子中,使用了 Arrays.sort() 方法来排序数组,以及 Arrays.toString() 方法来输出数组的内容。因为这些方法是在 java.util.Arrays 类中定义的,所以需要导入这个类。


特殊接口:java.util.List
以下为一个程序示例,来说明其是如何工作的

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class ScoreSorter {
    public static void main(String[] args) {
        // 创建一个 Double 类型的 ArrayList 列表
        List<Double> scores = new ArrayList<>();

        // 向列表中添加一些分数
        scores.add(85.5);
        scores.add(92.0);
        scores.add(78.3);
        scores.add(95.7);
        scores.add(88.2);

        // 创建一个迭代器
        Iterator<Double> iterator = scores.iterator();

        // 使用迭代器遍历并打印原始列表
        System.out.println("Original scores:");
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        // 重新初始化迭代器
        iterator = scores.iterator();

        // 对列表进行逆序排序
        Collections.sort(scores, Collections.reverseOrder());

        // 使用迭代器遍历并打印排序后的列表
        System.out.println("\nSorted in reverse order:");
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

在这个程序中,我们首先创建了一个 ArrayList 实例 scores,并向其中添加了一些 Double 类型的分数。然后,我们创建了一个迭代器 iterator 来遍历这个列表,并打印出原始的分数。

接下来,我们重新初始化迭代器,因为 Collections.sort() 方法会改变列表中元素的顺序,而迭代器是基于列表的当前状态创建的。如果我们不重新初始化迭代器,它将无法正确地遍历排序后的列表。

最后,我们使用 Collections.sort() 方法和 Collections.reverseOrder() 比较器对 scores 列表进行逆序排序,并再次使用迭代器遍历并打印排序后的分数。

请注意,由于 Collections.sort() 改变了列表的顺序,我们需要在排序后重新创建迭代器,否则迭代器将指向排序前的位置,从而导致遍历错误。

运行这个程序,你将看到原始分数和逆序排序后的分数输出。


特殊接口:import java.util.Set
Set 接口是 Java 集合框架中的一部分,它继承自 Collection 接口。Set 接口定义了一个集合,该集合不允许包含重复的元素。换句话说,一个 Set 可以存储一组唯一的对象。

Set 接口的主要特点包括:

唯一性:Set 中的元素必须是唯一的,不允许重复。如果尝试向 Set 中添加重复的元素,添加操作将会失败,而 Set 的大小不会改变。

无序性:Set 通常不保证元素的顺序。这意味着 Set 中的元素没有特定的顺序,你不能通过索引来访问 Set 中的元素。

接口实现:Set 接口有多个实现类,包括 HashSet、LinkedHashSet 和 TreeSet。每个实现类都有自己的特点:

HashSet:基于哈希表实现,提供最快的查找速度,但不保证元素的顺序。
LinkedHashSet:基于哈希表和链表实现,保持元素插入的顺序。
TreeSet:基于红黑树实现,提供有序的集合,元素按照自然顺序或者通过比较器指定的顺序排列。
方法:Set 接口继承了 Collection 接口的所有方法,包括添加元素的 add()、移除元素的 remove()、检查集合是否包含某个元素的 contains() 等。

下面是一个简单的 Set 使用示例:

import java.util.HashSet;
import java.util.Set;

public class SetExample {
    public static void main(String[] args) {
        // 创建一个 HashSet 实例
        Set<String> uniqueWords = new HashSet<>();

        // 向 Set 中添加元素
        uniqueWords.add("apple");
        uniqueWords.add("banana");
        uniqueWords.add("cherry");
        uniqueWords.add("apple"); // 重复的元素,不会被添加

        // 打印 Set 中的元素
        System.out.println("Set contains: " + uniqueWords);

        // 检查 Set 是否包含某个元素
        boolean containsBanana = uniqueWords.contains("banana");
        System.out.println("Contains 'banana'? " + containsBanana);

        // 移除元素
        uniqueWords.remove("cherry");
        System.out.println("After removing 'cherry': " + uniqueWords);
    }
}

在这个示例中,我们创建了一个 HashSet 实例 uniqueWords,并向其中添加了一些字符串。由于 Set 不允许重复元素,所以重复添加的 "apple" 只会被存储一次。最后,我们检查了集合中是否包含 "banana",并移除了 "cherry"。

运行这个程序,你将看到 Set 中的元素是唯一的,并且没有特定的顺序。



特殊接口:MAP
Map 接口是 Java 集合框架中的一部分,它用于存储键值对(key-value pairs)。Map 接口提供了一种通过键来访问值的方式,这意味着每个键在 Map 中必须是唯一的,而值可以重复。如果尝试将一个已存在的键映射到新的值,那么原有的键值对将被新的键值对替换。

Map 接口的主要特点包括:

  1. 键的唯一性Map 中的每个键必须是唯一的。如果尝试使用相同的键添加新的键值对,那么原有的键值对将被新的键值对替换。

  2. 键值对Map 存储的是键值对,每个键值对被称为一个 Entry

  3. 接口实现Map 接口有多个实现类,包括 HashMapLinkedHashMapTreeMapHashtableConcurrentHashMap 等。每个实现类都有自己的特点:

    • HashMap:基于哈希表实现,提供最快的查找速度,但不保证元素的顺序。
    • LinkedHashMap:基于哈希表和链表实现,保持元素插入的顺序。
    • TreeMap:基于红黑树实现,提供有序的集合,元素按照键的自然顺序或者通过比较器指定的顺序排列。
    • Hashtable:一个遗留的类,类似于 HashMap,但它是线程安全的,性能较差。
    • ConcurrentHashMap:线程安全的 HashMap 实现,适用于多线程环境。
  4. 方法Map 接口定义了一系列方法,包括添加键值对的 put(K key, V value)、移除键值对的 remove(Object key)、获取值的 get(Object key)、检查是否包含某个键或值的 containsKey(Object key)containsValue(Object value) 等。

下面是一个简单的 Map 使用示例:

import java.util.HashMap;
import java.util.Map;

public class MapExample {
    public static void main(String[] args) {
        // 创建一个 HashMap 实例
        Map<String, Integer> wordCounts = new HashMap<>();

        // 向 Map 中添加键值对
        wordCounts.put("apple", 5);
        wordCounts.put("banana", 3);
        wordCounts.put("cherry", 7);

        // 获取值
        int appleCount = wordCounts.get("apple");
        System.out.println("Count of 'apple': " + appleCount);

        // 检查 Map 是否包含某个键或值
        boolean containsBanana = wordCounts.containsKey("banana");
        System.out.println("Contains 'banana'? " + containsBanana);

        boolean containsMango = wordCounts.containsKey("mango");
        System.out.println("Contains 'mango'? " + containsMango);

        // 移除键值对
        wordCounts.remove("cherry");
        System.out.println("After removing 'cherry': " + wordCounts);
    }
}

在这个示例中,我们创建了一个 HashMap 实例 wordCounts,并向其中添加了一些字符串和整数的键值对。我们使用 get() 方法获取了 "apple" 的计数,使用 containsKey() 方法检查了 "banana" 和 "mango" 是否存在,并使用 remove() 方法移除了 "cherry" 的键值对。

运行这个程序,你将看到 Map 中的键值对是如何被存储和访问的。


二十二.多维数组

在Java中,多维数组实际上是数组的数组。这意味着一个数组的元素本身也可以是数组。最常见的多维数组是二维数组,但理论上你可以创建任意维度的数组。

二维数组
二维数组是最简单的多维数组形式,它通常用于表示矩阵或表格数据。在Java中,你可以通过以下方式声明和初始化一个二维数组:

// 声明一个二维数组
int[][] matrix;

// 初始化一个二维数组
matrix = new int[3][4]; // 创建一个3行4列的数组

// 或者在声明时直接初始化
int[][] matrix = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

访问二维数组的元素:

int element = matrix[1][2]; // 访问第2行第3列的元素



不规则数组
Java中的多维数组不一定是矩形的,也就是说,每一行的长度可以不同。这种数组称为不规则数组或锯齿数组。

// 声明并初始化一个不规则数组
int[][] irregularArray = new int[3][];
irregularArray[0] = new int[2];
irregularArray[1] = new int[3];
irregularArray[2] = new int[4];

// 或者在声明时直接初始化
int[][] irregularArray = {
    {1, 2},
    {3, 4, 5},
    {6, 7, 8, 9}
};



更高维度的数组
虽然不常见,但你也可以创建三维或更高维度的数组。

// 声明一个三维数组
int[][][] threeDArray;

// 初始化一个三维数组
threeDArray = new int[2][3][4];

// 或者在声明时直接初始化
int[][][] threeDArray = {
    {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    },
    {
        {13, 14, 15, 16},
        {17, 18, 19, 20},
        {21, 22, 23, 24}
    }
};

访问三维数组的元素:

int element = threeDArray[0][1][2]; // 访问第一个二维数组的第二行第三列的元素

多维数组在处理需要多层嵌套数据结构的问题时非常有用,例如图像处理、游戏开发、科学计算等领域。然而,随着维度的增加,数组的复杂性和内存需求也会增加,因此在使用多维数组时需要谨慎考虑性能和内存使用。


二十三.try...catch 语句

try...catch 语句是 Java 中用于处理异常的结构。异常是在程序执行过程中可能出现的错误或意外情况。通过使用 try...catch,你可以捕获这些异常并采取适当的措施来处理它们,而不是让程序崩溃。

try...catch 语句的基本结构如下:

try {
    // 可能会抛出异常的代码块
} catch (ExceptionType1 e1) {
    // 处理 ExceptionType1 类型的异常
} catch (ExceptionType2 e2) {
    // 处理 ExceptionType2 类型的异常
} finally {
    // 可选的 finally 块,无论是否发生异常都会执行
}
  • try 块:包含可能会抛出异常的代码。如果 try 块中的代码抛出了异常,那么程序的控制流会立即转移到相应的 catch 块。

  • catch 块:紧跟在 try 块后面,用于捕获并处理特定类型的异常。你可以有多个 catch 块来处理不同类型的异常。如果 try 块中的代码抛出了一个异常,程序会检查是否有匹配的 catch 块来处理这个异常。

  • finally 块:可选的块,无论是否发生异常,finally 块中的代码都会被执行。通常用于执行清理操作,如关闭文件或释放资源。

下面是一个简单的 try...catch 示例,演示了如何处理 ArithmeticException(算术异常,例如除以零):

public class TryCatchExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0; // 这行代码会抛出 ArithmeticException
            System.out.println("Result: " + result); // 这行代码不会被执行
        } catch (ArithmeticException e) {
            System.out.println("Error: Division by zero is not allowed.");
        } finally {
            System.out.println("This is the finally block, it always executes.");
        }
    }
}

在这个示例中,try 块中的代码尝试执行一个除以零的操作,这会抛出一个 ArithmeticExceptioncatch 块捕获了这个异常,并打印出一条错误消息。finally 块中的代码无论如何都会被执行,打印出一条消息。

运行这个程序,你将看到以下输出:

Error: Division by zero is not allowed.
This is the finally block, it always executes.

try...catch 语句是 Java 异常处理机制的核心,它允许你优雅地处理程序中可能出现的错误,从而提高程序的健壮性和可靠性。



二十四.throw 和throws 关键字

在 Java 中,throwthrows 是用于处理异常的关键字,但它们的作用和使用场景有所不同。

throw 关键字

throw 关键字用于手动抛出一个异常。当你在代码中遇到需要立即处理的错误情况时,可以使用 throw 来抛出一个异常对象。这个异常对象通常是 java.lang.Throwable 类或其子类的实例。

使用 throw 的语法如下:

throw new ExceptionType("optional message");

其中 ExceptionType 是你想要抛出的异常类型,可以是 Java 内置的异常类,如 IllegalArgumentExceptionNullPointerException 等,也可以是你自定义的异常类。

下面是一个使用 throw 的示例:

public class ThrowExample {
    public static void main(String[] args) {
        try {
            validateAge(-5);
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }

    public static void validateAge(int age) {
        if (age < 0) {
            throw new IllegalArgumentException("Age cannot be negative");
        }
        System.out.println("Age is valid: " + age);
    }
}

在这个示例中,validateAge 方法检查传入的年龄是否为负数。如果是负数,它使用 throw 抛出一个 IllegalArgumentException

throws 关键字

throws 关键字用于声明一个方法可能抛出的异常。当你编写一个方法时,如果该方法可能会抛出异常,但你不打算在方法内部处理这些异常,而是希望调用者来处理,那么你可以在方法签名中使用 throws 来声明这些异常。

使用 throws 的语法如下:

public returnType methodName() throws ExceptionType1, ExceptionType2 {
    // 方法体
}

其中 ExceptionType1ExceptionType2 是方法可能抛出的异常类型。

下面是一个使用 throws 的示例:

public class ThrowsExample {
    public static void main(String[] args) {
        try {
            readFile("nonexistent.txt");
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        }
    }

    public static void readFile(String filename) throws IOException {
        // 假设这里有一个读取文件的代码,可能会抛出 IOException
        // 由于我们不打算在方法内部处理这个异常,我们使用 throws 声明它
    }
}

在这个示例中,readFile 方法声明了它可能会抛出一个 IOException。在 main 方法中,我们使用 try...catch 来捕获并处理这个异常。

总结:

  • throw 用于在代码中手动抛出异常。
  • throws 用于声明一个方法可能抛出的异常,让调用者来处理这些异常。


二十五.数据库的操作

在 Java 中与数据库进行交互通常使用 JDBC(Java Database Connectivity)API。以下是使用 JDBC 进行数据插入、查询、修改和删除的基本步骤。

1. 导入 JDBC 驱动

首先,你需要导入数据库的 JDBC 驱动。这通常是通过将驱动 JAR 文件添加到项目的类路径中来完成的。

2. 建立数据库连接

使用 java.sql.Connection 对象来建立与数据库的连接。你需要提供数据库的 URL、用户名和密码。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseConnection {
    private static final String URL = "jdbc:mysql://localhost:3306/此处填写数据库名";
    private static final String USER = "此处填写数据库账号";
    private static final String PASSWORD = "此处填写数据库密码";

    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }
}

3. 数据插入

使用 java.sql.PreparedStatement 对象来执行 SQL 插入语句。

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class InsertData {
    public static void insert(String name, int age) {
        String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, name);
            pstmt.setInt(2, age);
            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

4. 数据查询

使用 java.sql.Statementjava.sql.PreparedStatement 对象来执行 SQL 查询语句,并使用 java.sql.ResultSet 来处理查询结果。

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class QueryData {
    public static void listAllUsers() {
        String sql = "SELECT * FROM users";
        try (Connection conn = DatabaseConnection.getConnection();
             Statement stmt = conn.createStatement()) {
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {
                System.out.println("User ID: " + rs.getInt("id"));
                System.out.println("Name: " + rs.getString("name"));
                System.out.println("Age: " + rs.getInt("age"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

5. 数据修改

使用 java.sql.PreparedStatement 对象来执行 SQL 更新语句。

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class UpdateData {
    public static void updateUserAge(int userId, int newAge) {
        String sql = "UPDATE users SET age = ? WHERE id = ?";
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setInt(1, newAge);
            pstmt.setInt(2, userId);
            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

6. 数据删除

使用 java.sql.PreparedStatement 对象来执行 SQL 删除语句。

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class DeleteData {
    public static void deleteUser(int userId) {
        String sql = "DELETE FROM users WHERE id = ?";
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setInt(1, userId);
            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

7. 关闭连接

在使用完数据库连接后,应该关闭 ConnectionStatementResultSet 对象,以释放资源。

try (Connection conn = DatabaseConnection.getConnection();
     Statement stmt = conn.createStatement();
     ResultSet rs = stmt.executeQuery(sql)) {
    // 使用 conn、stmt 和 rs
} catch (SQLException e) {
    e.printStackTrace();
}

以上是使用 JDBC 进行基本数据库操作的示例。在实际应用中,你可能需要处理更多的异常情况,并考虑使用连接池来管理数据库连接,以提高性能。此外,现代 Java 应用通常使用 ORM(对象关系映射)框架,如 Hibernate 或 JPA(Java Persistence API),来简化数据库操作。



二十六.JAVA IO

Java IO(输入/输出)是Java编程语言的基础部分,提供了一组类和接口,用于从各种来源读取和写入数据,例如文件、网络连接和输入/输出设备。Java IO包位于java.io包中,并包含用于处理不同类型的输入和输出操作的各种类。

以下是Java IO中的一些关键类和概念:

  1. InputStream(输入流):用于从源读取数据。它是所有字节输入流类的抽象基类。

  2. OutputStream(输出流):用于向目标写入数据。它是所有字节输出流类的抽象基类。

  3. Reader(读取器):用于读取字符流的抽象类。

  4. Writer(写入器):用于写入字符流的抽象类。

  5. File(文件):表示文件和目录路径名的抽象表示。

  6. FileInputStream(文件输入流):用于从文件读取数据的输入流。

  7. FileOutputStream(文件输出流):用于向文件写入数据的输出流。

  8. FileReader(文件读取器):用于读取字符文件的便捷类。

  9. FileWriter(文件写入器):用于写入字符文件的便捷类。

  10. BufferedInputStream(缓冲输入流):为另一个输入流添加缓冲功能。

  11. BufferedOutputStream(缓冲输出流):为另一个输出流添加缓冲功能。

  12. BufferedReader(缓冲读取器):从字符输入流读取文本,并提供缓冲功能。

  13. BufferedWriter(缓冲写入器):向字符输出流写入文本,并提供缓冲功能。

  14. DataInputStream(数据输入流):允许应用程序以与机器无关的方式从底层输入流中读取基本Java数据类型。

  15. DataOutputStream(数据输出流):允许应用程序以与机器无关的方式将基本Java数据类型写入输出流。

  16. PrintStream(打印流):提供格式化输出功能。

  17. PrintWriter(打印写入器):提供格式化输出功能,用于字符流。

  18. ObjectInputStream(对象输入流):用于从输入流读取Java对象(对象序列化)。

  19. ObjectOutputStream(对象输出流):用于将Java对象写入输出流(对象序列化)。

Java IO库提供了丰富的功能,可以处理各种输入和输出需求。然而,Java IO是阻塞的,意味着在读取或写入操作完成之前,程序会被阻塞。为了解决这个问题,Java还提供了java.nio(New Input/Output)包,它提供了非阻塞I/O操作和其他高级功能。

标准数据流

在Java中,标准数据流通常指的是System.inSystem.outSystem.err。这些流分别代表标准输入、标准输出和标准错误输出。下面是一个简单的Java IO应用程序示例,它使用这些标准数据流来读取用户输入并输出到控制台。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class StandardStreamExample {
    public static void main(String[] args) {
        // 创建一个BufferedReader来读取标准输入
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        System.out.println("请输入一些文本:");

        try {
            // 读取用户输入的一行文本
            String userInput = reader.readLine();
            System.out.println("你输入的是:" + userInput);
        } catch (IOException e) {
            System.err.println("读取输入时发生错误:" + e.getMessage());
        }
    }
}

在这个例子中,我们使用了以下标准数据流:

  • System.in:这是标准输入流,通常连接到键盘。我们使用BufferedReader包装System.in来读取用户输入的文本。
  • System.out:这是标准输出流,通常连接到控制台。我们使用System.out.println()来向用户显示消息。
  • System.err:这是标准错误输出流,也连接到控制台,但通常用于输出错误消息。在这个例子中,如果readLine()方法抛出IOException,我们使用System.err.println()来输出错误信息。

这个程序的工作流程如下:

  1. 程序启动并显示提示消息,要求用户输入一些文本。
  2. 用户在控制台输入文本并按下回车键。
  3. readLine()方法读取用户输入的文本,并将其存储在userInput变量中。
  4. 程序使用System.out.println()将用户输入的文本输出到控制台。
  5. 如果在读取输入时发生错误(例如,如果输入流被关闭),readLine()方法将抛出IOException,程序将使用System.err.println()输出错误消息。

这个简单的例子展示了如何使用Java IO中的标准数据流来创建基本的输入/输出应用程序。在实际应用中,这些流可以用于更复杂的交互,例如命令行工具或简单的控制台应用程序。


文件输入输出流

在Java中,文件输入输出流允许你读取和写入文件。以下是一个简单的Java IO应用程序示例,它使用文件输入流读取文件内容,并使用文件输出流将内容写入另一个文件。

import java.io.*;

public class FileStreamExample {
    public static void main(String[] args) {
        // 源文件路径
        String sourceFilePath = "source.txt";
        // 目标文件路径
        String destinationFilePath = "destination.txt";

        // 使用文件输入流读取源文件
        try (FileInputStream fis = new FileInputStream(sourceFilePath)) {
            // 使用文件输出流写入目标文件
            try (FileOutputStream fos = new FileOutputStream(destinationFilePath)) {
                // 创建一个缓冲区来存储读取的数据
                byte[] buffer = new byte[1024];
                int lengthRead;

                // 从输入流读取数据到缓冲区
                while ((lengthRead = fis.read(buffer)) > 0) {
                    // 将缓冲区的数据写入输出流
                    fos.write(buffer, 0, lengthRead);
                }

                System.out.println("文件复制成功。");
            } catch (IOException e) {
                System.err.println("写入文件时发生错误:" + e.getMessage());
            }
        } catch (IOException e) {
            System.err.println("读取文件时发生错误:" + e.getMessage());
        }
    }
}

在这个例子中,我们使用了以下文件输入输出流:

  • FileInputStream:用于从源文件读取数据。我们创建了一个FileInputStream实例,并将其连接到源文件source.txt
  • FileOutputStream:用于向目标文件写入数据。我们创建了一个FileOutputStream实例,并将其连接到目标文件destination.txt

程序的工作流程如下:

  1. 创建一个FileInputStream实例,用于从source.txt文件读取数据。
  2. 创建一个FileOutputStream实例,用于将数据写入destination.txt文件。
  3. 创建一个字节数组buffer作为缓冲区,用于存储从输入流读取的数据。
  4. 使用read()方法从输入流读取数据到缓冲区,直到没有更多数据可读。
  5. 使用write()方法将缓冲区的数据写入输出流。
  6. 如果读取或写入过程中发生IOException,程序将使用System.err.println()输出错误消息。

这个简单的例子展示了如何使用Java IO中的文件输入输出流来复制文件。在实际应用中,这些流可以用于更复杂的文件操作,例如文件的读取、写入、追加、删除等。

对象输入输出流

在Java中,对象输入输出流(ObjectInputStream 和 ObjectOutputStream)允许你将对象序列化并存储到文件中,或者从文件中反序列化对象。这通常用于在程序之间传递对象状态,或者在程序退出后保存对象状态以便下次运行时恢复。

以下是一个简单的Java IO应用程序示例,它使用对象输出流将对象写入文件,然后使用对象输入流从文件中读取并恢复对象。

import java.io.*;

// 需要实现Serializable接口
class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class ObjectStreamExample {
    public static void main(String[] args) {
        // 对象输出流使用的文件路径
        String outputFilePath = "person.ser";
        // 对象输入流使用的文件路径
        String inputFilePath = "person.ser";

        // 创建一个Person对象
        Person person = new Person("Alice", 30);

        // 使用对象输出流将对象写入文件
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(outputFilePath))) {
            oos.writeObject(person);
            System.out.println("对象已写入文件。");
        } catch (IOException e) {
            System.err.println("写入对象时发生错误:" + e.getMessage());
        }

        // 使用对象输入流从文件中读取对象
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(inputFilePath))) {
            // 读取对象并强制转换为Person类型
            Person restoredPerson = (Person) ois.readObject();
            System.out.println("从文件中读取的对象:" + restoredPerson);
        } catch (IOException | ClassNotFoundException e) {
            System.err.println("读取对象时发生错误:" + e.getMessage());
        }
    }
}

在这个例子中,我们使用了以下对象输入输出流:

  • ObjectOutputStream:用于将对象序列化并写入文件。我们创建了一个ObjectOutputStream实例,并将其连接到文件输出流。
  • ObjectInputStream:用于从文件中读取序列化的对象并反序列化。我们创建了一个ObjectInputStream实例,并将其连接到文件输入流。

程序的工作流程如下:

  1. 创建一个Person对象,并为其设置名称和年龄。
  2. 创建一个ObjectOutputStream实例,用于将Person对象序列化并写入文件。
  3. 使用writeObject()方法将Person对象写入输出流。
  4. 创建一个ObjectInputStream实例,用于从文件中读取序列化的Person对象并反序列化。
  5. 使用readObject()方法从输入流读取对象,并将其强制转换为Person类型。
  6. 如果序列化或反序列化过程中发生IOExceptionClassNotFoundException,程序将使用System.err.println()输出错误消息。

这个简单的例子展示了如何使用Java IO中的对象输入输出流来序列化和反序列化对象。在实际应用中,这些流可以用于更复杂的对象状态保存和恢复场景。