简介:Java是一种广泛使用的面向对象编程语言,涵盖了从基础语法到高级特性的多个方面。本资源包含100个Java编程示例,旨在帮助学习者深入理解和掌握Java的核心概念及特性。通过这些实例,学习者可以学习基础语法、数据类型、函数、类与对象、异常处理、集合框架、多线程、输入/输出流、泛型、枚举与注解、反射、集合接口以及设计模式等。实践这些实例能够提高编程技能、问题解决能力以及编程思维,为实际项目的应用打下坚实基础。 
1. Java基础语法与实例
Java是一种广泛使用的面向对象的编程语言,其基础语法是构建Java应用程序的基石。本章节将带您了解Java的基础语法,包括变量声明、控制结构、循环以及数组等,并将通过简单的实例加深理解。
1.1 Java变量和数据类型
在Java中,所有变量在使用前都必须声明,类型是必须提供的信息,它可以告诉编译器变量存储什么类型的数据,例如整型(int)、浮点型(double)、字符型(char)和布尔型(boolean)。变量命名应遵循一些规则,例如以字母、下划线开头,后接字母、数字和下划线的组合。
int number = 10; // 整型变量
double salary = 10.50; // 浮点型变量
char grade = 'A'; // 字符型变量
boolean isJavaFun = true; // 布尔型变量
1.2 控制结构和循环
Java提供了一组用于控制程序流程的关键字: if , else , switch , for , while 和 do-while 。这些结构允许程序根据不同的条件执行不同的代码分支,并能够创建循环以重复执行代码块。
if (isJavaFun) {
System.out.println("Java 是有趣的!");
} else {
System.out.println("Java 不是有趣的。");
}
for (int i = 0; i < 10; i++) {
System.out.println("循环次数: " + i);
}
1.3 数组与方法定义
数组是Java中用于存储固定大小的同类型元素的数据结构。创建数组后,可以通过索引访问其元素。此外,Java中定义方法也是不可或缺的一部分,它允许我们对一组代码进行命名,之后可以通过方法名调用执行。
int[] numbers = new int[5]; // 创建一个整型数组
numbers[0] = 1; // 赋值数组元素
public void printNumbers(int[] array) { // 定义一个打印数组的方法
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
printNumbers(numbers); // 调用方法打印数组元素
本章通过Java基础语法的介绍,为初学者提供了编程的初步理解和应用,以及如何通过实际代码示例来实践和掌握Java编程的核心概念。随着章节的深入,我们将会探讨更加复杂的概念和编程技巧。
2. Java数据类型及其使用
2.1 基本数据类型的介绍与实例
2.1.1 整型、浮点型、字符型和布尔型的特点和使用场景
Java语言中,数据类型主要分为两大类:基本数据类型和引用数据类型。基本数据类型包括整型、浮点型、字符型和布尔型,它们在内存中是预定义的,并且拥有固定大小,用于存储原始值。
整型 用于表示没有小数部分的数字,包括byte, short, int, long。byte类型是8位,适合存储很小的数值,通常用于处理字节级的数据。short类型是16位,int类型是32位,而long类型是64位,能够存储更大范围的整数。
int num = 100; // int类型的整数
long bigNum = ***L; // long类型的整数,末尾加L表示
浮点型 用于表示有小数部分的数字,包括float和double。float类型是单精度(32位),而double类型是双精度(64位)。double类型提供更高的精度,通常用于科学计算。
float smallFloat = 10.5f; // float类型的浮点数,末尾加f表示
double largeDouble = ***.***; // double类型的浮点数
字符型 只有一个类型,即char,它是16位的,用于存储单个字符,使用单引号表示字符常量。
char letter = 'A'; // char类型的字符
布尔型 包括boolean类型,只有两个值:true和false。它用于逻辑运算和条件控制。
boolean isTrue = true; // boolean类型的布尔值
使用场景: - 整型 :用于计数、循环控制、数组索引等操作。 - 浮点型 :用于金融计算、科学计算和需要高精度处理小数的场景。 - 字符型 :用于处理文本数据,如字符串构建等。 - 布尔型 :用于条件判断、逻辑运算、表示真/假状态。
2.1.2 数据类型之间的转换规则与实例
在Java中,数据类型的转换分为自动(隐式)转换和强制(显式)转换。
自动转换 发生于较小类型向较大类型转换时,如int转为double,无需编写转换代码,由JVM自动完成。
int i = 10;
double d = i; // 自动转换为double类型
强制转换 则是将较大类型转为较小类型,必须使用类型转换运算符()进行显式转换,可能会导致精度损失。
double d = 10.1;
int i = (int) d; // 强制转换为int类型,小数部分会被截断
强制转换的代码示例如下:
int i = 100;
byte b = (byte) i; // 正确的强制转换
int j = 300;
byte b2 = (byte) j; // 这可能会导致编译错误:possible loss of precision
转换规则中应注意以下几点: 1. 如果目标类型不能容纳原值,会发生溢出。 2. 对于float和double,自动转换时可能会有精度损失,因此应谨慎处理。 3. 布尔型不能转换为其他基本数据类型,其他基本数据类型也不能转换为布尔型。
2.2 引用数据类型的介绍与实例
2.2.1 类、接口、数组的声明和初始化
在Java中,引用数据类型包括类(class)、接口(interface)、数组(array)等。
类 是创建对象的模板,通过关键字class声明,可包含属性、方法和构造器。
class Person {
String name; // 属性
int age; // 属性
void sayHello() { // 方法
System.out.println("Hello, I'm " + name);
}
}
接口 声明了类或者对象应该具有的方法,但不提供这些方法的具体实现。通过关键字interface声明。
interface CanFly {
void fly(); // 抽象方法
}
数组 用于存储固定数量的同类型元素。通过在数据类型后面加上方括号[]来声明。
int[] numbers = new int[5]; // 声明并初始化一个整型数组
初始化数组时,可以使用初始化块或在声明时直接提供元素值。
// 使用初始化块初始化数组
int[] numbers = {1, 2, 3, 4, 5};
// 使用初始化块分开声明和初始化
int[] numbers;
numbers = new int[] {1, 2, 3, 4, 5};
2.2.2 字符串的创建和常用方法应用
字符串 在Java中是通过String类实现的。String对象一旦创建,其内容是不可变的。
String str = "Hello World"; // 创建字符串对象
String类提供了丰富的内置方法用于字符串操作,例如字符串连接、转换大小写、查找子字符串等。
String s1 = "Hello";
String s2 = "World";
String combined = s1.concat(s2); // 连接字符串s2到s1的末尾,得到"HelloWorld"
boolean startsWithHello = combined.startsWith("Hello"); // 检查字符串是否以"Hello"开头,结果为true
int indexOfWorld = combined.indexOf("World"); // 查找字符串中"World"的索引位置,结果为5
其他常见的字符串操作方法:
// 截取子字符串
String subStr = combined.substring(0, 5); // "Hello"
// 转换为大写或小写
String toUpperCase = combined.toUpperCase(); // "HELLOWORLD"
String toLowerCase = combined.toLowerCase(); // "helloworld"
// 分割字符串
String[] parts = combined.split(" "); // 使用空格分割字符串,得到数组{"Hello", "World"}
字符串的不可变性意味着任何对字符串的修改都会生成新的字符串对象。因此,在处理大量字符串或频繁修改的场景时,应考虑到性能开销。
3. Java函数定义与应用
3.1 函数的基本概念与定义
3.1.1 函数的声明、返回值和参数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。在 Java 中,每一个函数都是一个方法的一部分,而方法是类的一个成员。
函数声明包括四部分:访问修饰符、返回类型、函数名和参数类型。返回类型是指定函数返回值的数据类型,如果函数没有返回值,则使用 void 。
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
在上述代码中, add 函数接受两个 int 类型的参数,并返回一个 int 类型的结果。参数列表 int a, int b 表示两个整型输入参数。
3.1.2 递归函数的原理和应用
递归函数是一种调用自身的函数。每一级的函数调用都会保存其状态,以便后续返回到该状态继续执行。
递归的典型例子是计算阶乘:
public class Factorial {
public int factorial(int n) {
if (n <= 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
}
在上述代码中, factorial 函数会递归调用自己,直到 n 减到 1 为止。
3.2 函数的高级应用
3.2.1 函数式编程简介和Lambda表达式
函数式编程是一种编程范式,强调使用函数来表达计算。在 Java 中,Lambda 表达式提供了实现函数式编程的方式。
Lambda 表达式的基本语法是:
parameters -> expression
或者:
parameters -> { statements; }
以下是一个使用 Lambda 表达式的简单例子:
// 使用 Lambda 表达式
button.setOnClickListener(event -> System.out.println("Button clicked!"));
3.2.2 方法引用和构造函数引用的使用
方法引用允许你直接引用方法、构造函数或者实例的字段。在 Java 中,方法引用使用 :: 操作符。
方法引用的类型主要有以下几种:
- 引用静态方法:
ContainingClass::staticMethodName - 引用某个对象的方法:
containingObject::instanceMethodName - 引用某个类的方法:
ContainingType::methodName - 构造函数引用:
ClassName::new
例如,使用方法引用重写之前的 Lambda 表达式:
button.setOnClickListener(System.out::println);
在上面的代码中,我们引用了 System.out 的 println 方法,作为点击事件的响应。
接下来,我们探讨一个具体的使用场景,例如一个对象池,我们可以通过构造函数引用来实现对象池中对象的实例化:
Supplier<Object> objectPoolFactory = Object::new;
Object instance = objectPoolFactory.get();
以上代码片段演示了如何使用构造函数引用 Object::new 来快速创建一个新的对象实例。
通过上述章节的学习,你应该对 Java 函数的定义、声明和使用有了深入的理解。无论是基础函数的定义还是高级特性的应用,如 Lambda 表达式和方法引用,都为 Java 开发提供了强大的功能和灵活性。在实际的编程实践中,灵活运用这些知识可以极大提升代码的可读性和效率。
4. 类与对象的面向对象设计
4.1 类与对象的定义和创建
4.1.1 类的属性、方法和构造器
在Java中,类是面向对象编程的核心,它封装了数据和操作数据的方法。一个类可以包含属性、方法和构造器。属性相当于C语言中的结构体成员变量,它定义了类的状态;方法类似于函数,定义了类的行为;构造器是一个特殊的方法,用于在创建对象时初始化对象。
属性 是类的变量,用于存储对象的状态信息。在定义属性时,可以指定其类型和访问修饰符。访问修饰符控制了属性的可访问范围,常用的有 public 、 private 和 protected 。
方法 是定义在类内部的函数,它描述了类的行为。方法可以接收参数,并且可以有返回值。方法也可以使用访问修饰符来控制访问权限。
构造器 是一种特殊的方法,其名称必须与类名相同,并且不返回任何类型。构造器的主要目的是在创建对象时初始化对象的属性。
下面是一个简单的Java类的示例,其中包含了属性、方法和构造器:
public class Person {
// 类的属性
private String name;
private int age;
// 构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void introduce() {
System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}
}
在这个 Person 类中,我们定义了两个属性 name 和 age ,一个构造器用于初始化这两个属性,以及几个方法来获取和设置属性的值,并且有一个 introduce 方法用于打印个人信息。
4.1.2 对象的生成和引用
在Java中,对象是类的实例。创建对象的语法如下:
类名 对象名 = new 类名(参数列表);
例如,根据 Person 类创建一个对象:
Person person = new Person("Alice", 30);
这里, person 是对 Person 类实例的引用,通过这个引用,我们可以访问对象的属性和方法。
对象的生命周期从 new 关键字开始,直到没有引用指向它,并且被垃圾回收器回收为止。创建对象时,会在堆内存中分配空间,并且构造器会被调用以初始化对象。
4.1.3 综合实例
下面是一个综合的实例,演示了如何在Java中定义一个 Car 类,创建对象,并且通过方法来操作对象:
public class Car {
// 类的属性
private String model;
private int year;
// 构造器
public Car(String model, int year) {
this.model = model;
this.year = year;
}
// 方法
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public void drive() {
System.out.println("Driving " + model + " from " + year + ".");
}
}
// 主类
public class Main {
public static void main(String[] args) {
// 创建Car类的对象
Car myCar = new Car("Tesla", 2020);
// 调用对象的方法
myCar.drive(); // 输出: Driving Tesla from 2020.
}
}
在上述代码中, Car 类定义了汽车的属性和行为,包括模型和年份。我们创建了一个 Car 类的对象 myCar ,并调用了 drive 方法来模拟汽车驾驶。
4.2 面向对象的高级特性
4.2.1 继承、多态和封装的概念及其应用
继承 是面向对象设计中一个重要的特性,它允许我们创建一个新类,这个新类包含另一个类的属性和方法。这样做的目的是为了代码重用和逻辑的组织。继承使用关键字 extends 来实现。
多态 意味着同一个操作作用于不同的对象,可以有不同的解释和不同的执行结果。多态通常通过方法重载和方法重写来实现。
封装 是面向对象编程的一个核心概念,它意味着将数据(属性)和操作数据的代码(方法)捆绑在一起。封装的目的是隐藏对象的内部细节,只暴露一个公共的接口来访问对象。
下面是一个继承和封装的示例:
class Vehicle {
// 封装属性
private String color;
public Vehicle(String color) {
this.color = color;
}
// 封装方法
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void start() {
System.out.println("Vehicle is starting.");
}
}
// 派生类继承Vehicle
class Car extends Vehicle {
private int numberOfDoors;
public Car(String color, int numberOfDoors) {
super(color); // 调用父类的构造器
this.numberOfDoors = numberOfDoors;
}
public void drive() {
System.out.println("Car is driving.");
}
// 重写父类的方法
@Override
public void start() {
System.out.println("Car is starting with " + numberOfDoors + " doors.");
}
}
public class Main {
public static void main(String[] args) {
Car myCar = new Car("Red", 4);
myCar.start(); // 输出: Car is starting with 4 doors.
myCar.drive(); // 输出: Car is driving.
}
}
在这个例子中, Car 类继承自 Vehicle 类。 Car 类有自己的属性 numberOfDoors 和特有的方法 drive 。同时, Car 类重写了 Vehicle 类中的 start 方法,展示了多态的特性。通过 super 关键字调用了父类的构造器。这显示了继承和封装的典型应用。
4.2.2 抽象类和接口的使用场景和规则
抽象类 是不能被实例化的类,它通常用于表示一个概念或框架。抽象类可以包含抽象方法(没有方法体的方法),以及具体的方法和属性。当一个类继承抽象类时,它必须实现所有的抽象方法,除非它自己也被声明为抽象类。
接口 是一种特殊的抽象类,它完全由抽象方法和常量组成。接口的目的是定义一个协议,类可以实现这个协议。自Java 8起,接口也可以包含默认方法和静态方法,这为接口增加了更多的灵活性。
下面是一个使用抽象类和接口的示例:
// 抽象类
abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public abstract void makeSound();
public void sleep() {
System.out.println(name + " is sleeping.");
}
}
// 接口
interface IFlyable {
void fly();
}
// 实现接口的类
class Bird extends Animal implements IFlyable {
public Bird(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + " is chirping.");
}
@Override
public void fly() {
System.out.println(name + " is flying.");
}
}
public class Main {
public static void main(String[] args) {
Bird myBird = new Bird("Parrot");
myBird.makeSound(); // 输出: Parrot is chirping.
myBird.sleep(); // 输出: Parrot is sleeping.
myBird.fly(); // 输出: Parrot is flying.
}
}
在这个例子中, Animal 是一个抽象类,定义了一个抽象方法 makeSound 和一个具体方法 sleep 。 Bird 类继承了 Animal 类并实现了 IFlyable 接口,这表明了 Bird 类可以发声,并且会飞。这个实例展示了抽象类和接口的使用场景和规则。
这一章节到此为止,我们学习了类与对象的基础定义,以及面向对象设计的高级特性。下一章节我们将深入探讨Java异常处理机制。
5. Java异常处理机制
在Java编程中,处理异常是确保程序健壮性的重要环节。异常处理机制不仅能够帮助我们捕获运行时错误,还可以帮助我们更加优雅地处理错误情况,提高程序的可用性和用户体验。
5.1 异常处理的基本概念
5.1.1 异常类的层次结构
Java中的所有异常类都是从 Throwable 类派生而来,它有两个重要的子类: Error 和 Exception 。 Error 通常表示系统级错误,如虚拟机错误,应用无法处理这些错误。而 Exception 则分为两类: RuntimeException 和非 RuntimeException 。 RuntimeException 通常是由于代码逻辑错误引起的,如空指针异常,数组越界等,这类异常在编译时不需要强制处理;非 RuntimeException 则需要显式地进行捕获和处理,否则编译会报错。
try {
// 可能抛出异常的代码
} catch (ExceptionType1 e1) {
// 处理ExceptionType1类型的异常
} catch (ExceptionType2 e2) {
// 处理ExceptionType2类型的异常
} finally {
// 无论是否发生异常都会执行的代码
}
5.1.2 try-catch-finally语句的使用方法
在Java中,异常处理最常见的语法结构是 try-catch-finally 语句块。 try 块中包含了可能发生异常的代码, catch 块用来捕获 try 块中发生的异常类型,并提供相应的处理逻辑。 finally 块中的代码无论是否发生异常都会执行,通常用于释放资源。
try {
FileInputStream fileInputStream = new FileInputStream("file.txt");
// 文件操作代码
} catch (FileNotFoundException e) {
// 文件未找到的处理逻辑
e.printStackTrace();
} finally {
// 关闭文件流,释放资源
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.2 自定义异常和异常链
5.2.1 如何自定义异常类
Java允许我们自定义异常类,通常通过继承 Exception 或其子类来实现。自定义异常类一般需要提供两个构造器:一个是无参构造器,另一个是带有详细信息的构造器,它们最终都会调用父类的构造器。
public class MyCustomException extends Exception {
// 自定义异常构造器
public MyCustomException(String message) {
super(message);
}
public MyCustomException(String message, Throwable cause) {
super(message, cause);
}
// 其他方法...
}
5.2.2 异常链的构建和好处
异常链是一种特殊的异常处理方式,它允许一个异常对象通过构造器或特定的方法与另一个异常对象关联起来。这样做的好处是,除了捕获并处理异常之外,还可以将原始异常信息封装起来,继续向上层传递,而不丢失原始的错误信息,这对于错误的调试和日志记录非常有帮助。
try {
// 某些操作导致了异常
} catch (Exception e) {
// 创建一个新的异常对象,包装原始异常信息
throw new MyCustomException("无法处理的异常发生了", e);
}
在实际的项目中,合理地使用异常处理机制,可以使得代码更加健壮,便于维护。通过学习并应用本章节所介绍的异常处理和自定义异常,可以使得你在遇到运行时错误时,能够更加优雅地处理它们,而不是让程序因为未捕获的异常而意外终止。
简介:Java是一种广泛使用的面向对象编程语言,涵盖了从基础语法到高级特性的多个方面。本资源包含100个Java编程示例,旨在帮助学习者深入理解和掌握Java的核心概念及特性。通过这些实例,学习者可以学习基础语法、数据类型、函数、类与对象、异常处理、集合框架、多线程、输入/输出流、泛型、枚举与注解、反射、集合接口以及设计模式等。实践这些实例能够提高编程技能、问题解决能力以及编程思维,为实际项目的应用打下坚实基础。

1万+

被折叠的 条评论
为什么被折叠?



