一.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的值
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
接口的主要特点包括:
-
键的唯一性:
Map
中的每个键必须是唯一的。如果尝试使用相同的键添加新的键值对,那么原有的键值对将被新的键值对替换。 -
键值对:
Map
存储的是键值对,每个键值对被称为一个Entry
。 -
接口实现:
Map
接口有多个实现类,包括HashMap
、LinkedHashMap
、TreeMap
、Hashtable
和ConcurrentHashMap
等。每个实现类都有自己的特点:HashMap
:基于哈希表实现,提供最快的查找速度,但不保证元素的顺序。LinkedHashMap
:基于哈希表和链表实现,保持元素插入的顺序。TreeMap
:基于红黑树实现,提供有序的集合,元素按照键的自然顺序或者通过比较器指定的顺序排列。Hashtable
:一个遗留的类,类似于HashMap
,但它是线程安全的,性能较差。ConcurrentHashMap
:线程安全的HashMap
实现,适用于多线程环境。
-
方法:
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
块中的代码尝试执行一个除以零的操作,这会抛出一个 ArithmeticException
。catch
块捕获了这个异常,并打印出一条错误消息。finally
块中的代码无论如何都会被执行,打印出一条消息。
运行这个程序,你将看到以下输出:
Error: Division by zero is not allowed.
This is the finally block, it always executes.
try...catch
语句是 Java 异常处理机制的核心,它允许你优雅地处理程序中可能出现的错误,从而提高程序的健壮性和可靠性。
二十四.throw 和throws 关键字
在 Java 中,throw
和 throws
是用于处理异常的关键字,但它们的作用和使用场景有所不同。
throw
关键字
throw
关键字用于手动抛出一个异常。当你在代码中遇到需要立即处理的错误情况时,可以使用 throw
来抛出一个异常对象。这个异常对象通常是 java.lang.Throwable
类或其子类的实例。
使用 throw
的语法如下:
throw new ExceptionType("optional message");
其中 ExceptionType
是你想要抛出的异常类型,可以是 Java 内置的异常类,如 IllegalArgumentException
、NullPointerException
等,也可以是你自定义的异常类。
下面是一个使用 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 {
// 方法体
}
其中 ExceptionType1
和 ExceptionType2
是方法可能抛出的异常类型。
下面是一个使用 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.Statement
或 java.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. 关闭连接
在使用完数据库连接后,应该关闭 Connection
、Statement
和 ResultSet
对象,以释放资源。
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中的一些关键类和概念:
-
InputStream(输入流):用于从源读取数据。它是所有字节输入流类的抽象基类。
-
OutputStream(输出流):用于向目标写入数据。它是所有字节输出流类的抽象基类。
-
Reader(读取器):用于读取字符流的抽象类。
-
Writer(写入器):用于写入字符流的抽象类。
-
File(文件):表示文件和目录路径名的抽象表示。
-
FileInputStream(文件输入流):用于从文件读取数据的输入流。
-
FileOutputStream(文件输出流):用于向文件写入数据的输出流。
-
FileReader(文件读取器):用于读取字符文件的便捷类。
-
FileWriter(文件写入器):用于写入字符文件的便捷类。
-
BufferedInputStream(缓冲输入流):为另一个输入流添加缓冲功能。
-
BufferedOutputStream(缓冲输出流):为另一个输出流添加缓冲功能。
-
BufferedReader(缓冲读取器):从字符输入流读取文本,并提供缓冲功能。
-
BufferedWriter(缓冲写入器):向字符输出流写入文本,并提供缓冲功能。
-
DataInputStream(数据输入流):允许应用程序以与机器无关的方式从底层输入流中读取基本Java数据类型。
-
DataOutputStream(数据输出流):允许应用程序以与机器无关的方式将基本Java数据类型写入输出流。
-
PrintStream(打印流):提供格式化输出功能。
-
PrintWriter(打印写入器):提供格式化输出功能,用于字符流。
-
ObjectInputStream(对象输入流):用于从输入流读取Java对象(对象序列化)。
-
ObjectOutputStream(对象输出流):用于将Java对象写入输出流(对象序列化)。
Java IO库提供了丰富的功能,可以处理各种输入和输出需求。然而,Java IO是阻塞的,意味着在读取或写入操作完成之前,程序会被阻塞。为了解决这个问题,Java还提供了java.nio
(New Input/Output)包,它提供了非阻塞I/O操作和其他高级功能。
标准数据流
在Java中,标准数据流通常指的是System.in
、System.out
和System.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()
来输出错误信息。
这个程序的工作流程如下:
- 程序启动并显示提示消息,要求用户输入一些文本。
- 用户在控制台输入文本并按下回车键。
readLine()
方法读取用户输入的文本,并将其存储在userInput
变量中。- 程序使用
System.out.println()
将用户输入的文本输出到控制台。 - 如果在读取输入时发生错误(例如,如果输入流被关闭),
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
。
程序的工作流程如下:
- 创建一个
FileInputStream
实例,用于从source.txt
文件读取数据。 - 创建一个
FileOutputStream
实例,用于将数据写入destination.txt
文件。 - 创建一个字节数组
buffer
作为缓冲区,用于存储从输入流读取的数据。 - 使用
read()
方法从输入流读取数据到缓冲区,直到没有更多数据可读。 - 使用
write()
方法将缓冲区的数据写入输出流。 - 如果读取或写入过程中发生
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
实例,并将其连接到文件输入流。
程序的工作流程如下:
- 创建一个
Person
对象,并为其设置名称和年龄。 - 创建一个
ObjectOutputStream
实例,用于将Person
对象序列化并写入文件。 - 使用
writeObject()
方法将Person
对象写入输出流。 - 创建一个
ObjectInputStream
实例,用于从文件中读取序列化的Person
对象并反序列化。 - 使用
readObject()
方法从输入流读取对象,并将其强制转换为Person
类型。 - 如果序列化或反序列化过程中发生
IOException
或ClassNotFoundException
,程序将使用System.err.println()
输出错误消息。
这个简单的例子展示了如何使用Java IO中的对象输入输出流来序列化和反序列化对象。在实际应用中,这些流可以用于更复杂的对象状态保存和恢复场景。
停留在世界边缘,与之惜别