Cabbage Java self study room covers core knowledge

The path of Java Engineers (1) The path of Java engineers (2) the path of Java engineers (3)

1. The functions and features of constructors in Java

Functions of constructors:

A method defined in a Java class that initializes an object, using the new+ constructor to create a new object and assign a value to an instance of the object.

Constructor syntax rules:

  1. Method names must be the same as class names
  2. No return value type and cannot be modified with void (methods with any return value type are not constructors)
  3. Parameters can be specified or not specified. It can be divided into parametric construction method and parametric construction method

Characteristics of the construction method:

  1. When no constructor is specified, the system automatically adds a constructor with no arguments
  2. Constructors can be overloaded: multiple methods with the same method name but different parameters are called to automatically select the corresponding method based on the different parameters
  3. Constructors are not inherited
  4. When we specify a constructor manually, the system will no longer add a constructor with or without parameters
  5. Constructors not only assign values to attributes of objects, but also ensure that they are assigned a reasonable value
  6. Constructors cannot be modified by static, final, synchronized, abstract, and native

2. Final keyword in Java

In Java, the final keyword can be used to modify classes, methods, and variables (including member and local variables).

decorator

When you modify a class with final, it indicates that the class cannot be inherited. That is, if a class is never inherited, it can be modified with final. Member variables ina final class can be set to final if necessary, but be aware that all member methods ina final class are implicitly specified as final methods.

Modification methods

A final modifier means that the method is “final”, meaning that it cannot be overridden (multiple final modifier methods can be overridden). One thing to note here: The premise of rewriting is that the subclass can inherit the method from the parent class. If the access control permission of the final modified method in the parent class is private, the subclass cannot inherit the method directly. Therefore, the same method name and parameters can be defined in the subclass at this time, and the contradiction between rewriting and final will no longer occur. Instead, new methods are redefined in subclasses.

Modify variables

When final modifies a base datatype, it means that the value of the base datatype cannot change once initialized; When final modifies a reference type, it cannot be made to point to any other object after it is initialized, but the contents of the object to which the reference refers can change. It’s essentially the same thing, because the referenced value is an address, and final requires that the value, the value of the address, not change.

Final decorates a member variable (property) and must be displayed for initialization. There are two ways to initialize a variable: one is at variable declaration time; The second way is to declare a variable without assigning an initial value, but to assign an initial value to the variable in all constructors of its class.

If the parameter type of a function is final, the parameter is read-only. That is, you can read and use the parameter, but you cannot change its value.

3. The static keyword in Java

Static can be used to modify class member methods, class member variables, and you can write static code blocks to optimize program performance.

public class Person {

    private Date birthDate;
    private static Date startDate, endDate;
    
    static {
        startDate = Date.valueOf("1990");
        endDate = Date.valueOf("2090");
    }
     
    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }
     
    boolean isBornBoomer(a) {
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0; }}Copy the code

The static method

Static methods are called static methods. Because static methods can be accessed without any object, there is no such thing as this for static methods, because there is no object attached to them. And because of this feature, non-static member variables and non-static member methods of the class cannot be accessed in static methods, because non-static member methods/variables must depend on the specific object to be called. Note, however, that while non-static member methods and variables cannot be accessed in static methods, static member methods/variables can be accessed in non-static member methods.

Static variables

Static variables are also called static variables. The difference between static and non-static variables is that static variables are shared by all objects and have only one copy in memory, which is initialized if and only if the class is first loaded. Non-static variables are owned by the object, initialized when the object is created, and have multiple copies that do not affect each other. Static member variables are initialized in the order defined.

The static block

Another key use of the static keyword is to form static blocks of code to optimize program performance. Static blocks can be placed anywhere in a class, and there can be more than one static block in a class. When the class is first loaded, each static block is executed in the same order as the static block, and only once. The static block can be used to optimize program performance because it is executed only once when the class is loaded.

4. The Volatile keyword in Java

Volatile visibility

The thread itself does not interact with the main memory directly, but does so through the thread’s working memory. This is essentially why data is not visible between threads. Therefore, to achieve visibility of volatile variables, start directly from this area. There are two main differences between writes to volatile variables and normal variables:

  1. Changes to volatile variables force the values to be flushed to main memory.
  2. Modifying a volatile variable invalidates the corresponding variable value in the working memory of other threads. Therefore, reading the value of this variable requires reading the value from main memory again.

Volatile ordering principle

Volatile prevents instruction rearrangements because of the use of memory barriers in the underlying JVM, which serve three main functions:

  1. It ensures that instruction reordering does not place subsequent instructions in front of the memory barrier, nor does it place previous instructions behind the barrier; That is, by the time the memory barrier instruction is executed, all operations in front of it have been completed;
  2. It forces changes to the cache to be written to main memory immediately.
  3. If it is a write operation, it invalidates the corresponding cache line in the other CPU.

5. Transient keyword in Java

  1. Once a variable is transient, it is no longer part of the object’s persistence and its contents cannot be accessed after serialization.
  2. The TRANSIENT keyword can only modify variables, not methods and classes. Note that local variables cannot be modified by the TRANSIENT keyword. If a variable is a user-defined class variable, the class needs to implement the Serializable interface.
  3. A static variable can no longer be serialized, regardless of whether it was serialized or not. (If the class static variable still has a value after deserialization, the value of the corresponding static variable in the current JVM will be the same.)

Synchronized keyword in Java

Synchronized is a Java keyword and a type of synchronization lock. It modifies the following objects:

  1. Modifies a block of code, called a synchronous block, that acts on code enclosed in curly braces {} and on the object that calls the block.
  2. Modify a method. The modified method is called a synchronous method. The scope of the modified method is the whole method and the object is the object that calls the method.
  3. Modify a static method that applies to the entire static method and to all objects of the class.
  4. Modifies a class whose scope is the part enclosed in parentheses after synchronized, and whose main objects are all objects of the class.

Decorates a code block

  1. When one thread accesses a block of synchronized(this) code in an object, other threads attempting to access the object are blocked.
/** ** Synchronize thread */
public class SyncThread implements Runnable {
   private static int count;

   public SyncThread(a) {
      count = 0;
   }

   public  void run(a) {
      synchronized(this) {
         for (int i = 0; i < 5; i++) {
            try {
               System.out.println(Thread.currentThread().getName() + ":" + (count++));
               Thread.sleep(100);
            } catch(InterruptedException e) { e.printStackTrace(); }}}}public int getCount(a) {
      returncount; }}Copy the code
  1. When one thread accesses a synchronized(this) synchronized block of an object, another thread can still access the non-synchronized (this) synchronized block of that object.
public class Counter implements Runnable {
   private int count;

   public Counter(a) {
      count = 0;
   }

   public void countAdd(a) {
      synchronized(this) {
         for (int i = 0; i < 5; i ++) {
            try {
               System.out.println(Thread.currentThread().getName() + ":" + (count++));
               Thread.sleep(100);
            } catch(InterruptedException e) { e.printStackTrace(); }}}}// a block of non-synchronized code that does not read or write count, so can not use synchronized
   public void printCount(a) {
      for (int i = 0; i < 5; i ++) {
         try {
            System.out.println(Thread.currentThread().getName() + " count:" + count);
            Thread.sleep(100);
         } catch(InterruptedException e) { e.printStackTrace(); }}}public void run(a) {
      String threadName = Thread.currentThread().getName();
      if (threadName.equals("A")) {
         countAdd();
      } else if (threadName.equals("B")) { printCount(); }}}Copy the code
  1. Specifies that an object is to be locked
/** * bank account */
public class Account {
   String name;
   float amount;

   public Account(String name, float amount) {
      this.name = name;
      this.amount = amount;
   }
   / / save
   public  void deposit(float amt) {
      amount += amt;
      try {
         Thread.sleep(100);
      } catch(InterruptedException e) { e.printStackTrace(); }}/ / make a withdrawal
   public  void withdraw(float amt) {
      amount -= amt;
      try {
         Thread.sleep(100);
      } catch(InterruptedException e) { e.printStackTrace(); }}public float getBalance(a) {
      returnamount; }}/** * Account operation class */
public class AccountOperator implements Runnable{
   private Account account;
   public AccountOperator(Account account) {
      this.account = account;
   }

   public void run(a) {
      synchronized (account) {
         account.deposit(500);
         account.withdraw(500);
         System.out.println(Thread.currentThread().getName() + ":"+ account.getBalance()); }}}Copy the code

Modify a method

A synchronized modification method is similar to that of a code block, except that the scope of a synchronized modification is different. A code block is a range enclosed in braces, while a synchronized method range is the entire function.

public synchronized void run(a) {
   for (int i = 0; i < 5; i ++) {
      try {
         System.out.println(Thread.currentThread().getName() + ":" + (count++));
         Thread.sleep(100);
      } catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code

Decorates a static method

Static methods belong to classes, not objects. Similarly, synchronized modified static methods lock all objects of the class.

/** ** Synchronize thread */
public class SyncThread implements Runnable {
   private static int count;

   public SyncThread(a) {
      count = 0;
   }

   public synchronized static void method(a) {
      for (int i = 0; i < 5; i ++) {
         try {
            System.out.println(Thread.currentThread().getName() + ":" + (count++));
            Thread.sleep(100);
         } catch(InterruptedException e) { e.printStackTrace(); }}}public synchronized void run(a) { method(); }}Copy the code

Modify a class

Synchronized applies to a class T by locking it; all objects of T use the same lock.

/** ** Synchronize thread */
public class SyncThread implements Runnable {
   private static int count;

   public SyncThread(a) {
      count = 0;
   }

   public static void method(a) {
      synchronized(SyncThread.class) {
         for (int i = 0; i < 5; i ++) {
            try {
               System.out.println(Thread.currentThread().getName() + ":" + (count++));
               Thread.sleep(100);
            } catch(InterruptedException e) { e.printStackTrace(); }}}}public synchronized void run(a) { method(); }}Copy the code

Exception handling and class hierarchies in Java

Introduction to Java Exceptions

An exception is an unexpected event that occurs while a program is running and prevents the program from executing as expected. When the anomaly occurs, the program is left to die and quit immediately. In Java, errors that occur during compilation or execution of Java.

Java offers an even better solution: an exception handling mechanism. The exception handling mechanism allows the program to deal with exceptions according to the pre-set exception handling logic of the code when exceptions occur, so that the program can recover and continue to execute as much as possible, and keep the code clear.

An exception in Java can be raised during the execution of a statement in a function or manually thrown by a programmer using a throw statement. Once an exception is generated in a Java program, an exception object of the corresponding type is used to encapsulate the exception. The JRE tries to find an exception handler to handle the exception. The Java exception mechanism uses the following keywords: try, catch, finally, throw, throws.

  1. Try — for listening. The code to be listened on (code that might throw an exception) is placed inside the try block, and when an exception occurs within the try block, the exception is thrown.
  2. Catch — Used to catch exceptions. Catch is used to catch exceptions that occur in a try block.
  3. Finally — Finally blocks are always executed. It is primarily used to reclaim physical resources (such as database connections, network connections, and disk files) that are opened in the try block. Only a finally block will return to execute a return or throw statement ina try or catch block. If a statement terminates a method such as a return or throw is used in the finally block, it will not jump back to execution.
  4. Throw — Used to throw an exception.
  5. Throws — used in a method signature to declare exceptions that the method may throw. Throws can also be used on the main method. If throws is used on the main method, it means that exception handling is not mandatory in the main method. If an exception occurs, it is handed over to the JVM for default processing, which will result in program interruption.

There are three types of exceptions:

  1. Checking exceptions: The most representative checking exceptions are those caused by user errors or problems that the programmer could not have foreseen. For example, when trying to open a nonexistent file, an exception occurs that cannot simply be ignored at compile time.
  2. Runtime exceptions: Runtime exceptions are exceptions that can be avoided by programmers. In contrast to checking exceptions, runtime exceptions can be ignored at compile time.
  3. Errors: Errors are not exceptions, but problems outside the programmer’s control. Errors are generally ignored in code. For example, when a stack overflow occurs, an error occurs that is not detected at compile time.

Java exception classification

The root interface of the Exception Throwable has two subinterfaces, Error and Exception.

  1. Error: a JVM Error in which the program is not executed and cannot be handled;
  2. Exception: Refers to an Exception generated during the execution of a program that can be handled by the user using the processing format.

8. Java hashCode () and equals() methods

HashCode definition

From the Object perspective, every time the JVM creates a new Object, it drops that Object into a Hash table, so that the next time it compares or fetches that Object (during reading), it fetches that Object from the Hash table based on the Object’s HashCode. The purpose of this is to improve the efficiency of fetching objects. Call equal if HashCode is the same.

  1. The existence of HashCode is mainly used for quick lookup, such as Hashtable, HashMap, etc. HashCode is used to determine the storage address of the object in the hash storage structure.
  2. If two objects are the same, the equals method must return true, and they must have the same HashCode; Unless you override the method;
  3. If the equals method of an object is overridden, then the HashCode of the object should be overridden as well, and the resulting HashCode must be the same as that used in the equals method, otherwise it will violate point 2 above.
  4. The fact that two objects have the same HashCode does not necessarily mean that they are identical. Equals does not necessarily return true, but it does mean that the two objects are in a hash storage structure, such as Hashtable, and that they are stored in the same basket.

HashCode role

There are two classes of collections in Java: List and Set. The elements in the former set are ordered and can be repeated. The latter element is unordered, but the element cannot be repeated. The equals method can be used to ensure that elements are not duplicated, but if the equals method is checked every time an element is added to the collection, if there are already 1000 elements in the collection, then the equals method will be called 1000 times when the 1001st element is added to the collection. This is obviously a huge loss of efficiency.

So, Java adopted the principle of hash tables.

Hashing algorithm, also known as hashing algorithm, is to specify data directly to an address according to a specific algorithm. That way, when you add a new element to the collection, you call the element’s HashCode method, and you can immediately locate it in its physical location.

  1. If there is no element in this location, it can be stored directly in this location without any comparison;
  2. If the location already has an element, its equals method is called to compare it with the new element.
  3. If they are different, that is, if the Hash key is the same, the conflict will occur. Key generates a linked list of all objects that produce the same HashCode into this single linked list, strung together (rarely). This actually reduces the number of calls to equals to almost one or two.

Hashcode () and equals() methods

HashCode is used for lookups, and equals is used to compare whether two objects are equal.

  1. For example, memory has the following locations: 0, 1, 2, 3, 4, 5, 6, 7.

And I have a class that has a field called ID, and I’m going to store that class in one of these eight places, and if I don’t use HashCode to store it anywhere, then when I look it up, I’m going to have to look in each of these eight places, or I’m going to use a binary algorithm or something like that. But if you use HashCode that’s a lot more efficient. Define our HashCode as ID % 8. For example, if our ID is 9, the remainder of 9 divided by 8 is 1, then we put the class at position 1. If ID is 13, the remainder is 5, then we put the class at position 5. And so on.

  1. However, if two classes have the same HashCode, for example, 9 divided by 8 and 17 divided by 8 both have a remainder of 1. In other words, we use HashCode first to determine whether the two classes are stored in a bucket, but the bucket may contain many classes, such as hashtable. So we need to go back to equals and find the class we want in the bucket.

9. Differences between IO streams in Java and BIO,NIO, and AIO

Byte-oriented stream InputStream/OutputStream

InputStream and OutputStream are two abstact classes that extend both base classes for byte-oriented streams

Character-driven stream Reader/Writer

A Unicode-oriented stream that reads and writes information to and from a stream in Unicode characters.

BIO,NIO,AIO

  1. BIO (Blocking I/O): Synchronous Blocking in I/O mode, data reads and writes must be blocked in a thread waiting for it to complete. In the case that the number of active connections is not particularly high (less than 1000 for a single machine), this model is relatively good, allowing each connection to focus on its OWN I/O and simple programming model, without too much consideration of system overload, current limiting and other problems. The thread pool itself is a natural funnel to buffer connections or requests that the system can’t handle. However, when faced with hundreds of thousands or even millions of connections, the traditional BIO model is powerless. Therefore, we need a more efficient I/O processing model to handle the higher concurrency.

  2. NIO (non-blocking /New I/O): NIO is a synchronous non-blocking I/O model. The NIO framework was introduced in Java 1.4, corresponding to the Java. NIO package, providing abstractions such as channels, selectors, buffers, and so on. N in NIO can be interpreted as non-blocking, not just New. It supports buffer-oriented, channel-based approaches to I/O operations. NIO provides two different Socket channel implementations, SocketChannel and ServerSocketChannel, that correspond to Socket and ServerSocket in the traditional BIO model. Both channels support both blocking and non-blocking modes. Blocking mode, like traditional support, is relatively simple, but has poor performance and reliability. Non-blocking mode is the opposite. For low-load, low-concurrency applications, synchronous blocking I/O can be used for faster development and better maintenance; For high-load, high-concurrency (network) applications, NIO’s non-blocking mode should be used for development.

  1. AIO (Asynchronous I/O): AIO is NIO 2. NIO 2, an improved version of NIO introduced in Java 7, is an asynchronous, non-blocking IO model. Asynchronous IO is implemented based on events and callbacks, meaning that an action is applied and returned, not blocked, and when the background processing is complete, the operating system notifies the appropriate thread to proceed with the subsequent action. AIO is short for asynchronous IO. Although NIO provides a non-blocking method for network operations, NIO’s I/O behavior is synchronous. For NIO, our business thread is notified when the IO operation is ready, and then the thread performs the IO operation itself, which is synchronous. Looking around the Internet, I found that AIO is not widely used so far, and Netty tried and abandoned AIO before.

10. Basic concepts of threads and processes and their relationships

The basic concept

Thread is an entity in the process, which is the basic unit that is independently scheduled and dispatched by the system. The thread does not own the operating system resources, but the thread can share all the resources owned by the process with other threads of the same process.

Process is a software program in the computer about a data set of a running activity, is the system resource allocation and scheduling of the basic unit, is the basis of the operating system structure. In the early process-oriented computer architecture, the process is the basic execution entity of the program, while in the modern thread-oriented computer architecture, the process is the container of the thread. Software program is the description of instruction, data and its organizational form, and the surface process is the entity of the program. Generally speaking, the software program running in the system is called process.

Relationship between threads and processes

Threads are smaller running units that processes are divided into. The main difference between threads and processes is that processes are essentially independent, whereas threads are not necessarily, as threads in the same process will most likely interact with each other. On the other hand, a process belongs to the category of operating system, mainly in the same period of time, can execute more than one program, while a thread is in the same program almost simultaneously execute more than one program segment.

The basic state of the thread

  1. New: A thread object is created.

  2. Runnable: After a thread object is created, other threads (such as the main thread) call its start() method. Threads in this state are in the runnable thread pool, waiting to be selected by thread scheduler for CPU usage.

  3. Running: A runnable thread gets a TIMESlice and executes program code.

  4. Block: A blocked state is when a thread has relinquished CPU usage for some reason, giving up CPU timeslice, and temporarily stops running. Until the thread enters the runnable state, it has no chance to get the CPU timeslice again and go to the running state. There are three types of blocking: Wait blocking: A running thread executes o.wait(), and the JVM places the thread in a waiting queue. When a running thread acquires a lock on an object and the lock is held by another thread, the JVM adds that thread to the lock pool. Sleep (long ms) or t.join(), or when an I/O request is issued, the JVM blocks the running Thread. When the sleep() state timeout join() waits for the thread to terminate or timeout, or when I/O processing is complete, the thread returns to the runnable state.

  5. Dead: the run(), main() methods of a thread end execution, or exit the run() method because of an exception, the thread ends its life cycle. Dead threads cannot be resurrected.

The path of Java Engineers (1) The path of Java engineers (2) the path of Java engineers (3)