单例模式
单例模式确保一个类只有一个实例,并提供一个全局访问点。这在需要共享资源或控制唯一资源访问时非常有用。
饿汉式单例
饿汉式单例在类加载时就创建了实例,并在需要时返回该实例。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
// 私有构造函数
}
public static Singleton getInstance() {
return instance;
}
}
懒汉式单例
懒汉式单例在需要时才创建实例,并在后续调用中返回该实例。
public class Singleton {
private static Singleton instance;
private Singleton() {
// 私有构造函数
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
工厂模式
工厂模式提供了一种创建对象的方式,封装了对象的实例化过程,使得客户端与具体类的实例化解耦。
简单工厂模式
简单工厂模式通过一个工厂类来创建对象。
public interface Product {
void operation();
}
public class ConcreteProduct implements Product {
public void operation() {
// 具体产品的操作
}
}
public class SimpleFactory {
public static Product createProduct(String type) {
if (type.equals("A")) {
return new ConcreteProductA();
} else if (type.equals("B")) {
return new ConcreteProductB();
}
return null;
}
}
工厂方法模式
工厂方法模式定义了一个创建对象的接口,由子类决定实例化哪个类。
public interface Product {
void operation();
}
public class ConcreteProductA implements Product {
public void operation() {
// 具体产品A的操作
}
}
public class ConcreteProductB implements Product {
public void operation() {
// 具体产品B的操作
}
}
public interface Factory {
Product createProduct();
}
public class ConcreteFactoryA implements Factory {
public Product createProduct() {
return new ConcreteProductA();
}
}
public class ConcreteFactoryB implements Factory {
public Product createProduct() {
return new ConcreteProductB();
}
}
抽象工厂模式
抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
public interface ProductA {
void operation();
}
public interface ProductB {
void operation();
}
public class ConcreteProductA1 implements ProductA {
public void operation() {
// 具体产品A1的操作
}
}
public class ConcreteProductA2 implements ProductA {
public void operation() {
// 具体产品A2的操作
}
}
public class ConcreteProductB1 implements ProductB {
public void operation() {
// 具体产品B1的操作
}
}
public class ConcreteProductB2 implements ProductB {
public void operation() {
// 具体产品B2的操作
}
}
public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
public class ConcreteFactory1 implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA1();
}
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
public class ConcreteFactory2 implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA2();
}
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
代理模式
代理模式提供了一种代理对象控制对其他对象的访问的方式。
静态代理模式
静态代理模式通过创建一个代理类来控制对真实对象的访问。
public interface Subject {
void request();
}
public class RealSubject implements Subject {
public void request() {
// 真实对象的操作
}
}
public class Proxy implements Subject {
private RealSubject realSubject;
public Proxy() {
this.realSubject = new RealSubject();
}
public void request() {
// 在调用真实对象之前或之后执行额外的操作
realSubject.request();
// 在调用真实对象之前或之后执行额外的操作
}
}
动态代理模式
动态代理模式在运行时创建代理对象,无需事先定义代理类。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public interface Subject {
void request();
}
public class RealSubject implements Subject {
public void request() {
// 真实对象的操作
}
}
public class DynamicProxy implements InvocationHandler {
private Object realSubject;
public DynamicProxy(Object realSubject) {
this.realSubject = realSubject;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在调用真实对象之前或之后执行额外的操作
Object result = method.invoke(realSubject, args);
// 在调用真实对象之前或之后执行额外的操作
return result;
}
}
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Subject proxySubject = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new DynamicProxy(realSubject)
);
proxySubject.request();
}
}
装饰者模式
装饰者模式允许向现有对象添加新功能,同时又不改变其结构。
public interface Component {
void operation();
}
public class ConcreteComponent implements Component {
public void operation() {
// 原始对象的操作
}
}
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void operation() {
super.operation();
// 添加额外功能A
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
public void operation() {
super.operation();
// 添加额外功能B
}
}
观察者模式
观察者模式定义了对象之间的一对多依赖关系,使得当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
import java.util.ArrayList;
import java.util.List;
public interface Observer {
void update();
}
public class ConcreteObserver implements Observer {
public void update() {
// 观察者的更新操作
}
}
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
责任链模式
责任链模式将请求的发送者和接收者解耦,使多个对象都有机会处理请求。
public abstract class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handleRequest(Request request);
}
public class ConcreteHandlerA extends Handler {
public void handleRequest(Request request) {
if (request.getCondition()) {
// 处理请求A的逻辑
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
public class ConcreteHandlerB extends Handler {
public void handleRequest(Request request)
枚举(Enumeration)
枚举是一种特殊的数据类型,用于定义一组有限的常量。枚举类型提供了一种更优雅和类型安全的方式来表示一组相关的常量,并且可以在代码中进行优雅的使用。
枚举的定义使用关键字 enum
,并且枚举常量通常以大写字母命名。以下是一个简单的枚举的示例:
enum Day {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
枚举常量可以像普通的变量一样被使用,并且可以使用 switch
语句进行处理。枚举还可以有字段、方法和构造函数。枚举类型还可以实现接口,从而使枚举成员能够具有行为。
注解(Annotation)
注解是一种元数据,可以在代码中添加注解来提供额外的信息。注解可以应用于类、方法、字段和其他程序元素,以提供关于该元素的信息。
注解的定义使用关键字 @interface
,并且可以定义自己的元素。以下是一个简单的注解的示例:
@interface MyAnnotation {
String value();
int count() default 0;
}
在代码中,注解可以用于给元素添加额外的信息。例如,可以将注解应用于方法、类或字段上,以指示特定的行为或配置要求。注解还可以通过反射机制在运行时进行处理。
Java还提供了一些内置的注解,例如 @Override
,用于标识方法重写父类的方法;@Deprecated
,用于标识已过时的方法或类;@SuppressWarnings
,用于抑制编译器警告等。
常见的注解
@Override
:用于标识方法重写了父类的方法。
@Override
public void methodName() {
// 方法实现
}
@Deprecated
:用于标识方法、类或字段已被弃用,不推荐使用。
@Deprecated
public void oldMethod() {
// 方法实现
}
@SuppressWarnings
:用于抑制编译器产生的警告。
@SuppressWarnings("unchecked")
public void someMethod() {
// 忽略类型转换警告
List<String> list = (List<String>) someObject;
}
@FunctionalInterface
:用于标识函数式接口。
@FunctionalInterface
public interface MyInterface {
void someMethod();
}
@RunWith
:用于指定运行测试用例的测试运行器。
@RunWith(MyCustomRunner.class)
public class MyTestClass {
// 测试方法
}
@Test
:用于标识测试方法。
@Test
public void testMethod() {
// 测试逻辑
}
@Before
:用于在每个测试方法执行之前执行的方法。
@Before
public void setUp() {
// 初始化操作
}
@After
:用于在每个测试方法执行之后执行的方法。
@After
public void tearDown() {
// 清理操作
}
@Autowired
:用于自动注入依赖。
@Autowired
private MyDependency dependency;
@RequestMapping
:用于映射请求路径到处理方法。
@RequestMapping("/path")
public void handleRequest() {
// 处理请求逻辑
}
反射的使用
反射(Reflection)是Java提供的一种强大的机制,可以在运行时动态地获取类的信息、调用方法和访问字段。下面是一些反射的示例:
获取类的信息:
Class<?> clazz = MyClass.class;
String className = clazz.getName(); // 获取类名
Package pkg = clazz.getPackage(); // 获取包信息
Constructor<?>[] constructors = clazz.getConstructors(); // 获取构造函数列表
Method[] methods = clazz.getMethods(); // 获取方法列表
Field[] fields = clazz.getFields(); // 获取字段列表
创建对象实例:
Class<?> clazz = MyClass.class;
Constructor<?> constructor = clazz.getConstructor(); // 获取无参构造函数
Object instance = constructor.newInstance(); // 创建对象实例
调用方法:
Class<?> clazz = MyClass.class;
Object instance = clazz.newInstance();
Method method = clazz.getMethod("methodName", String.class); // 获取方法对象
method.invoke(instance, "argument"); // 调用方法
访问字段:
Class<?> clazz = MyClass.class;
Object instance = clazz.newInstance();
Field field = clazz.getField("fieldName"); // 获取字段对象
field.set(instance, value); // 设置字段值
Object value = field.get(instance); // 获取字段值
动态代理:
interface MyInterface {
void myMethod();
}
class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 处理方法调用
return null;
}
}
public class Main {
public static void main(String[] args) {
MyInterface proxyInstance = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class<?>[]{MyInterface.class},
new MyInvocationHandler()
);
proxyInstance.myMethod(); // 调用代理方法
}
}
通过反射,可以在运行时动态地获取类的信息,并根据需要创建实例、调用方法和访问字段。
import java.lang.annotation.Annotation;
@MyAnnotation(name = "Example", value = "Sample")
public class MyClass {
// 类定义
public void myMethod() {
// 方法实现
}
public static void main(String[] args) {
Class<?> clazz = MyClass.class;
// 获取类上的所有注解
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof MyAnnotation) {
MyAnnotation myAnnotation = (MyAnnotation) annotation;
// 获取注解的属性值
String name = myAnnotation.name();
String value = myAnnotation.value();
System.out.println("Name: " + name);
System.out.println("Value: " + value);
}
}
}
}
元注解(Meta-annotation)
是指用于注解其他注解的注解。Java提供了一些元注解,用于对自定义注解进行注解和定义。
常见元注解
@Target
:指定注解可以应用的目标元素类型,如TYPE
(类、接口、枚举)、METHOD
(方法)、FIELD
(字段)等。
@Target(ElementType.TYPE)
public @interface MyAnnotation {
// 注解定义
}
@Retention
:指定注解的保留策略,即注解在何时可见。有三个保留策略:SOURCE
(只在源代码中可见)、CLASS
(在编译时可见,默认值)、RUNTIME
(在运行时可见)。
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
// 注解定义
}
@Documented
:指定注解是否包含在Java文档中。
@Documented
public @interface MyAnnotation {
// 注解定义
}
@Inherited
:指定注解是否可以被继承。如果一个注解被@Inherited
注解,则表示子类也会继承该注解。
@Inherited
public @interface MyAnnotation {
// 注解定义
}
@Repeatable
:指定注解是否可重复应用于同一目标元素。该元注解用于Java 8及以上版本。
@Repeatable(MyAnnotations.class)
public @interface MyAnnotation {
// 注解定义
}
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
MyAnnotation[] value();
}
这些元注解提供了对自定义注解进行更精细化控制的能力,您可以根据需要选择使用它们。
Java 8新特性
-
Lambda表达式:Lambda表达式是一种匿名函数,可以用更简洁的语法编写函数式接口的实现。它提供了一种更简便的方法来处理集合、并行计算等任务。
import java.util.ArrayList; import java.util.List; public class LambdaExample { public static void main(String[] args) { List<String> names = new ArrayList<>(); names.add("Alice"); names.add("Bob"); names.add("Charlie"); names.add("Dave"); // 使用Lambda表达式遍历集合并打印每个元素 names.forEach(name -> System.out.println(name)); // 使用Lambda表达式过滤集合中的元素 names.removeIf(name -> name.startsWith("B")); // 使用Lambda表达式对集合中的元素进行转换 names.replaceAll(name -> name.toUpperCase()); // 使用Lambda表达式排序集合 names.sort((name1, name2) -> name1.compareTo(name2)); // 使用Lambda表达式进行自定义操作 names.forEach(name -> { System.out.println("Length of " + name + ": " + name.length()); }); } }
-
方法引用:方法引用允许直接通过方法的名称引用已经存在的方法。它提供了一种更简洁的方式来编写Lambda表达式。
-
默认方法(Default Methods):接口可以包含具有默认实现的方法。这样,在向接口中添加新方法时,不会破坏已有的实现类。
-
Stream API:Stream API提供了一种功能强大且易于使用的处理集合数据的方式。它可以进行过滤、映射、排序、聚合等操作,并支持并行处理。
-
新的日期和时间API(Date and Time API):Java 8引入了
java.time
包,提供了全新的日期和时间API,更好地处理日期、时间和时间间隔。 -
Optional类:Optional类是一个容器类,它可以用来表示一个值存在或不存在。它提供了一种更好的方式来处理可能为null的情况,避免了空指针异常。
-
函数式接口(Functional Interface):函数式接口是只包含一个抽象方法的接口。Java 8引入了
@FunctionalInterface
注解来标识函数式接口,并提供了一些内置的函数式接口,如Predicate
、Function
、Consumer
等。可以使用
@FunctionalInterface
注解来确保接口符合函数式接口的要求。以下是一个自定义函数式接口的示例:@FunctionalInterface public interface MyFunction<T, R> { R apply(T t); }
上面的代码定义了一个名为
MyFunction
的函数式接口,它接受一个类型为T
的参数,并返回一个类型为R
的结果。使用Lambda表达式或方法引用来实现该接口,如下所示:public class CustomFunctionalInterfaceExample { public static void main(String[] args) { MyFunction<String, Integer> strLength = str -> str.length(); System.out.println(strLength.apply("Hello")); // 输出: 5 MyFunction<Integer, String> intToString = num -> String.valueOf(num); System.out.println(intToString.apply(10)); // 输出: "10" } }
在上面的示例中,我们使用Lambda表达式分别实现了
MyFunction
接口的两个方法,并通过调用apply
方法来使用这些实现。 -
CompletableFuture类:CompletableFuture类是一种用于异步编程的工具,它支持以更简洁的方式处理异步操作和组合多个异步任务。
-
新的重复注解和类型注解:Java 8允许在同一元素上多次使用相同的注解,并引入了类型注解,使得注解可以用于更精确地类型检查。
Stream API
Stream API是Java 8引入的一种用于处理集合数据的功能强大的工具。它提供了一种流式处理的方式,可以对集合进行过滤、映射、排序、聚合等操作。以下是一些使用Stream API的示例:
- 过滤(Filter):
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamFilterExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evenNumbers = numbers.stream()
.filter(num -> num % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出: [2, 4, 6, 8, 10]
}
}
映射(Map):
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamMapExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> nameLengths = names.stream()
.map(name -> name.length())
.collect(Collectors.toList());
System.out.println(nameLengths); // 输出: [5, 3, 7]
}
}
排序(Sort):
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamSortExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> sortedNames = names.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(sortedNames); // 输出: [Alice, Bob, Charlie]
}
}
聚合(Reduce):
import java.util.Arrays;
import java.util.List;
public class StreamReduceExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
System.out.println(sum); // 输出: 15
}
}
Stream API还提供了许多其他的操作,如distinct、limit、skip、findFirst、max、min等。通过Stream API,我们可以以一种更简洁和功能强大的方式处理集合数据,提高代码的可读性和可维护性。