2024-08-26

栈(Stack)是一种线性数据结构,它遵循后进先出(LIFO)原则。在计算机科学中,栈常用于存储临时数据,如函数调用的局部变量、保存中间结果的计算过程等。

以下是使用Java实现栈的基本操作:




public class Stack<T> {
    private int size;
    private Node<T> top;
 
    public Stack() {
        size = 0;
        top = null;
    }
 
    // 入栈操作
    public void push(T data) {
        Node<T> newNode = new Node<>(data);
        if (top != null) {
            newNode.next = top;
        }
        top = newNode;
        size++;
    }
 
    // 出栈操作
    public T pop() {
        if (isEmpty()) {
            return null;
        }
        T data = top.data;
        top = top.next;
        size--;
        return data;
    }
 
    // 查看栈顶元素
    public T peek() {
        if (isEmpty()) {
            return null;
        }
        return top.data;
    }
 
    // 判断栈是否为空
    public boolean isEmpty() {
        return size == 0;
    }
 
    // 获取栈的大小
    public int size() {
        return size;
    }
 
    private static class Node<T> {
        T data;
        Node<T> next;
 
        public Node(T data) {
            this.data = data;
            this.next = null;
        }
    }
}

使用示例:




public class StackExample {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
 
        // 入栈
        stack.push(1);
        stack.push(2);
        stack.push(3);
 
        // 查看栈顶元素
        System.out.println("栈顶元素: " + stack.peek()); // 输出: 栈顶元素: 3
 
        // 出栈
        System.out.println("出栈元素: " + stack.pop()); // 输出: 出栈元素: 3
 
        // 再次查看栈顶元素
        System.out.println("栈顶元素: " + stack.peek()); // 输出: 栈顶元素: 2
 
        // 获取栈的大小
        System.out.println("栈的大小: " + stack.size()); // 输出: 栈的大小: 2
 
        // 判断栈是否为空
        System.out.println("栈是否为空: " + stack.isEmpty()); // 输出: 栈是否为空: false
    }
}

以上代码实现了一个简单的栈数据结构,并展示了如何使用它进行入栈、出栈、查看栈顶元素等操作。这个实现有利于进一步理解栈的概念和操作。

2024-08-26

在Spring Boot中集成WebSocket可以通过Spring WebSocket支持来完成。以下是一个简单的例子:

  1. 添加依赖到你的pom.xml



<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
  1. 配置WebSocket,创建一个配置类:



@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }
 
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").withSockJS();
    }
}
  1. 创建一个控制器来处理WebSocket请求:



@Controller
public class WebSocketController {
 
    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    public Greeting greeting(HelloMessage message) {
        return new Greeting("Hello, " + message.getName() + "!");
    }
}
 
class Greeting {
    private String content;
 
    // getters and setters
}
 
class HelloMessage {
    private String name;
 
    // getters and setters
}
  1. 在前端使用WebSocket:



var socket = new SockJS('/ws');
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
    console.log('Connected: ' + frame);
    stompClient.subscribe('/topic/greetings', function(greeting){
        console.log(JSON.parse(greeting.body).content);
    });
});
 
stompClient.send("/app/hello", {}, JSON.stringify({ 'name': 'John Doe' }));

以上代码展示了如何在Spring Boot应用中设置WebSocket服务器,并定义了一个简单的消息映射。客户端使用SockJS和Stomp.js与服务器进行通信。

2024-08-26

堆是Java中一种特殊的数据结构,它可以被看作是一棵完全二叉树。在Java中,堆可以被用于实现优先队列等数据结构。堆有两种类型:最大堆和最小堆。在最大堆中,根节点的值是所有堆节点中最大的;在最小堆中,根节点的值是所有堆节点中最小的。

Java中堆的操作主要通过PriorityQueue类实现,它是最常用的堆实现方式。以下是一些基本操作的示例代码:




import java.util.PriorityQueue;
 
public class HeapExample {
    public static void main(String[] args) {
        // 创建最小堆
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
 
        // 添加元素
        minHeap.offer(10);
        minHeap.offer(5);
        minHeap.offer(15);
 
        // 查看堆顶元素
        System.out.println(minHeap.peek()); // 输出:5
 
        // 移除并返回堆顶元素
        System.out.println(minHeap.poll()); // 输出:5
 
        // 判断堆是否为空
        System.out.println(minHeap.isEmpty()); // 输出:false
 
        // 返回堆的大小
        System.out.println(minHeap.size()); // 输出:2
    }
}

在这个例子中,我们创建了一个最小堆,并展示了如何添加元素、查看堆顶元素、移除堆顶元素、判断堆是否为空以及获取堆的大小。

除了PriorityQueue,Java标准库中还提供了ArrayDeque类,它可以用来模拟堆操作,但PriorityQueue更适合大多数堆操作。

2024-08-26

Java反射是一种强大的工具,它允许在运行时检查类、创建对象、调用方法和访问字段。以下是如何使用Java反射的基本步骤:

  1. 获取Class对象。
  2. 使用Class对象获取构造函数、方法和字段。
  3. 使用反射API来创建对象、调用方法和字段。

示例代码:




import java.lang.reflect.Method;
 
public class ReflectionExample {
    public static void main(String[] args) {
        try {
            // 1. 获取Class对象
            Class<?> clazz = Class.forName("com.example.MyClass");
 
            // 2. 使用Class对象获取方法
            Method method = clazz.getMethod("myMethod", String.class);
 
            // 3. 创建实例
            Object myObject = clazz.newInstance();
 
            // 4. 调用方法
            method.invoke(myObject, "参数");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
class MyClass {
    public void myMethod(String arg) {
        System.out.println("方法被调用,参数是:" + arg);
    }
}

在这个例子中,我们首先通过Class.forName()获取MyClassClass对象。然后,我们通过getMethod()获取myMethod方法的Method对象。接着,我们使用newInstance()创建MyClass的实例。最后,我们通过invoke()方法调用myMethod方法。

注意:在实际应用中,应该处理异常,并且确保使用反射时的安全性和性能。

2024-08-26

设计模式是软件开发中的重要概念,对于Java开发者来说,学习并理解23种设计模式是很有帮助的。下面我将为你提供每种设计模式的简短描述和示例代码。

  1. 抽象工厂(Abstract Factory)

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。




public interface AnimalFactory {
    Animal createAnimal();
}
 
public class DogFactory implements AnimalFactory {
    public Animal createAnimal() {
        return new Dog();
    }
}
  1. 建造者模式(Builder)

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。




public class Car {
    private String engine;
    private String wheel;
    // ...
}
 
public class CarBuilder {
    public Car buildCar(String engine, String wheel) {
        Car car = new Car();
        car.setEngine(engine);
        car.setWheel(wheel);
        return car;
    }
}
  1. 工厂方法(Factory Method)

定义一个用于创建对象的接口,让子类决定实例化哪个类。




public interface VehicleFactory {
    Vehicle createVehicle();
}
 
public class CarFactory implements VehicleFactory {
    public Vehicle createVehicle() {
        return new Car();
    }
}
  1. 原型(Prototype)

用原型实例指定创建对象的种类,并且通过复制这个原型来创建新的对象。




public class Car implements Cloneable {
    // ...
    public Car clone() {
        try {
            return (Car) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}
  1. 单例(Singleton)

确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一的实例。




public class DatabaseConnection {
    private static DatabaseConnection instance = null;
    private DatabaseConnection() {}
    public static synchronized DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
}
  1. 适配器(Adapter)

将一个类的接口转换成客户希望的另一个接口。




public class AnimalAdapter implements Dog {
    private Animal animal;
    public AnimalAdapter(Animal animal) {
        this.animal = animal;
    }
    public void bark() {
        animal.makeNoise();
    }
}
  1. 桥接(Bridge)

将抽象部分与它的实现部分分离,使它们都可以独立地变化。




public interface Engine {
    void start();
}
 
public class V8Engine implements Engine {
    public void start() {
        System.out.println("V8 Engine starting.");
    }
}
  1. 组合(Composite)

将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对

2024-08-26

在Java中,Map接口是一个存储键值对的对象,每个键都是唯一的。以下是Map接口的一些常用方法:

  1. V put(K key, V value): 将指定的值与该映射中的指定键关联。如果之前在映射中使用了该键,则返回与该键关联的旧值。



Map<String, Integer> map = new HashMap<>();
map.put("apple", 10);
  1. V get(Object key): 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null



Integer value = map.get("apple"); // 返回 10
  1. V remove(Object key): 如果存在一个键的映射关系,则移除该关系并返回该值。



Integer removedValue = map.remove("apple"); // 返回 10,apple键值对被移除
  1. boolean containsKey(Object key): 如果此映射包含指定键的映射关系,则返回 true



boolean hasKey = map.containsKey("apple"); // 如果map中有apple键,返回true
  1. boolean isEmpty(): 如果此映射未包含键-值映射关系,则返回 true



boolean isEmpty = map.isEmpty(); // 如果map为空,返回true
  1. int size(): 返回此映射中的键-值映射关系数。



int size = map.size(); // 返回map中键值对的数量
  1. Set<K> keySet(): 返回此映射中包含的键的 Set 视图。



Set<String> keys = map.keySet(); // 返回map中所有键的Set集合
  1. Collection<V> values(): 返回此映射中包含的值的 Collection 视图。



Collection<Integer> values = map.values(); // 返回map中所有值的Collection集合
  1. Set<Map.Entry<K, V>> entrySet(): 返回此映射中包含的映射关系的 Set 视图。



Set<Map.Entry<String, Integer>> entries = map.entrySet(); // 返回map中所有键值对的Set集合
  1. void putAll(Map<? extends K, ? extends V> m): 将指定映射中的所有映射关系复制到此映射中。



Map<String, Integer> anotherMap = new HashMap<>();
anotherMap.putAll(map); // 将map中的所有键值对复制到anotherMap
  1. void clear(): 移除此映射中的所有映射关系。



map.clear(); // 移除map中的所有键值对

这些方法涵盖了Map接口的基本操作,在实际应用中可以根据需要使用。

2024-08-26

在Java中,可以使用java.io.File类的getName()方法和lastIndexOf()方法来解析文件的后缀名(扩展名)。以下是几种解析文件后缀名的方法:

  1. 使用java.nio.file.Pathsjava.nio.file.PathgetFileName()getExtension()方法。



import java.nio.file.Paths;
import java.nio.file.Path;
 
Path path = Paths.get("example.txt");
String extension = path.getFileName().toString().split("\\.")[1];
System.out.println(extension);
  1. 使用java.io.FilegetName()方法和lastIndexOf()方法。



import java.io.File;
 
File file = new File("example.txt");
String extension = file.getName().substring(file.getName().lastIndexOf('.') + 1);
System.out.println(extension);
  1. 使用Apache Commons IO库的FilenameUtils.getExtension()方法。



import org.apache.commons.io.FilenameUtils;
 
String extension = FilenameUtils.getExtension("example.txt");
System.out.println(extension);

以上三种方法均可以获取文件的后缀名,选择合适的方法根据实际情况使用即可。

2024-08-26

反射是Java的一个强大特性,它允许程序在运行时进行自我检查并操作它自己的结构。这里是一个简单的Java反射示例:




import java.lang.reflect.Method;
 
public class ReflectionExample {
    public static void main(String[] args) {
        try {
            // 使用Class.forName()加载类
            Class<?> clazz = Class.forName("com.example.MyClass");
 
            // 使用clazz.newInstance()创建类的实例
            Object myClassInstance = clazz.newInstance();
 
            // 获取特定的方法
            Method myMethod = clazz.getMethod("myMethodName", int.class, String.class);
 
            // 调用方法
            myMethod.invoke(myClassInstance, 42, "Hello World");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
// 确保这个类存在并且可以被加载
class MyClass {
    public void myMethodName(int number, String text) {
        System.out.println("Method invoked with number: " + number + " and text: " + text);
    }
}

这个例子展示了如何使用反射API加载一个类,创建该类的实例,获取特定的方法,并调用该方法。这是反射的基本使用方式,但是它可以做更多的事情,比如访问私有字段、调用私有方法等。

2024-08-26

List、Map 和 Set 是 Java 集合框架中的三个主要接口。它们之间的主要区别在于它们的存储特性和用途:

  1. List:

    • 存储特性:允许重复、有序(插入顺序)。
    • 基本实现类:ArrayList、LinkedList、Vector(线程安全)。
    • 用途:动态数组,适合频繁的插入和删除操作。
  2. Map:

    • 存储特性:键值对、无序。键唯一、值可重复。
    • 基本实现类:HashMap、TreeMap、LinkedHashMap、Hashtable(线程安全)。
    • 用途:键值对映射,适合快速查找和键值对访问。
  3. Set:

    • 存储特性:元素唯一、无序。
    • 基本实现类:HashSet、LinkedHashSet、TreeSet。
    • 用途:集合,适合快速查找和集合操作。

示例代码:




import java.util.*;
 
public class CollectionFeatures {
    public static void main(String[] args) {
        // List
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add(1, "c"); // 在指定位置插入
        System.out.println(list); // 输出 [a, c, b]
 
        // Map
        Map<String, Integer> map = new HashMap<>();
        map.put("key1", 1);
        map.put("key2", 2);
        System.out.println(map.get("key1")); // 输出 1
 
        // Set
        Set<String> set = new HashSet<>();
        set.add("a");
        set.add("b");
        set.add("a"); // 重复元素不会添加
        System.out.println(set); // 输出 [a, b]
    }
}
2024-08-26



public class BinaryAddition {
 
    // 将字符串表示的二进制数转换为整数
    public static int binaryStringToInt(String binaryStr) {
        return Integer.parseInt(binaryStr, 2);
    }
 
    // 将整数转换为二进制字符串
    public static String intToBinaryString(int num) {
        return Integer.toBinaryString(num);
    }
 
    // 计算两个二进制字符串表示的数值的和
    public static String addBinary(String a, String b) {
        int num1 = binaryStringToInt(a);
        int num2 = binaryStringToInt(b);
        int sum = num1 + num2;
        return intToBinaryString(sum);
    }
 
    public static void main(String[] args) {
        String binary1 = "1010";
        String binary2 = "1001";
        String result = addBinary(binary1, binary2);
        System.out.println("和的二进制表示: " + result);
    }
}

这段代码首先定义了将字符串表示的二进制数转换为整数以及将整数转换为二进制字符串的方法。然后定义了一个计算两个二进制字符串表示的数值的和的方法,它使用了前面定义的转换方法。最后在main方法中提供了示例输入并打印结果。