Java基础知识二

news/2025/2/12 1:41:47/文章来源:https://www.cnblogs.com/qiaozc/p/18710825

二十、断言(Assertion)

20.1 断言概述

断言是一种调试工具,用于在代码中插入一些检查点,确保程序在执行到这些点时某些条件为真。如果断言条件为假,会抛出 AssertionError 异常。断言主要用于开发和测试阶段,帮助程序员快速定位错误。

20.2 断言的语法

Java 中的断言使用 assert 关键字,有两种形式:

  • 简单形式assert condition;
int num = 10;
assert num > 5; // 如果 num <= 5,会抛出 AssertionError
  • 带消息形式assert condition : message;
int value = -1;
assert value >= 0 : "Value must be non - negative"; 

20.3 启用和禁用断言

默认情况下,Java 虚拟机是禁用断言的。要启用断言,可以在运行 Java 程序时使用 -ea-enableassertions 的缩写)选项。例如:

收起

sh

java -ea MyClass

要禁用断言,可以使用 -da-disableassertions 的缩写)选项。

二十一、包(Package)

21.1 包的概念

包是 Java 中组织类和接口的一种方式,它可以避免命名冲突,提高代码的可维护性和可管理性。包可以包含类、接口、子包等。

21.2 包的声明和使用

  • 声明包:在 Java 源文件的第一行使用 package 关键字声明包名。
package com.example.myapp;public class MyClass {// 类的定义
}
  • 使用包中的类:可以使用全限定名或 import 语句来使用包中的类。
// 使用全限定名
com.example.myapp.MyClass obj = new com.example.myapp.MyClass();// 使用 import 语句
import com.example.myapp.MyClass;
MyClass obj2 = new MyClass();

21.3 包的访问权限

包可以影响类和成员的访问权限。例如,默认(没有任何访问修饰符)的类和成员只能被同一个包中的其他类访问。

二十二、包访问权限和访问控制总结

22.1 访问修饰符回顾

Java 中有四种访问修饰符:privatedefault(默认,无关键字)、protectedpublic,它们对类、成员变量和方法的访问权限限制如下:

访问修饰符 本类 同一个包中的类 不同包中的子类 不同包中的非子类
private 可以访问 不可以访问 不可以访问 不可以访问
default 可以访问 可以访问 不可以访问 不可以访问
protected 可以访问 可以访问 可以访问 不可以访问
public 可以访问 可以访问 可以访问 可以访问

22.2 类的访问权限

类可以使用 public 或默认访问修饰符。如果一个类被声明为 public,则该类可以被任何包中的其他类访问;如果没有指定访问修饰符(默认),则该类只能被同一个包中的其他类访问。

22.3 成员的访问权限

成员变量和方法可以使用四种访问修饰符中的任何一种。private 成员只能在本类中访问;default 成员可以在同一个包中的类中访问;protected 成员除了可以在同一个包中的类访问外,还可以在不同包的子类中访问;public 成员可以被任何类访问。

二十三、Java 中的命令行参数

23.1 命令行参数的概念

命令行参数是在运行 Java 程序时传递给主方法(main 方法)的参数。main 方法的签名为 public static void main(String[] args),其中 args 是一个字符串数组,用于接收命令行参数。

23.2 使用命令行参数

public class CommandLineArgsExample {public static void main(String[] args) {if (args.length > 0) {System.out.println("Command line arguments:");for (String arg : args) {System.out.println(arg);}} else {System.out.println("No command line arguments provided.");}}
}

要运行这个程序并传递命令行参数,可以在命令行中这样做:

收起

sh

java CommandLineArgsExample arg1 arg2 arg3

二十四、Java 中的命令行编译和运行

24.1 编译 Java 程序

使用 javac 命令来编译 Java 源文件。例如,要编译一个名为 MyClass.java 的源文件,可以在命令行中输入:

收起

sh

javac MyClass.java

这会在当前目录下生成一个名为 MyClass.class 的字节码文件。

24.2 运行 Java 程序

使用 java 命令来运行编译好的 Java 程序。例如,要运行 MyClass 类的 main 方法,可以在命令行中输入:

收起

sh

java MyClass

如果程序需要命令行参数,可以在类名后面跟上参数,如:

收起

sh

java MyClass arg1 arg2

24.3 编译和运行带包的 Java 程序

如果 Java 程序使用了包,编译和运行时需要注意目录结构和类路径。假设 MyClass 类位于 com.example 包中,源文件的目录结构应该是 com/example/MyClass.java。编译时可以使用以下命令:

收起

sh

javac com/example/MyClass.java

运行时需要指定完整的类名(包括包名):

收起

sh

java com.example.MyClass

二十五、Java 中的注解处理器 API

25.1 注解处理器概述

注解处理器 API(javax.annotation.processing)允许开发者在编译时处理注解。注解处理器可以读取、修改和生成 Java 源代码,常用于生成代码、验证代码等场景。

25.2 自定义注解处理器

要创建自定义注解处理器,需要继承 AbstractProcessor 类,并实现 process 方法。以下是一个简单的示例:

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import java.util.Set;@SupportedAnnotationTypes("com.example.MyAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyAnnotationProcessor extends AbstractProcessor {@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {for (TypeElement annotation : annotations) {System.out.println("Processing annotation: " + annotation.getSimpleName());}return true;}
}

要使用这个注解处理器,需要将其注册到 Java 编译器中。可以通过创建 META - INF/services/javax.annotation.processing.Processor 文件,并在文件中指定注解处理器的全限定名来实现。

二十六、Java 中的 Lambda 表达式和函数式接口

26.1 Lambda 表达式概述

Lambda 表达式是 Java 8 引入的一种简洁的语法,用于表示匿名函数。它可以作为参数传递给方法,使代码更加简洁和易读。

26.2 Lambda 表达式的语法

Lambda 表达式的基本语法为:(parameters) -> expression(parameters) -> { statements; }

// 无参数的 Lambda 表达式
Runnable runnable = () -> System.out.println("Running...");
new Thread(runnable).start();// 有参数的 Lambda 表达式
java.util.List<Integer> numbers = java.util.Arrays.asList(1, 2, 3, 4, 5);
numbers.forEach((Integer num) -> System.out.println(num));

26.3 函数式接口

函数式接口是只包含一个抽象方法的接口。Lambda 表达式可以用于实现函数式接口。Java 提供了一些内置的函数式接口,如 PredicateConsumerFunction 等。

import java.util.function.Predicate;Predicate<Integer> isEven = (num) -> num % 2 == 0;
System.out.println(isEven.test(4)); // 输出 true

二十七、Java 中的 Stream API

27.1 Stream API 概述

Stream API 是 Java 8 引入的一种处理集合数据的新方式,它提供了一种声明式的操作方式,使得代码更加简洁和易读。Stream 可以对集合中的元素进行过滤、映射、排序等操作。

27.2 创建 Stream

可以通过集合、数组等创建 Stream。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream();

27.3 Stream 操作

  • 中间操作:如 filtermapsorted 等,中间操作会返回一个新的 Stream。
Stream<Integer> evenNumbers = stream.filter(num -> num % 2 == 0);
  • 终端操作:如 forEachcollectcount 等,终端操作会触发 Stream 的执行并产生结果。
evenNumbers.forEach(System.out::println);

以上进一步丰富了 Java 基础知识的内容,涵盖了从断言、包管理、命令行操作到 Java 8 新特性(Lambda 表达式、Stream API)等多个方面,这些知识是构建更复杂 Java 应用的基石。

二十八、方法引用

28.1 方法引用概述

方法引用是 Java 8 引入的一种简化 Lambda 表达式的语法糖,它允许直接引用已有的方法或构造函数,使代码更加简洁易读。方法引用可以看作是 Lambda 表达式的一种特殊形式,当 Lambda 表达式只是简单地调用一个已存在的方法时,就可以使用方法引用。

28.2 方法引用的类型

静态方法引用

语法:类名::静态方法名

import java.util.Arrays;
import java.util.List;class MathUtils {public static int square(int num) {return num * num;}
}public class StaticMethodReferenceExample {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);numbers.stream().map(MathUtils::square).forEach(System.out::println);}
}

实例方法引用

语法:对象名::实例方法名

import java.util.Arrays;
import java.util.List;class StringUtils {public boolean isUpperCase(String str) {return str.equals(str.toUpperCase());}
}public class InstanceMethodReferenceExample {public static void main(String[] args) {StringUtils utils = new StringUtils();List<String> words = Arrays.asList("HELLO", "world", "JAVA");words.stream().filter(utils::isUpperCase).forEach(System.out::println);}
}

特定类型的实例方法引用

语法:类名::实例方法名

import java.util.Arrays;
import java.util.List;public class SpecificTypeInstanceMethodReferenceExample {public static void main(String[] args) {List<String> words = Arrays.asList("apple", "banana", "cherry");words.stream().map(String::length).forEach(System.out::println);}
}

构造方法引用

语法:类名::new

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;class Person {private String name;public Person(String name) {this.name = name;}public String getName() {return name;}
}public class ConstructorMethodReferenceExample {public static void main(String[] args) {List<String> names = Arrays.asList("Alice", "Bob", "Charlie");List<Person> people = names.stream().map(Person::new).collect(Collectors.toList());people.forEach(person -> System.out.println(person.getName()));}
}

二十九、Optional 类

29.1 Optional 类概述

Optional 类是 Java 8 引入的一个容器类,用于表示一个值可能存在也可能不存在的情况。它可以避免 NullPointerException,使代码更加健壮。

29.2 创建 Optional 对象

import java.util.Optional;// 创建一个包含值的 Optional 对象
Optional<String> optionalWithValue = Optional.of("Hello");// 创建一个可能为空的 Optional 对象
Optional<String> optionalNullable = Optional.ofNullable(null);// 创建一个空的 Optional 对象
Optional<String> emptyOptional = Optional.empty();

29.3 Optional 的常用方法

import java.util.Optional;public class OptionalExample {public static void main(String[] args) {Optional<String> optional = Optional.of("Hello");// 判断 Optional 是否包含值boolean isPresent = optional.isPresent();System.out.println("Is present: " + isPresent);// 获取 Optional 中的值,如果值不存在会抛出 NoSuchElementExceptionString value = optional.get();System.out.println("Value: " + value);// 如果值存在则执行操作optional.ifPresent(str -> System.out.println("Value is: " + str));// 如果值不存在则返回指定的默认值String defaultValue = optional.orElse("Default");System.out.println("Default value: " + defaultValue);// 如果值不存在则执行指定的操作optional.orElseGet(() -> {System.out.println("Value is absent, doing something...");return "Generated value";});}
}

三十、CompletableFuture 类

30.1 CompletableFuture 类概述

CompletableFuture 是 Java 8 引入的一个强大的异步编程工具,它实现了 Future 接口,同时提供了丰富的方法来处理异步任务的完成、组合和异常处理。

30.2 创建 CompletableFuture 对象

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;public class CompletableFutureCreationExample {public static void main(String[] args) throws ExecutionException, InterruptedException {// 创建一个已经完成的 CompletableFutureCompletableFuture<String> completedFuture = CompletableFuture.completedFuture("Result");System.out.println(completedFuture.get());// 异步执行任务CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return "Async result";});System.out.println(future.get());}
}

30.3 CompletableFuture 的组合和链式调用

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;public class CompletableFutureCombinationExample {public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");// 组合两个 CompletableFutureCompletableFuture<String> combinedFuture = future1.thenCombine(future2, (s1, s2) -> s1 + " " + s2);System.out.println(combinedFuture.get());// 链式调用CompletableFuture<String> chainedFuture = future1.thenApply(s -> s + "!").thenApply(String::toUpperCase);System.out.println(chainedFuture.get());}
}

30.4 CompletableFuture 的异常处理

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;public class CompletableFutureExceptionHandlingExample {public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {if (Math.random() < 0.5) {throw new RuntimeException("Something went wrong");}return "Success";});CompletableFuture<String> handledFuture = future.exceptionally(ex -> {System.out.println("Exception: " + ex.getMessage());return "Recovered result";});System.out.println(handledFuture.get());}
}

三十一、Java 中的模块化系统(Java 9+)

31.1 模块化系统概述

Java 9 引入了模块化系统(Project Jigsaw),旨在解决大型项目中类路径的复杂性、依赖管理困难等问题。模块化系统允许将代码组织成模块,每个模块有明确的依赖关系和导出的包。

31.2 模块的定义

在 Java 9 及以后的版本中,可以通过 module-info.java 文件来定义模块。例如:

// module-info.java
module mymodule {// 导出包,其他模块可以访问这些包中的类exports com.example.mypackage;// 依赖其他模块requires othermodule;
}

31.3 模块化编译和运行

编译模块化代码

收起

sh

javac --module-source-path src -d mods $(find src -name "*.java")

运行模块化程序

收起

sh

java --module-path mods -m mymodule/com.example.mypackage.Main

三十二、Java 中的密封类和接口(Java 15+)

32.1 密封类和接口概述

Java 15 引入了密封类和接口,用于限制哪些类可以继承该类或实现该接口。通过使用 sealed 关键字,可以明确指定允许的子类或实现类,增强了代码的安全性和可维护性。

32.2 密封类的定义和使用

// 定义密封类
public sealed class Shape permits Circle, Rectangle {// 类的定义
}// 定义允许的子类
final class Circle extends Shape {// 子类的定义
}non-sealed class Rectangle extends Shape {// 子类的定义
}

在上述示例中,Shape 是一个密封类,只有 CircleRectangle 可以继承它。Circle 被声明为 final,表示它不能再被其他类继承;Rectangle 被声明为 non-sealed,表示它的子类不受限制。

32.3 密封接口的定义和使用

// 定义密封接口
public sealed interface Animal permits Dog, Cat {void makeSound();
}// 定义允许的实现类
final class Dog implements Animal {@Overridepublic void makeSound() {System.out.println("Woof!");}
}non-sealed class Cat implements Animal {@Overridepublic void makeSound() {System.out.println("Meow!");}
}

这里,Animal 是一个密封接口,只有 DogCat 可以实现它。同样,Dogfinal 类,Catnon-sealed 类。

这些内容进一步丰富了 Java 基础知识体系,涵盖了 Java 8 及以后版本引入的一些重要特性,对于理解和运用现代 Java 编程至关重要。

三十三、文本块(Java 13+)

33.1 文本块概述

文本块是 Java 13 引入的新特性,它提供了一种更方便的方式来处理多行字符串,避免了传统字符串拼接中繁琐的换行符和转义字符。

33.2 文本块的语法

文本块使用三个双引号(""")作为开始和结束标记,并且可以包含换行符、制表符等,无需进行额外的转义。

public class TextBlockExample {public static void main(String[] args) {String html = """<html><body><h1>Hello, World!</h1></body></html>""";System.out.println(html);}
}

33.3 文本块的处理

文本块在编译时会进行一些处理,例如去除每行的前导空格,并且可以使用 \s 来保留一个空格。

String poem = """Twinkle, twinkle, little star,How I wonder what you are.Up above the world so high,Like a diamond in the sky.""";
// 输出时会按照预期的格式输出,去除每行前面多余的空格
System.out.println(poem);

三十四、记录类(Java 14+)

34.1 记录类概述

记录类(Record)是 Java 14 引入的一种特殊类,用于表示不可变的数据载体。它可以自动生成构造方法、getter 方法、equals()hashCode()toString() 方法,减少了样板代码。

34.2 记录类的定义和使用

// 定义记录类
record Person(String name, int age) {// 可以添加额外的方法public String getNameAndAge() {return name + " is " + age + " years old.";}
}public class RecordExample {public static void main(String[] args) {Person person = new Person("Alice", 25);System.out.println(person.name()); // 自动生成的 getter 方法System.out.println(person.getNameAndAge());}
}

34.3 记录类的特点

  • 不可变性:记录类的属性是不可变的,一旦创建,其值不能被修改。
  • 紧凑构造方法:可以定义紧凑构造方法来进行参数验证等操作。
record Point(int x, int y) {// 紧凑构造方法public Point {if (x < 0 || y < 0) {throw new IllegalArgumentException("Coordinates cannot be negative.");}}
}

三十五、模式匹配(Java 14+)

35.1 模式匹配概述

模式匹配是 Java 14 开始逐步引入的特性,它可以简化类型检查和类型转换的代码,使代码更加简洁易读。目前主要包括 instanceof 的模式匹配和 switch 表达式的模式匹配。

35.2 instanceof 的模式匹配

在传统的 Java 中,进行类型检查和类型转换需要多行代码,而模式匹配可以将其简化为一行。

public class InstanceOfPatternMatchingExample {public static void main(String[] args) {Object obj = "Hello";if (obj instanceof String str) {// 直接使用 str 变量,无需显式类型转换System.out.println(str.toUpperCase());}}
}

35.3 switch 表达式的模式匹配(Java 17+)

switch 表达式的模式匹配允许在 switch 语句中使用模式来匹配不同的情况。

sealed interface Shape permits Circle, Rectangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}public class SwitchPatternMatchingExample {public static double area(Shape shape) {return switch (shape) {case Circle c -> Math.PI * c.radius() * c.radius();case Rectangle r -> r.width() * r.height();};}public static void main(String[] args) {Shape circle = new Circle(5);System.out.println("Circle area: " + area(circle));}
}

三十六、协变返回类型(Java 5+)

36.1 协变返回类型概述

协变返回类型是 Java 5 引入的特性,它允许子类重写父类的方法时,返回类型可以是父类方法返回类型的子类。这使得方法重写更加灵活。

36.2 协变返回类型的示例

class Animal {Animal create() {return new Animal();}
}class Dog extends Animal {// 重写方法,返回类型为 Dog,是 Animal 的子类@OverrideDog create() {return new Dog();}
}

三十七、菱形运算符(Java 7+)

37.1 菱形运算符概述

菱形运算符(<>)是 Java 7 引入的特性,用于简化泛型类的实例化。在创建泛型类的对象时,可以省略泛型类型参数,编译器会根据上下文自动推断。

37.2 菱形运算符的使用

import java.util.ArrayList;
import java.util.List;public class DiamondOperatorExample {public static void main(String[] args) {// Java 7 之前的写法List<String> list1 = new ArrayList<String>();// 使用菱形运算符List<String> list2 = new ArrayList<>();}
}

三十八、自动装箱和拆箱(Java 5+)

38.1 自动装箱和拆箱概述

自动装箱和拆箱是 Java 5 引入的特性,它允许基本数据类型和对应的包装类之间自动进行转换,提高了代码的简洁性。

38.2 自动装箱和拆箱的示例

public class AutoboxingUnboxingExample {public static void main(String[] args) {// 自动装箱:将基本数据类型转换为包装类Integer num1 = 10; // 自动拆箱:将包装类转换为基本数据类型int num2 = num1; System.out.println("Autoboxed value: " + num1);System.out.println("Unboxed value: " + num2);}
}

三十九、可变参数(Java 5+)

39.1 可变参数概述

可变参数(Varargs)是 Java 5 引入的特性,它允许方法接受可变数量的参数,使用 ... 语法来表示。

39.2 可变参数的使用

public class VarargsExample {public static int sum(int... numbers) {int total = 0;for (int num : numbers) {total += num;}return total;}public static void main(String[] args) {int result1 = sum(1, 2, 3);int result2 = sum(4, 5, 6, 7);System.out.println("Sum 1: " + result1);System.out.println("Sum 2: " + result2);}
}

这些 Java 基础知识涵盖了从早期版本到较新版本的多个重要特性,理解和掌握这些内容有助于更好地进行 Java 编程。

四十、序列化控制

40.1 自定义序列化过程

虽然实现 Serializable 接口能让对象自动序列化,但有时候需要自定义序列化过程。可以通过在类中定义 writeObjectreadObject 方法来实现。

import java.io.*;class CustomSerializable implements Serializable {private int value;public CustomSerializable(int value) {this.value = value;}// 自定义序列化方法private void writeObject(ObjectOutputStream out) throws IOException {// 可以在此添加额外的处理逻辑out.defaultWriteObject();out.writeInt(value * 2); // 对值进行一些处理后再写入}// 自定义反序列化方法private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();this.value = in.readInt() / 2; // 恢复处理后的值}public int getValue() {return value;}
}public class CustomSerializationExample {public static void main(String[] args) {CustomSerializable obj = new CustomSerializable(10);try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("custom.ser"));ObjectInputStream ois = new ObjectInputStream(new FileInputStream("custom.ser"))) {oos.writeObject(obj);CustomSerializable deserializedObj = (CustomSerializable) ois.readObject();System.out.println(deserializedObj.getValue());} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}

40.2 序列化版本号(serialVersionUID

serialVersionUID 是一个序列化版本的标识符。当对象序列化和反序列化时,JVM 会比较 serialVersionUID 的值,如果不一致会抛出 InvalidClassException。手动指定 serialVersionUID 可以避免在类结构发生微小变化时导致反序列化失败。

import java.io.Serializable;class VersionedClass implements Serializable {private static final long serialVersionUID = 123456789L;private String data;public VersionedClass(String data) {this.data = data;}public String getData() {return data;}
}

四十一、反射的更多应用

41.1 动态代理

动态代理是 Java 反射机制的一个重要应用,它允许在运行时创建代理类和对象。Java 提供了两种动态代理方式:基于接口的动态代理(java.lang.reflect.Proxy)和基于类的动态代理(CGLIB)。这里介绍基于接口的动态代理。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 定义接口
interface Subject {void request();
}// 实现接口的真实类
class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}// 实现 InvocationHandler 接口
class ProxyHandler implements InvocationHandler {private Object target;public ProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method call.");Object result = method.invoke(target, args);System.out.println("After method call.");return result;}
}public class DynamicProxyExample {public static void main(String[] args) {RealSubject realSubject = new RealSubject();ProxyHandler handler = new ProxyHandler(realSubject);Subject proxySubject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),new Class<?>[]{Subject.class},handler);proxySubject.request();}
}

41.2 反射获取和修改注解

通过反射可以获取类、方法、字段等元素上的注解信息,并且可以根据需要进行处理。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyAnnotation {String value();
}class AnnotatedClass {@MyAnnotation("Test Annotation")public void annotatedMethod() {// 方法体}
}public class ReflectionAnnotationExample {public static void main(String[] args) throws NoSuchMethodException {Class<?> clazz = AnnotatedClass.class;Method method = clazz.getMethod("annotatedMethod");if (method.isAnnotationPresent(MyAnnotation.class)) {MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);System.out.println("Annotation value: " + annotation.value());}}
}

四十二、Java 中的信号量(Semaphore

42.1 信号量概述

Semaphore 是 Java 并发包(java.util.concurrent)中的一个类,用于控制同时访问某个资源的线程数量。它维护了一组许可证,线程在访问资源前需要获取许可证,访问结束后释放许可证。

42.2 信号量的使用示例

import java.util.concurrent.Semaphore;class Resource {private final Semaphore semaphore = new Semaphore(2); // 允许最多 2 个线程同时访问public void accessResource() {try {semaphore.acquire();System.out.println(Thread.currentThread().getName() + " is accessing the resource.");Thread.sleep(2000); // 模拟资源访问时间System.out.println(Thread.currentThread().getName() + " has finished accessing the resource.");} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {semaphore.release();}}
}public class SemaphoreExample {public static void main(String[] args) {Resource resource = new Resource();for (int i = 0; i < 5; i++) {new Thread(() -> resource.accessResource()).start();}}
}

四十三、Java 中的屏障(CyclicBarrier

43.1 屏障概述

CyclicBarrier 是 Java 并发包中的另一个同步工具,它允许一组线程相互等待,直到所有线程都到达某个屏障点,然后所有线程再继续执行。CyclicBarrier 可以重复使用。

43.2 屏障的使用示例

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;class Worker implements Runnable {private final CyclicBarrier barrier;public Worker(CyclicBarrier barrier) {this.barrier = barrier;}@Overridepublic void run() {try {System.out.println(Thread.currentThread().getName() + " is doing some work.");barrier.await(); // 等待其他线程到达屏障点System.out.println(Thread.currentThread().getName() + " has passed the barrier.");} catch (InterruptedException | BrokenBarrierException e) {Thread.currentThread().interrupt();}}
}public class CyclicBarrierExample {public static void main(String[] args) {int numThreads = 3;CyclicBarrier barrier = new CyclicBarrier(numThreads, () -> System.out.println("All threads have reached the barrier."));for (int i = 0; i < numThreads; i++) {new Thread(new Worker(barrier)).start();}}
}

四十四、Java 中的交换器(Exchanger

44.1 交换器概述

Exchanger 是 Java 并发包中的一个工具类,它允许两个线程在某个同步点交换数据。当两个线程都到达交换点时,它们会交换各自持有的数据。

44.2 交换器的使用示例

import java.util.concurrent.Exchanger;class ExchangerTask implements Runnable {private final Exchanger<String> exchanger;private String data;public ExchangerTask(Exchanger<String> exchanger, String data) {this.exchanger = exchanger;this.data = data;}@Overridepublic void run() {try {System.out.println(Thread.currentThread().getName() + " before exchange: " + data);data = exchanger.exchange(data);System.out.println(Thread.currentThread().getName() + " after exchange: " + data);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}public class ExchangerExample {public static void main(String[] args) {Exchanger<String> exchanger = new Exchanger<>();new Thread(new ExchangerTask(exchanger, "Data from Thread 1")).start();new Thread(new ExchangerTask(exchanger, "Data from Thread 2")).start();}
}

这些 Java 基础知识进一步拓展了 Java 的使用场景,涉及到序列化的深入控制、反射的高级应用以及并发编程中的多种同步工具,有助于你更全面地掌握 Java 编程。

四十五、Java 中的锁机制补充

45.1 读写锁(ReentrantReadWriteLock

概述

ReentrantReadWriteLock 是 Java 并发包中提供的一种读写分离的锁机制。它允许多个线程同时进行读操作,但在写操作时会独占锁,以保证数据的一致性。读写锁适用于读多写少的场景。

示例代码

import java.util.concurrent.locks.ReentrantReadWriteLock;class ReadWriteLockExample {private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();private int data;public int readData() {readLock.lock();try {return data;} finally {readLock.unlock();}}public void writeData(int newData) {writeLock.lock();try {data = newData;} finally {writeLock.unlock();}}
}

45.2 StampedLock

概述

StampedLock 是 Java 8 引入的一种新的锁机制,它支持三种模式:写锁、读锁和乐观读。乐观读模式下不会阻塞写操作,能在一定程度上提高并发性能。

示例代码

import java.util.concurrent.locks.StampedLock;class StampedLockExample {private final StampedLock stampedLock = new StampedLock();private int data;public int optimisticReadData() {long stamp = stampedLock.tryOptimisticRead();int currentData = data;if (!stampedLock.validate(stamp)) {stamp = stampedLock.readLock();try {currentData = data;} finally {stampedLock.unlockRead(stamp);}}return currentData;}public void writeData(int newData) {long stamp = stampedLock.writeLock();try {data = newData;} finally {stampedLock.unlockWrite(stamp);}}
}

四十六、Java 中的并发集合

46.1 ConcurrentHashMap

概述

ConcurrentHashMap 是线程安全的哈希表实现,它在多线程环境下能高效地进行并发操作。与 HashTable 相比,ConcurrentHashMap 采用分段锁或 CAS(Compare - And - Swap)等机制,减少了锁的粒度,提高了并发性能。

示例代码

import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapExample {public static void main(String[] args) {ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();map.put("key1", 1);map.put("key2", 2);Integer value = map.get("key1");System.out.println(value);}
}

46.2 CopyOnWriteArrayList

概述

CopyOnWriteArrayList 是线程安全的 List 实现,它在进行写操作(如 addremove)时会创建一个原数组的副本,在副本上进行修改,修改完成后将原数组引用指向新的副本。这种方式保证了读操作不需要加锁,适用于读多写少的场景。

示例代码

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;public class CopyOnWriteArrayListExample {public static void main(String[] args) {CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();list.add("element1");list.add("element2");Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}}
}

46.3 ConcurrentLinkedQueue

概述

ConcurrentLinkedQueue 是线程安全的无界非阻塞队列,基于链表实现。它采用 CAS 操作来保证并发环境下的线程安全,适合在多线程环境下进行高效的队列操作。

示例代码

import java.util.concurrent.ConcurrentLinkedQueue;public class ConcurrentLinkedQueueExample {public static void main(String[] args) {ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();queue.offer("item1");queue.offer("item2");String item = queue.poll();System.out.println(item);}
}

四十七、Java 中的类加载机制

47.1 类加载器的层次结构

Java 中的类加载器分为以下几种,它们构成了一个层次结构:

  • 启动类加载器(Bootstrap ClassLoader):负责加载 Java 的核心类库,如 java.lang 包下的类,它是用 C++ 实现的,在 Java 代码中无法直接引用。
  • 扩展类加载器(Extension ClassLoader):负责加载 Java 的扩展类库,通常是 jre/lib/ext 目录下的类。
  • 应用类加载器(Application ClassLoader):负责加载用户类路径(classpath)下的类,它是 ClassLoader 类的子类。

47.2 双亲委派模型

概述

双亲委派模型是 Java 类加载器的工作模式。当一个类加载器收到类加载请求时,它首先不会自己去尝试加载这个类,而是把请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都会传送到顶层的启动类加载器。只有当父类加载器反馈自己无法完成该加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

示例代码

public class ClassLoaderExample {public static void main(String[] args) {ClassLoader classLoader = ClassLoaderExample.class.getClassLoader();System.out.println("Current class loader: " + classLoader);System.out.println("Parent class loader: " + classLoader.getParent());System.out.println("Grandparent class loader: " + classLoader.getParent().getParent());}
}

47.3 自定义类加载器

概述

在某些情况下,需要自定义类加载器,例如从网络、数据库等非标准位置加载类。自定义类加载器需要继承 ClassLoader 类,并重写 findClass 方法。

示例代码

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;public class CustomClassLoader extends ClassLoader {private String classPath;public CustomClassLoader(String classPath) {this.classPath = classPath;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {byte[] classData = loadClassData(name);if (classData == null) {throw new ClassNotFoundException();}return defineClass(name, classData, 0, classData.length);}private byte[] loadClassData(String name) {String filePath = classPath + File.separator + name.replace('.', File.separatorChar) + ".class";try (FileInputStream fis = new FileInputStream(filePath);ByteArrayOutputStream bos = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = fis.read(buffer)) != -1) {bos.write(buffer, 0, bytesRead);}return bos.toByteArray();} catch (IOException e) {return null;}}
}

四十八、Java 中的枚举的高级用法

48.1 枚举实现单例模式

概述

使用枚举实现单例模式是一种简洁且安全的方式,它能自动处理序列化和反序列化问题,防止反射攻击。

示例代码

enum SingletonEnum {INSTANCE;public void doSomething() {System.out.println("Doing something...");}
}public class EnumSingletonExample {public static void main(String[] args) {SingletonEnum singleton = SingletonEnum.INSTANCE;singleton.doSomething();}
}

48.2 枚举与策略模式结合

概述

可以将枚举与策略模式结合,每个枚举常量代表一种策略,通过不同的枚举常量调用不同的策略方法。

示例代码

enum PaymentStrategy {CREDIT_CARD {@Overridepublic void pay(double amount) {System.out.println("Paying " + amount + " using credit card.");}},PAYPAL {@Overridepublic void pay(double amount) {System.out.println("Paying " + amount + " using PayPal.");}};public abstract void pay(double amount);
}public class EnumStrategyExample {public static void main(String[] args) {PaymentStrategy strategy = PaymentStrategy.CREDIT_CARD;strategy.pay(100.0);}
}

这些 Java 基础知识涵盖了锁机制、并发集合、类加载机制以及枚举的高级用法等方面,进一步丰富了 Java 编程的知识体系。

四十九、Java 中的弱引用、软引用和虚引用

49.1 引用类型概述

在 Java 中,除了强引用,还有弱引用(WeakReference)、软引用(SoftReference)和虚引用(PhantomReference),它们的强度依次减弱,主要用于更灵活地管理对象的生命周期,帮助垃圾回收器进行内存管理。

49.2 弱引用(WeakReference

概述

弱引用所引用的对象在垃圾回收时,无论当前内存是否充足,都会被回收。常用于实现一些缓存机制,避免内存泄漏。

示例代码

import java.lang.ref.WeakReference;public class WeakReferenceExample {public static void main(String[] args) {Object obj = new Object();WeakReference<Object> weakRef = new WeakReference<>(obj);obj = null; // 去除强引用System.gc(); // 手动触发垃圾回收Object retrievedObj = weakRef.get();if (retrievedObj == null) {System.out.println("Object has been garbage - collected.");} else {System.out.println("Object is still alive.");}}
}

49.3 软引用(SoftReference

概述

软引用所引用的对象在内存充足时不会被回收,但当内存不足时,会被垃圾回收器回收。常用于实现内存敏感的缓存。

示例代码

import java.lang.ref.SoftReference;public class SoftReferenceExample {public static void main(String[] args) {Object obj = new Object();SoftReference<Object> softRef = new SoftReference<>(obj);obj = null; // 去除强引用try {// 模拟内存不足,创建大量对象byte[] bigArray = new byte[1024 * 1024 * 10];} catch (OutOfMemoryError e) {System.out.println("Out of memory error occurred.");}Object retrievedObj = softRef.get();if (retrievedObj == null) {System.out.println("Object has been garbage - collected due to memory shortage.");} else {System.out.println("Object is still alive.");}}
}

49.4 虚引用(PhantomReference

概述

虚引用是最弱的一种引用类型,它的主要作用是在对象被垃圾回收时收到一个系统通知。虚引用必须和引用队列(ReferenceQueue)联合使用。

示例代码

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;public class PhantomReferenceExample {public static void main(String[] args) {Object obj = new Object();ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();PhantomReference<Object> phantomRef = new PhantomReference<>(obj, referenceQueue);obj = null; // 去除强引用System.gc(); // 手动触发垃圾回收if (referenceQueue.poll() != null) {System.out.println("Object has been garbage - collected and detected by phantom reference.");} else {System.out.println("Object may still be alive.");}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/882368.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

容器附加存储CAS之OpenEBS快速入门

作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任。 目录一.CAS之OpenEBS存储机制概述1.什么是CAS2.什么是OpenEBS3.OpenEBS数据引擎4.NDM(Node Disk Manager)5.部署OpenEBS的基本流程二.部署OpenEBS 一.CAS之OpenEBS存储机制概述 1.什么是CAS Kubernetes的卷…

【CodeForces训练记录】Codeforces Round 1004 (Div. 2)

训练情况赛后反思 这场太神奇了,都在和出题人对脑电波,全是智慧题 A题 我们考虑进位的情况,例如 9999 之类的,我们发现进位对答案的影响只有 \(x - 9k + 1 = y\),判断 \(k\) 是否存在非负整数解即可点击查看代码 #include <bits/stdc++.h> // #define int long long…

短信验证码爆破

漏洞原理 短信验证码验证时间和次数无限制,存在爆破可能 短信验证码有效期:5~10min,验证码位数4位或6位,纯数字 破解方式:使用枚举逐个尝试 使用BP爆破短信验证码可以先用已有手机号确认验证码位数2.发送验证码后将验证码输入,然后登陆抓包后续和爆破操作一致如果字典太大…

【洛谷P1955】程序自动分析[NOI2015]

今天开始学习并查集 什么是并查集呢?顾名思义,就是动态维护一个方便进行合并和查找的集合 我们采用的是树状结构 也就是说,对于一开始的每个元素 它的爸爸是它自己 然后在输入两个元素的从属关系的时候,通过路径压缩,把它的爸爸直接连到根节点 因为我们只关心这个元素在这…

chorme 系统代理设置

https 需要证书 1.使用BurpSuite导出CA证书,文件导出到本地2. 谷歌浏览器添加证书 谷歌浏览器->设置->搜索"证书"->安全->管理证书->管理从windows导入的证书->受信任的根证书颁发机构->导入第一步的证书3.设置系统代理 windows系统->设置-…

picachu 越权漏洞

1. 水平越权 1.查看提示信息,提供了3个普通用户2. 登陆其中一个账户,并查看个人信息3.根据url 可以看出有用户名信息,尝试在URL中更改其他账户名,发现查看到其他用户的信息4.再次点击查看个人信息按钮,信息更改为已登陆的用户的信息5. 查看源代码发现第27行username 的值是…

windows使用Makefile时自动给可执行文件加上.exe后缀

APP := main在使用makefile的时候,一般通过变量设置自己想要编译出来的可执行文件的名字在windows平台编译出来的可执行文件是需要.exe后缀的识别当前操作系统 通过识别当前的操作系统是什么,从而确定是否添加这个后缀在windows系统中,有这个环境变量说明自己的系统是windows而…

pikachu 验证码绕过 onclient

前端生成的验证码,无论验证码是否正确,都不影响发送到服务器结果(刷新验证码不会通过BP,没有对应的请求出现) 前端验证码逻辑:输入账号密码验证码,如果验证码正确,数据将发送给服务器;如果验证码不正确,数据不会发送给服务器 1.查看页面源代码,发现是前端生成验证码…

图片验证码绕过(验证码不失效) - 使用验证码识别插件

使用BP抓包,抓到的包没有验证码请求添加过滤图片,出现图片验证码请求包添加captcha-killer-modified 插件,识别图片验证码验证码识别服务按照下面链接操作 https://www.cnblogs.com/mr-ryan/p/17812482.html 文档中的ocr_api_server 使用这个链接:https://gitee.com/yijing…

弱口令暴力破解

使用vulhub/tomcat/tomcat8 靶场点击Manager App按钮,提示登陆,输入用户名密码通过BP抓取提交用户名密码的请求报文,获取Authorization信息将Authorization 发送到解码器解码 ,使用Base64 解码成功(一般Base64 编码最后会带= 或者 ==), 解码后知道了发送的密码规则添加Aut…

攻防世界-RE-CatFly

我们将文件拖入虚拟机中运行看到这样的效果 其中上方的数字是不停变化的,下面的次数也在不断的增长。我们猜测这两者是有关联的。 接下来我们进行反编译程序的分析。最上面的字符输出肯定是与printf函数有关,所以我们检索printf在main函数中的调用time(&timer);v13 = 1;v…

Maui 内嵌网页直接调用本机原生功能 Demo

使用 MAUI 制作 H5 套壳程序有以下几个好处:跨平台支持:MAUI (Multi-platform App UI) 允许开发者在多个平台(如 iOS、Android、Windows 和 macOS)上运行应用程序。统一封装的MauiPlus库可以统一调用本机功能,确保在不同平台上有一致的用户体验。访问本地功能:MauiPlus库…