Advanced Java Review Notes (Please Don't Fail the Final!)

发表于 2021-12-16 01:31 2912 字 15 min read

cos avatar

cos

FE / ACG / 手工 / 深色模式强迫症 / INFP / 兴趣广泛养两只猫的老宅女 / remote

文章系统梳理了Java中常用的设计模式、核心编程概念及实际应用,重点涵盖了工厂模式、装饰器模式、观察者模式、代理模式和策略模式的原理与应用场景,介绍了对象实例化方式(new、反射、克隆、序列化等),深入讲解了Java事件监听机制、反射机制、AOP(面向切面编程)和Socket网络编程,同时复习了多线程编程中的同步机制与线程状态,对比了线程与进程的区别,并介绍了数据库连接池和线程池的使用价值。此外,还涉及Comparable与Comparator比较接口的实现方式以及JDBC数据库连接的基本实践。

This article has been machine-translated from Chinese. The translation may contain inaccuracies or awkward phrasing. If in doubt, please refer to the original Chinese version.

Professor said: Just review the basic design patterns, serialization, event listeners, object instantiation methods, the role of reflection, aspect-oriented programming, sockets, synchronization, connection pools, thread pools, comparator interfaces. Also review proxy pattern, strategy pattern applications, and multi-threaded programming. That’s it. There must also be a key topic on database connections! ( Alright then.

Although I don’t want to find a job using Java, I still need to learn it because it’s a required course. Required!

Java Object Instantiation Methods

Reference: Several Ways to Instantiate Objects in Java There are several ways to instantiate objects in Java:

  • Using the new statement, the most commonly used method for creating objects.
  • Returning objects through factory pattern methods. Introduced in the design patterns section below. e.g.: String str = String.valueOf(23); Yes, this is it.
  • Using reflection, calling Class.newInstance() (or Constructor class) instance methods.
  • Calling the object’s Clone() method.
  • Through I/O streams (including deserialization), e.g., using readObject to read out an object instance through deserialization.

Java Design Patterns

Design patterns are a set of repeatedly used, widely known, categorized, and catalogued summaries of code design experience. Using design patterns ensures code reusability, readability, reliability, and program reuse.

Factory Pattern

Reference: Factory Pattern | Runoob

The Factory Pattern is one of the most commonly used design patterns in Java. It is a creational pattern that provides an optimal way to create objects. In the factory pattern, we do not expose creation logic to the client and use a common interface to point to newly created objects.

Intent: Define an interface for creating objects, letting subclasses decide which factory class to instantiate. The factory pattern defers the creation process to subclasses. Main problem solved: Interface selection problems. When to use: When we explicitly plan to create different instances under different conditions. How to solve: Let subclasses implement the factory interface, returning abstract products. Key code: The creation process is executed in subclasses. Practical example: You need a car and can pick it up directly from the factory without worrying about how it’s made or its internal implementation. Advantages:

  1. A caller only needs to know the name to create an object.
  2. Highly extensible; to add a product, just extend a factory class.
  3. Shields the specific implementation of products; callers only care about the product interface.

Disadvantages: Every time a product is added, a concrete class and factory implementation must also be added, which increases system complexity and dependency on concrete classes.

Decorator Pattern

Reference: Decorator Pattern | Runoob

The Decorator Pattern allows adding new functionality to an existing object without changing its structure. It is a structural pattern that wraps existing classes. This pattern creates a decorator class to wrap the original class, providing additional functionality while maintaining the integrity of the class method signatures.

When to use: When you want to extend a class without creating many subclasses.

How to solve: Divide specific responsibilities and inherit from the decorator pattern.

Key code: 1. The Component class acts as an abstract role and should not have concrete implementations. 2. The decorator class references and inherits the Component class; concrete extension classes override parent methods.

We demonstrate the decorator pattern with an example where we decorate shapes with different colors without modifying the shape classes.

Decorator pattern illustration

Observer Pattern

Reference: Observer Pattern | Runoob

When there is a one-to-many relationship between objects, the Observer Pattern is used. For example, when an object is modified, its dependent objects are automatically notified and

Observer pattern illustration
updated automatically. The Observer Pattern belongs to behavioral patterns.

Key code: An ArrayList in the abstract class stores the observers. Practical example: During an auction, the auctioneer observes the highest bid and notifies other bidders. Advantages:

  1. Observers and subjects are abstractly coupled.
  2. Establishes a trigger mechanism.

Disadvantages:

  1. If a subject has many direct and indirect observers, notifying all of them can be time-consuming.
  2. Circular dependencies between observers and subjects can trigger circular calls, potentially crashing the system.
  3. The observer pattern has no mechanism for observers to know how the observed target changed; they only know that it changed.

Proxy Pattern

Reference: Proxy Pattern | Runoob

In the Proxy Pattern, one class represents the functionality of another class. It is a structural pattern. In the proxy pattern, we create an object with an existing object to provide a functional interface to the outside world.

Main problem solved: Issues arising from directly accessing objects, such as: the object to access is on a remote machine. In object-oriented systems, some objects are expensive to create, require security controls, or need out-of-process access. Direct access brings many complications, so we add an access layer when accessing such objects. How to solve: Add an intermediary layer. Practical examples: 1. Shortcuts in Windows. 2. You can buy train tickets at a reseller instead of the train station. 3. A check or bank deposit slip is a proxy for account funds. Advantages: 1. Clear responsibilities. 2. High extensibility. 3. Intelligence. Disadvantages: 1. Adding proxy objects between clients and real subjects may slow request processing. 2. Implementing proxy patterns requires extra work; some are very complex.

Strategy Pattern

Reference: Strategy Pattern | Runoob

  • In the Strategy Pattern, a class’s behavior or algorithm can be changed at runtime. It is a behavioral pattern.
  • In the strategy pattern, we create objects representing various strategies and a context object whose behavior changes with the strategy object. The strategy object changes the context object’s execution algorithm.

Intent: Define a family of algorithms, encapsulate each one, and make them interchangeable.

Main problem solved: When there are many similar algorithms, using if…else becomes complex and hard to maintain.

When to use: When a system has many classes distinguished only by their behavior.

How to solve: Encapsulate these algorithms into individual classes for arbitrary replacement.

Key code: Implement the same interface.

Practical examples: 1. Zhuge Liang’s strategems in silk bags — each bag is a strategy. 2. Travel modes — cycling, driving, etc. Each travel mode is a strategy.

Advantages: 1. Algorithms can be freely switched. 2. Avoids multiple conditional statements. 3. Good extensibility.

Disadvantages: 1. The number of strategy classes increases. 2. All strategy classes must be exposed.

PS: For strategy pattern applications, this blog post is particularly good! Design Patterns | Strategy Pattern and Typical Applications

Java Serialization

Advanced Java Quiz - Serialized Object I/O

  • Java provides an object serialization mechanism where an object can be represented as a byte sequence containing the object’s data, type information, and the types of data stored in the object.
  • After writing a serialized object to a file, it can be read back and deserialized, meaning the object’s type information, data, and data types can be used to create a new object in memory.
  • The entire process is JVM-independent, meaning an object serialized on one platform can be deserialized on a completely different platform.

See Java Serialization | Runoob for details.

Java Event Handling and Listeners

Broadly speaking, there are many aspects. Here is a brief note: In Java’s event handling architecture, the main objects involved are Event, Event Source, and Event Listener. The listener-based event handling mechanism is a delegation-based approach, with the following implementation steps:

  • Delegation: Components delegate event handling to specific event handling objects.
  • Notification: When a specified event is triggered, the delegated event handler is notified.
  • Handling: The event handling object calls the appropriate event handling methods.

Listener pattern: After the event source registers a listener, when the event source triggers an event, the listener can call back the event object’s methods. More specifically, the listener pattern is based on register-callback event/message notification processing — the monitored entity notifies all monitors.

  1. Register listener: eventSource.setListener.
  2. Callback: eventSource implements onListener.

Methods for registering listener classes are referenced in: Summary of Java Listener Registration Methods Among these, anonymous class implementations are suitable when the events being listened to are simple.

Java Reflection

Reference blog: Java Reflection Explained

  • Java Reflection means that at runtime, for any class, you can know all its properties and methods; for any object, you can call any of its methods and properties, and change its properties. This is a key property that makes Java a dynamic language.
  • For a concrete implementation, see the previous assignment: Advanced Java Assignment

Java Aspect-Oriented Programming (AOP)

Source: Spring Core AOP Summary

AOP (Aspect-Oriented Programming) is one of Spring Framework’s signature features. Aspect-oriented programming means extending functionality without modifying source code, separating functional code from business logic code. Main uses: logging, performance statistics, security control, transaction processing, exception handling, etc. Main intent: Separate logging, performance statistics, security control, transaction processing, exception handling, etc. from business logic code. By separating these behaviors, we hope to place them in methods independent of the guiding business logic, so that changing these behaviors doesn’t affect the business logic code. Just review the concepts — it shouldn’t go too deep on the exam (hopefully).

Socket-Based Network Programming

Reference blogs: Java Advanced: Socket and Reflection, ServerSocket and Socket Communication Example | Runoob

Two programs on a network exchange data through a two-way communication link, and one end of this bidirectional link is called a Socket. Sockets are commonly used to implement client-server connections and are a very popular programming interface for TCP/IP protocols. A Socket is uniquely determined by an IP address and a port number.

In the Java environment, Socket programming mainly refers to TCP/IP-based network programming. The code can refer to the Runoob tutorial, which is easy to understand. The process is:

  1. Setting up the server side:
  • Server creates a communication ServerSocket
  • Server creates a Socket to accept client connections
  • Creates IO input stream to read data sent by the client
  • Creates IO output stream to send data to the client
  1. Setting up the client side:
  • Creates a Socket for communication, setting the server’s IP and Port
  • Creates IO output stream to send data to the server
  • Creates IO input stream to read data sent by the server

Multi-Thread Synchronization

See Assignment 2 for application: Advanced Java Quiz 2 — Threads

A Thread is an execution unit that runs independently of other threads and plays a vital role in Java’s multitasking.

Difference Between Threads and Processes

  • Thread: A lightweight program with a start, execution, and end. Multiple threads share the same memory and resources.
  • Process: Has its own independent memory space and resources; a running program.
  • Multithreading: Running multiple tasks simultaneously within one program.
  • Multiprocessing: Running multiple tasks (programs) simultaneously in the operating system.
  • A process can contain multiple threads that share the process’s resources. Processes are typically the basic unit for resource allocation, while threads are the basic unit for independent execution and scheduling.
  • Since threads are smaller than processes and basically don’t own system resources, scheduling them incurs less overhead, enabling more efficient concurrent execution of multiple programs.

Thread States:

  • born: New thread state
  • runnable: Ready state
  • running: Running state
  • blocked: Blocked state
  • sleeping: Sleeping state
  • waiting: Waiting state
  • dead: Dead state

Thread Synchronization: Ensures a resource can only be accessed by one thread at a time, thus guaranteeing the integrity of shared data and operations. Several ways to achieve thread synchronization: 7 Ways of Thread Synchronization

  • Synchronized methods: Add the synchronized keyword before the method.
  • Synchronized code blocks: Statements modified with the synchronized keyword.
  • Using volatile variables for thread synchronization.
  • Using reentrant locks for thread synchronization (ReentrantLock class).
  • Using thread-local variables for thread synchronization (ThreadLocal class).
  • Using blocking queues for thread synchronization (LinkedBlockingQueue class, for practical development away from low-level structures).
  • Using atomic variables for thread synchronization (AtomicInteger class).

The first four are enough for the exam (lol).

Database Connection Pools and Thread Pools

When using databases, connection pools are typically used rather than direct database connections, because creating and destroying each connection is expensive. Pool technology is responsible for allocating, managing, and releasing database connections. Resources are pre-created and reusable, ensuring that under multi-user scenarios, only a specified number of resources are used, avoiding the overhead of creating a new connection per user.

Thread pools work the same way. First, a collection of threads is created, called a thread pool. Using thread pools can significantly improve performance. The thread pool creates many idle threads at system startup. When a program submits a task to the thread pool, the pool starts a thread to execute it. After execution, the thread doesn’t die but returns to the pool as idle, waiting for the next task. Just understand the concepts For more details, see these blogs: Java Concurrency in Practice: Connection Pool Implementation, Detailed Guide to Java Thread Pools

Comparable/Comparator Interfaces

Reference blog: Comparing Objects in Java: Comparable and Comparator Interfaces My own application: Advanced Java Assignment

Comparable Interface

  • This interface imposes a total ordering on the objects of each class that implements it.
  • This ordering is called the class’s natural ordering.
  • The class’s compareTo method is called its natural comparison method. Object lists (and arrays) implementing this interface can be automatically sorted using Collections.sort (and Arrays.sort). Objects implementing this interface can be used as keys in sorted maps or elements in sorted sets, without specifying a Comparator.
  • The compareTo() method has a single parameter and returns an int. A return value greater than 0 indicates the object is greater than the parameter; less than 0 indicates the object is smaller; equal to 0 means they are equal.

Comparator Interface

  • The Comparable interface embeds comparison code in the class itself, while the Comparator interface implements comparison in a separate class.
  • If a class was designed without considering comparison and didn’t implement Comparable, a Comparator can be used later to implement the comparison algorithm for sorting, and different sorting criteria (e.g., ascending, descending) can be prepared.
  • Comparable forces natural ordering, while Comparator does not force natural ordering and allows specifying the sort order.

JDBC Database Connection

My project files Put database connection information in a mysql.properties configuration file with the following content:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/exp_1
user=root
pwd= your database password

Config class for retrieving configuration file information:

package config;

import java.io.FileInputStream;
import java.util.Properties;

public class Config {
    private  static Properties p = null;
    static {
        try {
            p = new Properties();
            p.load(new FileInputStream("config/mysql.properties"));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static String getValue(String key) {
        return p.get(key).toString();
    }
}

Define the database utility class DBUtil, including configuration fields, database connection object Connection, query result set ResultSet, commit status autoCommit (boolean type), PreparedStatement, etc. Methods include:

  • Get database connection: getConnection
  • Release resources: closeAll
  • Execute SQL statement for database queries: executeQuery
  • Execute SQL statements for database insert, delete, update operations: executeUpdate
public class DBUtil {
    private static String URL;
    private static String USER;
    private static String PASSWORD;
    private static String DRIVER;
    private PreparedStatement ps;
    private Connection connection;  // Database connection object
    private ResultSet resultSet;    // Query result set
    private boolean autoCommit;
    public DBUtil() {
        DRIVER = Config.getValue("driver");
        URL = Config.getValue("url");
        USER = Config.getValue("user");
        PASSWORD = Config.getValue("pwd");
    }
    /**
     * Get database connection
     * @return connection Database connection object
     */
    public Connection getConnection() throws SQLException {
        try {
            Class.forName(DRIVER);
            // Get database connection
            connection = DriverManager.getConnection(URL, USER, PASSWORD);
            System.out.println("Database connection successful");
            return connection;
        } catch (Exception e) {
            // If an exception occurs during connection, throw exception info
            e.printStackTrace();
            throw new SQLException("Driver error or connection failed!");
        }
    }

    /**
     * Release resources
     */
    public void closeAll() {
        // Close resultSet
        if(resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        // Close ps
        if(ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        // Close connection
        if(connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Execute SQL statement for database query
     * @param preSql SQL query statement with parameters to be filled
     * @param params List of parameters to fill in
     * @throws SQLException Database update exception
     * @return ResultSet Result set
     */
    public ResultSet executeQuery(String preSql, List<Object> params) {
        try {
            ps = connection.prepareStatement(preSql);
            if (ps != null) {
                // Fill in parameters
                for(int i = 0; i < params.size(); ++i) {
                    ps.setObject(i+1, params.get(i));
                }
            }
            // Execute SQL statement
            resultSet = ps.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return resultSet;
    }


    /**
     * Execute SQL statement for database insert, delete, update operations
     * @param sql SQL statement with parameters to be filled
     * @param params List of parameters to fill in
     * @throws SQLException Database update exception
     * @return Whether the update was successful
     */
    public boolean executeUpdate(String sql, List<Object> params) throws SQLException {
        int rowNum = -1;        // If row number is less than zero, the update failed
        ps = connection.prepareStatement(sql);
        if (params != null && !params.isEmpty()) {
            for(int i = 0; i < params.size();  ++i) {
                ps.setObject(i+1, params.get(i));
            }
        }
        rowNum = ps.executeUpdate(); //executeUpdate returns an integer indicating the number of affected rows (update count)
        return rowNum > 0;
    }
}

喜欢的话,留下你的评论吧~

© 2020 - 2026 cos @cosine
Powered by theme astro-koharu · Inspired by Shoka