javase learning notes

Keywords: Java Back-end

Lao Du, eternal God!!!

Features of java language

1. Simplicity. Single inheritance is supported in Java, multiple inheritance is supported in c + +, and there is no pointer in Java.

2. Robustness. There is an automatic garbage collection mechanism (GC) in java, and the jvm will recycle objects without variables in the heap.

3. Portable. Compile once and run everywhere. We only need to compile it into bytecode file, and then install jre running environment on windows or linux system.

4. Multithreading. The handler is faster.

5. Security. Open source code is safer for programmers.

JDK installation

After downloading the JDK (java development kit), if you need to compile and run java files on the DOS command line, you need to configure the environment variable for the system in advance and add the bin directory in the JDK to the PATH in the environment variable.

The JDK contains jre and jvm, and jre contains jvm. If you need to develop, you need to install JDK. If you only need to run bytecode files, you only need to install jre of the corresponding system. This reflects the portability of java files.

Compiling and running of java

In the DOS window, compile the javac + source file path

java + class name to run

Running process of java program

Use javac to compile and generate bytecode files, and then use Java commands to call the JVM virtual machine. At this time, the JVM will start the classloader to find the bytecode file in the current directory. After finding it, the classloader will give the file to the JVM, which will translate it into a binary file that can be read by the operating system. (after JDK11, including JDK11, you can directly use java + source file path for compilation and operation)

Identifier in java

In java, identifiers are things that we can modify, not system definitions.

Are identifiers:

Class name, method name, variable name, constant name and interface name.

Identifiers can include:

It is composed of numbers, letters, underscores and dollar symbols, but numbers cannot be used as the beginning.

It is strictly case sensitive and its length is not limited.

Naming conventions for identifiers:

Class name and interface name: follow the hump naming method (the first letter of each word is uppercase and the rest is lowercase).

Variable name and method name: the first word is all lowercase, and each subsequent word follows the hump naming method.

Constant name: each word is capitalized with an underscore in the middle.

variable

The most basic storage unit in memory is a box used to hold data.

Three elements of variables:

Data type, variable name, literal (data).

int i = 1;

Different positions of variables will lead to different scopes of variables. Large scope includes small scope. For example, member variable scope includes local variable scope.

data type

There are two types of data in java. Basic data type and reference data type. The basic data type is the system default. Except for String, other basic reference data types are defined by the user.

Basic data type:

​ byte(1) ,short(2),int(4),long(8) ,float(4),double(8),boolean(1),char(2)

Reference data type:

String (string is formed by splicing multiple char characters.)....

Of which:

byte indicates the range: - 128 ~ 127

short indicates the range: - 32768 ~ 32767

int indicates the range: - 2147483648 ~ 2147483647

char indicates the range: 0 ~ 65535

It can be assigned directly within the value range. In addition to the boolean type, other basic types of data can be converted to each other.

Small capacity can be directly converted into large capacity, which is called automatic type conversion.

Large capacity can be converted to small capacity, which is called forced type conversion. (loss of accuracy)

int i =(int)2147483648;  //Strong conversion to Int beyond Int range

Input integer data will be treated as int by default, and input floating-point data will be treated as double.

float i = 5.0F;  
long  j = 2147483648L; //If L is not added, it will be treated as int type data. If int is assigned to long, an error will be reported

When byte, short, int and char are mixed, the jvm will first convert them to int type and then convert them

Character encoding

The original computer code was ASCII code. Although one byte was used to store ASCII code, the first bit was discarded, so there were only 128 ASCII codes at most.

Later, the ISO-8859-1 code, which is commonly used as latin-1, appeared, but this code does not support Chinese. Later, GB2312, GBK and GB18030 (the size of the three character codes increases from left to right) appeared, and Chinese was supported.

java uses Unicode encoding (to support global text), which supports utf8, utf16 and utf32······

The traditional Chinese character code is big5.

Logical operator

Arithmetic operators: relational operators: logical operators: ternary operators:

​ ±*/%+±- > >= < <= == != &|! && || Boolean expression? Expression 1: expression 2

Receive keyboard input data

java.util.Scanner s = new java.util.Scanner(System.in);
int i = s.nextInt();//Receive integer
String j = s.next();//Receive string

Loop, turn, branch statements

Loops include for, while, and do while. Steering includes break, continue, and return. Options include if and switch

for(i=0;i<10;i++){
    if(i==5){
    continue;//When i is equal to 5, jump out of this cycle and proceed to the next cycle
	system.out.println("This is the second"+i+"Print times");
	}
	if(i==9){
	system.out.println("This is the second"+i+"Print times");
	break;//When i is equal to 9, the cycle of this layer is terminated
	}
}
switch(value){//String and int types are OK
	case Value 1:
		java sentence;
		break;//If the break is not written, case breakdown will occur. The breakdown will not end until the break or branch is found
	case Value 2:
		java sentence;
		break;
		············
	default
	 java sentence;
}

The do... while loop must be executed once. break terminates the loop at this level, continue jumps out of this loop and proceeds to the next loop. Return is used to return the result and terminate the current method.

method

Code snippets that can be reused and have specific functions.

definition:

[Modifier list] Return value type method name (formal parameter list){Method body;}

The statements in the method body are executed from top to bottom.

When the method and the entry are in the same class, you can call the method directly. If you are not in the same class, you need to enter '' class name. Method '' call.

When we use recursive methods, we must ensure that there is a termination condition at the end, otherwise the recursive call will produce a stack memory overflow error.

jvm memory space

JVM memory space mainly consists of three parts: heap area, stack area and method area.

Method area:

After the JVM is started, it will call the class loader to load the bytecode file into the method area to form a code fragment. At this time, the method area stores all the non running bytecode files. In addition, our static variables will be assigned when the class is loaded, and our static code blocks will also be executed.

Stack area:

When we call a method, the JVM will load the corresponding method into the stack area. This process is called pressing the stack. If the executing code fragment (method) calls another method while it is running, the JVM will continue to press the stack until the last method is called, and after the execution is completed, start from the last method and execute the previous method code of the method in reverse until the end. This process is called bouncing the stack. Therefore, the stack stores the running methods and local variables. (the stack frame in the stack area always points to the top of the stack, so the method at the top of the stack is active)

Stacking area:

When our heap method is executing, an object may be created. The object we create will be put into the heap by the JVM. After the object is created, the JVM will return us a memory address, which is the address of the created object, and this address will be returned to our reference. If our reference is not released, our corresponding objects in the heap will not be released. Therefore, the heap stores the objects we create and the instance variables in the objects.

User u = new User();//Where new User(); Is an object, u is a reference, and the User in front of u is the data type of the variable.

object-oriented

For C language, it is completely object-oriented. Although object-oriented is comfortable when writing code, the coupling between code and code is high, one ring after another, and it is very troublesome to expand in the later stage. C + + is a kind of code that is half object-oriented and half process oriented. Our JVM underlying code is implemented in C + +.

For the java language, it is completely object-oriented. In our real life, we are exposed to objects, such as Xiao Ming playing basketball. Xiao Ming is an object, basketball is also an object, and there is a playing behavior between them. Using object-oriented programming development, it can be more convenient for us to program.

Object oriented terminology:

OOA object oriented analysis

OOD object oriented design

OOP object oriented programming

Three characteristics of object-oriented:

Encapsulation, inheritance and polymorphism.

Encapsulation - > inheritance - > polymorphism (layer upon layer)

Classes and objects

Class: some things in the real world have the same characteristics. We abstract these characteristics into a concept, which is called class.

Object: an individual existing in reality. (instance is another appellation of object)

The process of extracting the features of objects into classes is called abstraction. The process of creating objects with classes is called instantiation.

The variables in the class are called instance variables, and the methods are called instance methods (there can also be other types of methods). Instance methods cannot be modified by static. The invocation of instance methods requires' 'reference. Method name' '. A variable in a class is actually an attribute, and a method is an action. A has a B indicates that a has an attribute B.

The object is created by new. The creation method of the object has been described above and will not be repeated here.

Construction method

After we create a class, if we do not create a constructor for it, the system will generate a parameterless constructor (also known as the default constructor) by default. However, if we create a parameterless constructor, the system will no longer create parameterless constructors for us. Therefore, we need to create both parameterless and parameterless constructors.

class User(){
	int id;
	String name;
		public User(){}//Nonparametric structure
		public User(int id,String name){
		this.id = id;//this refers to the address of the current object
		this.name = name;
		}
}

encapsulation

We generally recommend using the private modifier to modify the attributes in our class. The variables modified by private can only be used in this class. In other classes, we need to use the get() and set() methods to call. We can limit the program calling variables and assignment in the get() and set() methods. Using encapsulation allows us to better protect the interior of the class. We only need to call the entry to access it.

For variables modified by static keyword, we can access' 'through' 'class name. Variable name' 'or' 'reference. Variable name', but we recommend the calling form of the former for static variables. Static variables generally will not change after initial value is assigned. Therefore, we do not need to assign values every time the new object is loaded (the initial value has been assigned when the class is loaded and stored in the method area) .

class User{
	private int id;
		public User(){}//Nonparametric structure
		public User(int id){
			this.id = id;//this refers to the address of the current object
		}
		public int getId(){
			return this.id;
		}
		public void setId(int id){
			if(id==123)
			return ;
			this.id=id;//Description the id value can be changed successfully only if the entered id is not 123
		}
}

class Test{
	public static void main(String[] args){
		User u = new User();//Create a User object and call the parameterless construct
        u.setId(456);
		System.out.println(u.getId());//Print id
	}
}

This keyword is only used in this class and can be omitted in most cases. However, if the name of the passed parameter is the same as that of the parameter to be assigned, it cannot be omitted. For example, this.name=name cannot be omitted, otherwise it will assign its own value. When this() is placed on the first line of the construction method, it means that the parameterized construction can be called to pass values.

class User{
	int id;
		public User(){
		this(678);//In the parameter free construction method, we call the parameter structure and assign it.
		}//Nonparametric structure
		public User(int id){
			this.id = id;//this refers to the address of the current object
		}
		
}

inherit

Subclasses inherit the properties and methods of the parent class (construction methods cannot be inherited, and the private properties inherited by the parent class cannot be accessed directly, but get and set methods can be used) to realize code reuse. Inheritance also laid the foundation for later polymorphism. Only with inheritance can there be polymorphism. In the java language, classes only support single inheritance. All classes will eventually inherit the Object class, which is the ancestor of all classes. If it can be described by A is a B, then A is A subclass and B is A parent class.

class Anmial{
	private String name;
	public void move(){//move method
		System.out.println("Animals are walking");
	}
	public Anmial(){}
	public Anmial(String name){
		this.name=name;
	}
	public String getName(){
	 	return this.name;
	}
	public void setName(String name){
		this.name=name;
	}
}

class Cat extends Anmial{
	public void move(){//Override the move() method of the parent class
	System.out.println(this.getName()+"Walking");
	}
}

class Test{
 public static void main(String[] args){
     Cat cat = new Cat();
     cat.setName("cat");//Use the setName method to assign a value to the private property of the inherited parent class
     cat.move();
 }
}

Overwrite (overwrite)

After we inherit the parent method, if the parent method cannot meet our needs, we need to override the parent method. Rewriting is to expand requirements.

be careful:

The constructor cannot be overridden because it cannot be inherited.

The method permissions after rewriting are higher than those of the parent class, and the exceptions thrown are less than those of the parent class.

Rewriting is a method, not a property. Private methods cannot be rewritten. Static method rewriting is meaningless.

When rewriting, the return value type, method name and parameter list are required to be the same, and the method body is different. (method overloading requires the same variable values, different formal parameters (number, order and type of formal parameters) and similar method bodies. Method overloading is to solve the problem that multiple methods have similar functions.)

polymorphic

There are two forms of compilation and Runtime: static binding at compile time and dynamic binding at runtime.

Use of polymorphism

class Anmial{
	private String name;
	public void move(){//move method
		System.out.println("Animals are walking");
	}
	public Anmial(){}
	public Anmial(String name){
		this.name=name;
	}
	public String getName(){
	 	return this.name;
	}
	public void setName(String name){
		this.name=name;
	}
}

class Cat extends Anmial{
	public void move(){//Override the move() method of the parent class
	System.out.println(this.getName()+"Walking");
	}
}

class Test{
 public static void main(String[] args){
     Anmial cat = new Cat();
     if(cat instanceof Cat){
       Cat x = (Cat)cat;
    	 x.setName("cat");//Use the setName method to assign a value to the private property of the inherited parent class
    	 x.move();
         }
 }
}

In the Test class, line 26, Anmial cat = new Cat(), Anmial is the parent type, and the reference points to the subtype cat. If you compile from the left during compilation, it is considered that the variable cat is of Anmial type, and the move method of the parent class is detected in line 28 during compilation; However, when running from right to left, the subclass rewritten move method will be called to realize polymorphic applications.

Anmial cat = new Cat(), this new object method is called upward transformation. Cat is a subclass and is converted to the parent anmial type.

Cat x = (Cat)cat, which is called downward transformation. Because errors may occur during downward transformation (if the object address pointed to by cat reference is not of cat type), it is necessary to judge with "A instanceof downward type" during downward transformation. Forced transformation can be carried out only when the types are consistent.

be careful:

The premise of using polymorphism: there must be inheritance.

super

The super() method can actively call the parameterless or parameterless construction method of the parent class (if no parameters are passed, the parameterless construction method is called by default). If there is no parent class, it inherits the object class by default (therefore, if there is multi-layer inheritance, when calling the super() method, it will also look for the parent class construction method layer by layer and execute it according to the definition order of the stack).

As long as there is a parameterless constructor, there will be a super() method. When we create a parameterless constructor, if we don't fill in anything internally, we add a super() method for it by default.

The super() method can only be placed on the first line of the constructor, and the this() method can only be placed on the first line of the constructor. Therefore, there can only be one of the two methods in a constructor.

Super also represents the address of the parent class, so "super." can be used to call parent methods or properties (only for instance methods).

abstract class

Abstract class: it is a class formed by two or more abstract classes. For example, savings card class and credit card class can be further abstracted into bank card class.

Abstract classes can have abstract methods (abstract methods have no method body) or non abstract methods. However, if a class has abstract methods, it must be an abstract class.

Although an abstract class cannot be instantiated (the class abstracted from the class cannot be instantiated), it can be inherited. However, if a subclass inherits the abstract method of the parent class, it must override the abstract method in the parent class.

abstract class Card{
    private int id;
    abstract  void printId();//Abstract method has no method body

    public Card(int id) {
        this.id = id;
    }

    public Card() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}


class Creditcard extends Card{
     public void printId(){
         System.out.println("Credit Card ID yes"+this.getId());
     }
}
class Depositcard extends Card{
    public void printId() {
        System.out.println("savings deposit card ID yes" + this.getId());
    }
}

class Test{
    public static void main(String[] args) {
        Card c1 = new Creditcard();
        c1.setId(100001);
        Card c2 = new Depositcard();
        c2.setId(200001);
        c1.printId();
        c2.printId();
    }
}

final

The class modified by final cannot be inherited, the modified method cannot be overridden, and the modified variable can only be assigned once.

The constant created by the combination of final and static is called a constant. If we do not assign an initial value to it, the system will automatically assign an initial value to the new object by calling the parameterless construction method. However, once the value is assigned, it cannot be modified, and the constant will lose its meaning. Therefore, we need to assign a value to it before the program assigns an initial value to it. We can use the parameterless construction method It can also be assigned directly after the constant name. (constant naming specification: all letters are capitalized, and each word is connected with an underscore)

Because the class modified by final cannot be inherited, and abstract classes are generally used for inheritance, final and abstract classes cannot be used together.

Interface

Only constants and abstract methods can be stored in the interface, so we can omit the public static final of constants and the public abstract of abstract methods, and the program will automatically fill them in when calling.

Interfaces are different from classes. Classes only support single inheritance, while interfaces support multiple inheritance. When we create a class and its internal methods, we must assign values to its constants and implement the abstract methods of the interface. If the abstract methods are not implemented, the program cannot run normally. (a class can implement multiple interfaces)

The application of the interface is to reduce the coupling between the caller and the implementer. The interface is like an intermediary. The caller only needs to care about what functions of the interface are available, not how to implement the functions. They are separated.

The properties owned by the class can be implemented by the interface.

--------------------------------------------------------------------------Create interface
interface CardNature{//Use the interface to set what the card contains
    void printColour();
    void printSize();
}
---------------------------------------------------------------------------Implementation interface method
class Card implements CardNature{//Method for implementing card interface
    private String cardColour;
    private String cardSize;

    public Card(String cardColour, String cardSize) {
        this.cardColour = cardColour;
        this.cardSize = cardSize;
    }

    public Card() {
    }

    public String getCardColour() {
        return cardColour;
    }

    public void setCardColour(String cardColour) {
        this.cardColour = cardColour;
    }

    public String getCardSize() {
        return cardSize;
    }

    public void setCardSize(String cardSize) {
        this.cardSize = cardSize;
    }

    public  void printColour(){
        System.out.println("What is the color of the card"+this.getCardColour());
    }
    public void printSize(){
        System.out.println("What is the card size"+this.getCardSize());
    }
}
-------------------------------------------------------------------------Create caller
class User{//Users only see the interface and don't care how to implement it
    CardNature cardNature;

    public User(CardNature cardNature) {
        this.cardNature = cardNature;
    }

    public CardNature getCardNature() {
        return cardNature;
    }

    public void setCardNature(CardNature cardNature) {
        this.cardNature = cardNature;
    }
    
    
    public void seeColour(){
        cardNature.printColour();
    }
    public void seeSize(){
        cardNature.printSize();
    }
}
---------------------------------------------------------------------------test
class Test{
    public static void main(String[] args) {
        CardNature c = new Card();//Upward transformation
        if(c instanceof Card){//Judge whether c is a Card type. If yes, transition down
            Card cc = (Card)c;//Downward transformation
            cc.setCardColour("white");//set a property
            cc.setCardSize("10cm");
            User u =new User(cc);
           u.seeColour();//The user looks at the card color
           u.seeSize();//The user sees the card size
        }
    }
}

array

Array is a storage method for storing multiple data of the same data type in a continuous space. The stored data type can be basic data type or reference data type. If the stored data type is basic data type, all the data stored in the array space is data. If it is reference data type, all the data stored is the address of the object. We can use the address to Find this object.

Since the storage space of the array is continuous, when we create an array, the reference returned by the program to the array is the initial address of the array. Since we already know what data type the address stores, we can determine the address of the value through the first address and the subscript of the value in the array (initial address + (subscript + 1) * data type length).

There are two forms of array initialization, one is static initialization and the other is dynamic initialization. The traversal of the array only needs to use the for loop.

public class Test{
    public static void main(String[] args) {
        int[] arr1 = new int[]{1,4,6,4,3};//initiate static
        int[] arr2 = new int[5];//dynamic initialization
        for (int i=0;i<5;i++){
            arr2[i]=(int)(Math.random()*10);
        }
        String[] arr3 = new String[5];//Reference data type array
        arr3[0]="Xiao Ming";
        arr3[1]="floret";
        arr3[2]="Xiao Huang";
       for (int i=0;i<5;i++)
           System.out.println(arr1[i]);
        System.out.println("---------------------------------");
        for (int i=0;i<5;i++)
            System.out.println(arr2[i]);
        System.out.println("---------------------------------");
        for (int i=0;i<5;i++)
            System.out.println(arr3[i]);
    }
}

To copy the array, you can call the System.arraycopy() method in the library. (system. Arraycopy (copy source, start location, copy destination, start location, length)) Array has a disadvantage. Once the length is determined, it cannot be changed. Therefore, when the length of our array cannot meet our needs, we need to new an array with larger capacity. Use the System.arraycopy() method to copy the values in the original array to the new array, and the original array can be released.

public class Test{
    public static void main(String[] args) {
        int[] arr1 = new int[]{1, 4, 6, 4, 3};
        int[] arr2 = new int[10];
        System.arraycopy(arr1, 0, arr2, 0, arr1.length);
     for (int i=0;i<5;i++)
         System.out.println(arr1[i]);
        System.out.println("--------------------------------------");
        for (int i=0;i<10;i++)
            System.out.println(arr2[i]);
        arr1=null;
    }
}

System.arraysort in array

Access control rights

Access control rightsThis categorySame packageSubclassCross package
public
protected
Default (add nothing)
private

What can an access control permission modifier modify?

Properties (all 4 can be used)

Methods (all 4 can be used)

Class (public and default)

Interface (public and default)

String,StringBuffer,StringBuilder

String data type is a reference data type, but we don't need a new object in the process of using it. We can assign a value to it directly.

The character content enclosed in double quotation marks is immutable. (the byte array of the underlying character is modified by final. Once it is put into the string constant pool, the value cannot be modified.)

String constant pool:

It is located in the method area, which stores the strings we created. Each string created will generate a string object and cannot be modified. If two different strings are added, three strings will be generated. These strings have their own unique storage addresses.

String str1 = "123";//Create first string object
String str2 = "456";//Create a second string object
String str = str1+str2//Create a third string object
    String str3 = "123";//No new string will be created because the "123" string has already been created on line 1
String str4 = "123";
String strr = str3+str4//Create a fourth string object

Integer constant pool:

Since -128 ~ 127 these data are often called by the system, the JVM has opened up a space in the method area to store these commonly used integers, which is called the integer constant area. Convenient for us to call. These data have their own unique addresses.

If we splice strings frequently, the program will constantly generate string objects in the static constant pool, reducing efficiency. StringBuffer can solve this problem. The bottom layer of StringBuffer calls the Byte array, which is 16 by default. We can use the System.append() method to add characters to the array, These characters will not be put into the string constant pool. When the Byte array is full, the bottom layer will automatically call the Arrayscopy() method to expand the array.

Differences between StringBuffer and Stringbuilder:

StringBuffer is safe in a multithreaded environment.

StringBuilder is not safe in a multithreaded environment. However, in a single thread, it is more efficient than StringBuffer.

String method

import java.util.Locale;
public class StringTest {
    public static void main(String[] args) {
     String str = new String(" QWEdw#21#23 ");
        System.out.println(str);//Print string to console
        System.out.println("Second bit of string:"+str.charAt(2));
        System.out.println("2 First occurrence:"+str.indexOf("2"));
        System.out.println("2 Location of the last occurrence"+str.lastIndexOf("2"));
        System.out.println("Convert all letters to lowercase:"+str.toLowerCase());
        System.out.println("Convert all letters to uppercase:"+str.toUpperCase());
        System.out.println("The string after the second bit is intercepted:"+str.substring(2));
        System.out.println("Intercept strings from 2 to 6:"+str.substring(2,6));
        System.out.println("Determine whether the string is empty:"+str.isEmpty());
        System.out.println("Remove front and back blanks:"+str.trim());
        System.out.println("Replace "2" with "1":"+str.replace("2","1"));
        System.out.println("Judge whether there is in the string“ dw"character string:"+str.contains("dw"));
        System.out.println("Get string length:"+str.length());
        System.out.println("Determine whether the string is“ QW"start:"+str.startsWith(" QW"));
        System.out.println("Judge whether the string ends with "23":"+str.endsWith("23 "));
        System.out.println("Determine whether the string contains“ dw"character string:"+str.contains("dw"));
        System.out.println(""With"#"Split string");
        String[] s = str.split("#");
        for(int i=0;i<s.length;i++)
            System.out.println(s[i]);
        System.out.println("Convert string to char array");
        char[] c = str.toCharArray();
        for(int i=0;i<c.length;i++)
            System.out.print(c[i]+" ");
        System.out.println();
        System.out.println("-----------------------------------------------------");
     String str1 = new String("aSdAB123");
     String str2 = new String("asDAB123");
          System.out.println(str1);
         System.out.println(str2);
        System.out.println("Compare two strings for equality:"+str1.equals(str2));
        System.out.println("Compare two strings for equality, case insensitive:"+str1.equalsIgnoreCase(str2));

    }
}

exception handling

Throwable is a class. Its subclasses are Error and Exception (there is a runtimeException (runtime Exception) class and compile time Exception class under the Exception class). Once the Error class occurs, the JVM will exit directly and cannot be recovered. The Exception class is something we can handle.

Exceptions are divided into compile time exceptions and run-time exceptions (RunTimeException). Compile time exceptions must be handled. If we do not handle them, the code cannot be passed by the compiler, and run-time exceptions can be handled or not handled. Both compile time exceptions and run-time exceptions occur during the run-time.

There are generally two ways to deal with compile time exceptions, one is "throws" and the other is to deal with them directly in the current (try... catch).

We can't throw up at the method entrance and exit and must handle it. We can't hand over exceptions to the JVM for processing.

If throws is used to throw an exception, the code fragment after the exception will not be executed. If try... catch is used to handle the exception, the code fragment after try... catch will still be executed.

Custom exception class

public class IllegalInputException extends Exception{//Create exception class manually
    public  IllegalInputException(){}
    public  IllegalInputException(String s){
        super(s);
    }
}

Test exception

import java.util.Scanner;
//The user enters the name and password to judge whether the name is legal (6-14 digits). If it is not legal, the exception defined by us will be reported
public class RegisterTest {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        System.out.println("Please enter user name:");
        String s1 = s.next();
        System.out.println("Please input a password:");
        String s2 = s.next();
        UserService u =new UserService();
        try {
            u.register(s1,s2);
        } catch (IllegalInputException e) {
           e.getMessage();
            System.out.println(e);//Print exception information
        }
    }
}

 class UserService { //Define class
        private String username;
        private String password;
    public void register(String username,String password) throws IllegalInputException {
        if(username.length()>14||username.length()<6)
           throw new IllegalInputException("Illegal value entered");//Manually throw an exception, which has been defined above, and enter the exception information
        this.username=username;
        this.password=password;
    }
}

Try can be used not only with catch, but also with finally (try... Catch, try... Finally, try... Catch... finally). The code fragments placed in finally will be executed.

If the result is returned in try, the statement block in finally will still be executed normally. The JVM will find a variable to store the value in i first, and then continue to execute the statement in finally. Finally, it returns the first executed return statement. At this time, it returns not i but the variable with value. (java language, executed from top to bottom)

public class TryTest { //The result is 1
    public static void main(String[] args) {
        int i=1;
        System.out.println(question(i));
    }

    public static int question(int i){
        try{
            return i;
        }
        finally {
            return ++i;

        }
    }
}

aggregate

There are three main types of sets: list, map and set.

A collection can only be placed at the address of an object.

Map can be transferred to Set (using entrySet or keyset, and keyset needs to obtain the value value during traversal), and Set can be transferred to list (put the Set into the new Set), but there is a problem in the reverse.

Iterators and enhanced for loops are generally used for traversal of collections.

Subclasses of Iterable (Interface) are Collection (Interface), and subclasses of Collection are set (Interface) and list (Interface)

Under list (ordered and repeatable), there are common classes such as ArrayList, LinkedList and Vector.

Under set (unordered and non repeatable): HashSet, TreeSet and other common classes. (the parent class of TreeSet is SortedSet).

Under map (unordered and unrepeatable), there are common classes such as HashMap, Hashtable, properties (a subclass of Hashtable), treemap (the parent class is SortedMap).

ArrayList:

The bottom layer of the ArrayList collection is an Object [] array, and the length of the Object [] array is initialized to 10, and the capacity is assigned to Object [] by the JVM when the first value is assigned Array. When the Object array is full, the array will be expanded by 1.5 times. Because the bottom layer of ArrayList is implemented by array, query and modification efficiency is high. However, ArrayList is non thread safe.

mport java.util.*;

public class CollectionTest {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("123");
        c.add(100);
        String s = new String("SAD");
		c.add(s);
        System.out.println(c.size());
        c.remove(100);
        System.out.println(c.size());
       Iterator it =c.iterator();
       while (it.hasNext())//Traversing a collection using an iterator
           System.out.println(it.next());

LinkedList:

At the bottom of the LinkedList set is a two-way linked list. The linked list has no initial length and can be expanded all the time. In addition, the addition and deletion efficiency of the linked list is high.

 List<String> l =new LinkedList<>();
        l.add("asd");
        l.add("dsa");
        l.add("12233");
         l.set(2,"qwe");//Modified value
        System.out.println(l.lastIndexOf("dsa"));//Determine the position where "dsa" appears last
        Iterator it2=l.iterator();
        while (it2.hasNext())//Traversal using iterators
            System.out.println(it2.next());
        for (String ss:l//Traversal using foreach
        ) {
            System.out.println(ss);
        }

Vector:

The bottom layer of the Vector collection is an Object [] array with an initialization capacity of 10. When the array capacity is full, the array will be expanded in a double relationship. Because the bottom layer of the Vector is implemented by the array, the query and modification efficiency is high. However, the Vector is thread safe. Because the Vector thread is safe, the efficiency is not as high as ArrayList.

HashSet:

The bottom layer of the HashSet set is a HashMap, and only the key part of the HashMap is used. The initial length of the HashMap set is 16. When the set capacity is full of 0.75, the HashMap will automatically expand to twice the original set. And the HashSet is non thread safe. (HashTable is thread safe)

TreeSet:

The bottom layer of TreeSet (sortable) uses TreeMap, and only the key part of HashMap is used. The initial length of the HashMap set is 11. When the set capacity is full of 0.75, the HashMap will automatically expand to double and 1 of the original set. If the TreeSet collection is used and the stored data type is user-defined, the compareTo method of the comparable interface must be implemented. (this method is responsible for sorting)

import java.util.Iterator;
import java.util.TreeSet;

public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        treeSet.add("123");
        treeSet.add("456");
        treeSet.add("100");
        System.out.println(treeSet.size());
        treeSet.add("456");
        System.out.println(treeSet.size());
        treeSet.remove("456");
        System.out.println(treeSet.size());
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext())
            System.out.println(iterator.next());
    }
}

Properties:

The Key and value of Properties must be of string type.

import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class PropertiesTest {
    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.setProperty("123","Zhang San");
        properties.setProperty("124","Li Si");
        properties.setProperty("93","Wang Wu");
        properties.setProperty("25","Zhao Liu");
        System.out.println(properties.getProperty("123"));
        Set<Map.Entry<Object, Object>> entries = properties.entrySet();//Convert the propertyoes set into a set square
        Iterator<Map.Entry<Object, Object>> iterator = entries.iterator();
        while (iterator.hasNext()){
            Map.Entry<Object, Object> next = iterator.next();
            Object key = next.getKey();
            Object value = next.getValue();
            System.out.println(key+"--->"+value);
        }
    }
}

HashMap:

At the bottom of the HashMap is the hash table. The bottom layer of the hash table consists of an array and several single linked lists. Therefore, HashMap integrates the advantages and disadvantages of linked lists and arrays. The initial length of the hash table is 16. When the hash table is full of 0.75, the HashMap will automatically expand to twice the original table. If the HashMap collection is used and the stored data type is user-defined, the eauals and hashcode methods must be overridden. When saving data, the hash table will first use the hashcode method to convert the key into a hash value, and then convert it into an array subscript through the hash algorithm, and compare it with all nodes under the subscript (equals). If it is not repeated, it can be inserted. Non thread safe.

import java.util.*;

public class MapTest {
    public static void main(String[] args) {
        HashMap<Integer,String> m =new HashMap<>();
        m.put(1,"zhangsan");
        m.put(2,"liwang");
        m.put(3,"wwangwu");
        System.out.println(m.size());
        System.out.println(m.get(2));
        Set<Integer> keys = m.keySet();//Get the key first, and then use the get method to get the value in the process of traversal
        Iterator<Integer> iterator = keys.iterator();
        while(iterator.hasNext()) {
            Integer integer = iterator.next();
            String s = m.get(integer);
            System.out.println(integer+"="+s);
        }
        for (Integer i:keys
             ) {
            String s = m.get(i);
            System.out.println(i+"="+s);
        }
        System.out.println("-----------------");
        Set<Map.Entry<Integer, String>> entries = m.entrySet();
        Iterator<Map.Entry<Integer, String>> iterator1 = entries.iterator();
        while (iterator1.hasNext()){
            System.out.println(iterator1.next());
        }
        for (Map.Entry<Integer, String> i:entries
             ) {
            System.out.println(i);
        }
    }
}

To use a custom type key, you must override the hashcode and equals and toString methods. If the keys are the same and the values are different, they will be overwritten.

import java.util.*;

public class HashMapTest {
    public static void main(String[] args) {
        HashMap<Student, Integer> hashMap = new HashMap<>();
        hashMap.put(new Student("zhangsan"),5);
        hashMap.put(new Student("lisi"),3);
        hashMap.put(new Student("wangwu"),2);
        hashMap.put(new Student("zhaoliu"),1);
        hashMap.put(new Student("wangwu"),2);
        Set<Map.Entry<Student, Integer>> entries = hashMap.entrySet();
        Iterator<Map.Entry<Student, Integer>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}
class Student{
    String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

Hashtable:

The initial call capacity of the Hashtable is 11. When the set capacity is full of 0.75, the Hashtable will automatically expand by 2 times + 1 of the original set. Thread safe.

TreeMap:

The bottom layer of TreeMap is a binary tree, and the binary tree is orderly. If the TreeMap collection is used and the stored data type is user-defined, the compareTo method of the comparable interface must be implemented.

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class TreeMapTest {
    public static void main(String[] args) {
        TreeMap<Integer, String> treeMap = new TreeMap<>();
        treeMap.put(1,"zhangsan");
        treeMap.put(5,"lisi");
        treeMap.put(4,"zhaoliu");
        treeMap.put(4,"maqi");
        Set<Integer> objects = treeMap.keySet();
        Iterator<Integer> iterator = objects.iterator();
        while (iterator.hasNext()) {
            Integer next = iterator.next();
            System.out.println(next+"="+treeMap.get(next));
        }
        System.out.println("---------------------");
        Set<Map.Entry<Integer, String>> entries = treeMap.entrySet();
        Iterator<Map.Entry<Integer, String>> entryIterator = entries.iterator();
        for (Map.Entry<Integer, String> s:entries
             ) {
            System.out.println(s.getKey()+"="+s.getValue());

        }
    }
}

The user-defined type (key) in HashMap must implement the comparable interface (compare the key successively, and the first value is the same as the second ratio) and the toString method. If the keys are the same and the values are different, they will be overwritten.

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class TreeMapTest1 {
    public static void main(String[] args) {
        TreeMap<User, Integer> treeMap = new TreeMap<>();
            treeMap.put(new User(5,"zhangsan"),3);
            treeMap.put(new User(4,"lisi"),2);
            treeMap.put(new User(4,"wangwu"),1);
            treeMap.put(new User(3,"zhaoliu"),5);
         	treeMap.put(new User(3,"zhaoliu"),6);
        Set<Map.Entry<User, Integer>> entries = treeMap.entrySet();
        Iterator<Map.Entry<User, Integer>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}
class User implements Comparable<User>{//Implement Comparable interface
    int id;
    String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public int compareTo(User o) {//Override compareTO method
        if(this.id==o.id)
            return this.name.compareTo(o.name);
        return this.id-o.id;
    }
}

IO stream

The IO stream is used for the interaction between hard disk and memory. The IO stream is like a pipe connecting it.

IO flows fall into four categories:

​ InputStream,OutputStream,Reader,Writer. The first two types are byte streams and the last two types are character streams. And 1 and 3 are input streams and 2 and 4 are output streams.

When we use up the stream, we must remember to close the stream (close()), and at the end of the output stream, we must use the flash() method to refresh the pipeline to empty the remaining data in the pipeline to ensure the integrity of the data we have obtained.

Common streams:

FileInputStream, FileOutputStream -- > file byte stream

FileReader, FileWriter -- > file character stream

BufferedInputStream, BufferedOutputStream -- > buffered byte stream

BufferedReader, BufferedWirter -- > buffered character stream

InputStreamReader, OutputStreamWirter -- > byte conversion stream

PrintStream, PrintWirter -- > output stream

DataInputStream, DataOutputStream -- > data stream

ObjectInputStream, ObjectOutputStream -- > object stream

The common ones are:

​ FileInputStream,FileOutputStream,ObjectInputStream,ObjectOutputStream,PrintStream

FileInputStream:

Because it is a byte stream, we use a byte array to store the read data. If the length of the byte array is 4, it indicates that it can read up to 4 bytes at a time. Define a flag variable outside the loop to save the number of read data (that is, the length). Use a while loop to judge whether there is data in the file. If not, the loop ends. Print the data we read every time. (if we do not set the initial array, each time we read the flag variable, we will not read a length, but a value.)

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest {
    public static void main(String[] args) {
        FileInputStream fileInputStream=null;
        try {
            fileInputStream = new FileInputStream("E:\\Java\\JavaProjects\\javase\\IoStream\\src\\test.txt");//Absolute path, relative path starts under the project
            byte[] bytes = new byte[4];//Use a byte array to receive the passed data
            int read = 0;//Define a flag variable to judge whether there is data in the file
            while ((read=fileInputStream.read(bytes))!=-1)//Judge whether there is data in the file. fileInputStream.read(bytes)) stores the number of data read by the array at that time,
                System.out.print(new String(bytes,0,read));//Output the data read and placed in the array
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream!=null) {
                try {
                    fileInputStream.close();//Close flow
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

The txt file is read by the above file input stream

admin=1223525235
password=7890

FileOutputStream:

The file output stream is simpler than the file input stream. Directly call the Wirter method of the stream to write the data, and finally brush the stream and close the stream. (ture is used to add content without emptying the original content)

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutPutStreamTest {
    public static void main(String[] args) {
        FileOutputStream fileOutputStream=null;
        try {
             fileOutputStream = new FileOutputStream("test1.txt",true);//Path to output file
            String s = new String("made in China");
            byte[] b1 =s.getBytes();//Convert string to byte array
            fileOutputStream.write(b1);//Write to file
            fileOutputStream.flush();//Refresh stream
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream == null) {
                try {
                    fileOutputStream.close();//Close flow
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Copy data from one file to another (combining input and output streams):

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyTest {
    public static void main(String[] args) {
        FileInputStream fileInputStream=null;
        FileOutputStream fileOutputStream=null;
        try {
            fileInputStream = new FileInputStream("E:\\a.txt");//Enter file path
            fileOutputStream = new FileOutputStream("E:\\b.txt",true);//Output file path. true is used to append. The original stored content is not cleared
            byte[] b = new byte[1024*1024];//Store read data
            int count=0;//Flag variable
            while ((count=fileInputStream.read(b))!=-1)//Can I read the data
            fileOutputStream.write(b,0,count);//Writes the data stored in the array to a file
            fileOutputStream.flush();//Refresh stream
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();//Close flow
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

FileReader:

FileReader is similar to FileInputStream. FileReader reads in character and FileInputStream reads in byte. FileReader uses char [] array to store the read data, and FileInputStream uses byte [] array to store the read data.

FileWirter:

The usage is exactly the same as FileOutputStream.

ObjectOutputStream:

ObjectOutputStream is used to serialize objects. Put objects into a collection and store the collection using the writeObject() method of the object stream.

To serialize objects, you must implement the Serializable interface, which is just a flag for the JVM to recognize.

If we change the contents of the serialized class after a period of time, there may be problems in deserialization, so we mark the serialization Id in the class to be serialized in advance

After that, even if we modify the code content of the serialization class, the deserialization can succeed.

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;

public class SerializationTest {
    public static void main(String[] args) throws IOException {
        ArrayList<Object> objects = new ArrayList<>();//Create a collection to store the new objects
        objects.add(new Serialization(1));
        objects.add(new Serialization(1));
        objects.add(new Serialization(1));
        objects.add(new Serialization(1));
        objects.add(new Serialization(1));
        objects.add(new Serialization(1));
        //Specify storage path
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("log.txt"));
        objectOutputStream.writeObject(objects);//Serialize the objects collection. The serialized file content is a pile of garbled code and needs to be deserialized

    }
}


class Serialization implements Serializable{
    private static final long serialVersionUID = 0001L;//Serialization number, random number, shall be globally unique
    private int i;

    public Serialization(int i) {
        this.i = i;
    }

    @Override
    public String toString() {
        return "Serialization{" +
                "i=" + i +
                '}';
    }
}

ObjectInputStream:

ObjectInputStream is used to deserialize objects. Use the stream to get the serialized file, call the readObject method of the stream, complete deserialization, and output.

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Iterator;

public class SerializationreadTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {//Throw the anomaly out first
        //Serialized file path
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("log.txt"));
        Object o = objectInputStream.readObject();//Read serialized object, this should be a collection
       if(o instanceof ArrayList){
           ArrayList a=(ArrayList)o;//Downward transformation
           for (Object aa:a
                ) {
               System.out.println(aa);//Enhanced for traversal
           }
           Iterator iterator = a.iterator();//Iterator traversal
           while (iterator.hasNext()) {
               Object next = iterator.next();
               System.out.println(next);
           }
       }

    }
}

PrintStream:

PrintStream is a standard output stream that can be used to record logs. The following code is used for this purpose. System.setOut specifies the output path.

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;

public class PrintStreamTest {
    public static void main(String[] args) {
       log("Modify text");
       log("Modify picture");
    }
    public static void log(String s){
        try {
            PrintStream printStream = new PrintStream(new FileOutputStream("log.txt",true));
            System.setOut(printStream);//Output to specified file
            Date date = new Date();
            //Specifies the formatted format
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss ssss");
            String format = simpleDateFormat.format(date);//Format Date
            System.out.println(format+"   "+s);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }
}

IO stream matching Properties collection:

With the combination of the two, you can take out the "value" corresponding to "key" in the file.

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

public class IoPropertiesTest throws Exception{
    public static void main(String[] args) {      
        FileInputStream fileInputStream = new FileInputStream("IoStream\\src\\test.txt");//Get the file
        Properties properties = new Properties();//new a properties collection
            properties.load(fileInputStream);//load file
        System.out.println(properties.getProperty("admin"));//Get value from key
    }

}

admin=1223525235//test.txt content
password=7890

Other streams are not commonly used. No more.

thread

Process is the smallest unit of resource allocation, and thread is the smallest unit of program execution. A program is a process. A process can be completed by several threads. Generally speaking, the process directs the thread to work.

Heap memory and method area memory resources between threads are shared, but stack area resources are not shared. Each thread has a separate stack.

Thread scheduling model:

Preemptive, scheduling by thread priority

Equal fraction, which allocates the same time slice to each thread

The method involved in thread scheduling in java: void setPriority (int newPriority) sets the priority. static void yield() gives way to the thread. This method will change the thread from running state to ready state. void join() merges the thread into the currently running thread, which is equivalent to queue jumping. The queue jumping thread runs before running the current thread.

There are three ways to implement threads:

Class directly inherits the thread and overrides the run method of the thread. Turn this class into a thread class.

Thread A and thread B run simultaneously.

public class ThreadExtendsTest {
    public static void main(String[] args) {
        AThread aThread = new AThread();//new a thread object
        BThread bThread = new BThread();
        aThread.setName("thread  A");//Thread rename
        bThread.setName("thread  B");
        aThread.start();//Start thread
        bThread.start();
    }

}
class AThread extends Thread{//Inheritance thread
    @Override
    public void run() {//Rewrite the run method of the thread
        for (int i=0;i<10000;i++)
            //Thread.currentThread().getName() this method is to get the name of the current thread
        System.out.println(Thread.currentThread().getName()+"Running!");
    }
}
class BThread extends Thread{
    @Override
    public void run() {
        for (int i=0;i<10000;i++)
            System.out.println(Thread.currentThread().getName()+"Running!");
    }
}

Class implements the Runnable interface

public class ThreadRunnableTest {
    public static void main(String[] args) {
        CThread threadC = new CThread();//new out the corresponding class object first
        DThread threadD = new DThread();
        Thread cThread = new Thread(threadC);//Turn the object into a thread object
        Thread dThread = new Thread(threadD);
        cThread.setName("thread  C");
        dThread.setName("thread  D");
        cThread.start();
        dThread.start();
    }
}
class CThread implements Runnable{//Implement Runnable interface
    @Override
    public void run() {
        for(int i=0;i<1000;i++)
        System.out.println(Thread.currentThread().getName()+"Running!");
    }
}
class DThread implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<1000;i++)
            System.out.println(Thread.currentThread().getName()+"Running!");
    }
}

Class implements the Callable interface

Implementing the Callable interface, we will get a return value, which is obtained using the FutureTask.get() method

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadCallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        EThread threadE = new EThread();//new is a corresponding class object
        FThread threadF = new FThread();
        FutureTask futureTask1 = new FutureTask<>(threadE);//The new FutureTask object is used to get the return value of the thread
        FutureTask futureTask2 = new FutureTask<>(threadF);
        Thread eThread = new Thread(futureTask1);//Join thread
        Thread fThread = new Thread(futureTask2);
        eThread.setName("E process");
        fThread.setName("F process");
        eThread.start();
        fThread.start();
        System.out.println(futureTask1.get());//Get return value
        System.out.println(futureTask2.get());
    }
}

class EThread implements Callable {
    int i=100;
    @Override
    public Object call() throws Exception {
        return i;
    }
}
class FThread implements Callable {
    int i=200;
    @Override
    public Object call() throws Exception {
        return i;
    }
}

In the future development environment, we are facing the multi-threaded running environment. In this case, if multiple thread objects modify a shared data at the same time, it may cause data security problems.

This leads to the thread synchronization mechanism:

If multiple threads want to operate a shared data at the same time, they need to queue. Sacrifice some efficiency, but ensure data security.

Thread synchronization mechanism will reduce the user experience.

Resolve thread synchronization issues:

Use local variables instead of instance variables and static variables. Local variables are in the stack area, so there is no security problem.

If it is an instance variable, you can create multiple objects so that each thread has a separate object adjustable.

If the first two cannot be solved, only synchronized can be used.

synchronized locks shared objects“

For example:

Producers and consumers share a warehouse. Only when there is inventory in the warehouse can consumers consume. Similarly, when the warehouse is full, producers cannot reproduce. (after using thread synchronization mechanism, either produce or consume at a time point)

Both wait() and notify() are object-level methods. Sleep sleeps the current thread and interrupts sleep with a reference to. interrupt().

import java.util.ArrayList;

public class HomeWorkTest {
    public static void main(String[] args) {
        ArrayList<Object> objects = new ArrayList<>();//new a warehouse object
        Producter producter = new Producter(objects);//Share warehouse with producer
        Customer customer = new Customer(objects);//Share warehouse to consumer
        Thread threadA = new Thread(producter);//Production thread
        Thread threadB = new Thread(customer);//Consumption thread
        threadA.setName("producer");
        threadB.setName("consumer");
            threadA.start();//start-up
            threadB.start();
    }
}
class Producter implements Runnable{
    private ArrayList objects;
    public Producter(ArrayList objects) {
        this.objects = objects;
    }

    @Override
    public void run() {
        while (true) {//Always produce
            synchronized (objects) {//Lock the warehouse. The object of the lock is the warehouse
                if (this.objects.size() > 0) {//Stop production when there is inventory in the warehouse
                    try {
                        this.objects.wait();//Surrender your lock and the following code will not be executed
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                Object o = new Object();
                objects.add(o);//Add inventory
                System.out.println(Thread.currentThread().getName()+o);//output
                this.objects.notify();//Wake up other threads
            }
        }
    }
}

class Customer implements Runnable{
    private ArrayList objects;
    public Customer(ArrayList objects) {
        this.objects = objects;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (objects) {
                if (objects.size() == 0) {//No inventory, stop consumption
                    try {
                        this.objects.wait();//Surrender your lock and the following code will not be executed
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + objects.get(0));//output
                objects.remove(0);//Move out of stock
                objects.notify();//Wake up other threads
            }
        }
    }
}

If the synchronization mechanism is not used properly, it will cause deadlock. The deadlock will not report an error and the program will not terminate.

Thread A calls the o1 object first and thread B calls the o2 object first. When thread A calls o2, it is found that o2 has been locked. When thread B calls o1, it is found that o1 is locked.

public class DeadLockTest {
    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = new Object();
        Thread threadA = new ThreadA(o1, o2);
        Thread threadB = new ThreadB(o1, o2);
        threadA.setName("thread  A");
        threadB.setName("thread  B");
        threadA.start();
        threadB.start();
    }
}

class ThreadA extends Thread{
    private Object o1;
    private Object o2;

    public ThreadA(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }

    @Override
    public void run() {
        synchronized (o1){//Lock o1
            try {
                Thread.sleep(5000);//Set the sleep time so that o2 has a high probability of being locked by process B
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o2){//Lock o2
                System.out.println(Thread.currentThread().getName()+"------Running");
            }
        }
    }
}
class ThreadB extends Thread{
    private Object o1;
    private Object o2;

    public ThreadB(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }
    
    @Override
    public void run() {
        synchronized (o2){//Lock o2
            synchronized (o1){//Lock o1
                System.out.println(Thread.currentThread().getName()+"------Running");
            }
        }
    }
}

timer

The timer executes a specific action at a specific time, and can set the time of repeated execution of the action.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {
    public static void main(String[] args) throws ParseException {
        Timer timer = new Timer();//new a timer object
        TimerTask01 timerTask = new TimerTask01();//new a timer task
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date firstDate = simpleDateFormat.parse("2021-11-16 11:15:00");//Format time
        timer.schedule(timerTask,firstDate,1000);//Call timer method (task, execution time, repeat execution interval)
    }
}
class TimerTask01 extends TimerTask {//The timer task inherits the TimerTask class

    @Override
    public void run() {
       Date time = new Date();//Get current time
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = simpleDateFormat.format(time);//Format current time
        System.out.println(format+"Complete backup");
    }
}

Daemon

As long as our user thread exists, the daemon thread will always execute. Generally, the daemon thread is an endless loop. When all user threads end, the daemon thread will also end.

public class DeamonTest {
    public static void main(String[] args) {
        MyDeamon myDeamon = new MyDeamon();
        Thread thread = new Thread(myDeamon);
        thread.setDaemon(true);//Set this thread as a daemon
        thread.setName("Daemon thread");
        thread.start();
        for (int i=0;i<1000;i++)
            System.out.println(Thread.currentThread().getName()+"Running!");

    }
}
class MyDeamon implements Runnable{
    @Override
    public void run() {
        while(true)
        System.out.println(Thread.currentThread().getName()+"Running!");
    }
}

Reflection mechanism

Reflection mechanism allows us to directly manipulate bytecode files, which can increase the scalability of our programs.

There are three ways to get class es in java:

Class c = Class.forname("Class name");//First kind
Class c = object.getClass();//Second
Class C = data type.class;//Third

There are three class loaders in the JDK by default:

Start class loader (rt.jar), extension class loader (ext/*.jar), and application class loader (classpath). It is called from front to back, in which the start and extension are called the two parent delegation mechanism.

Reflection mechanism and flow loading path

There are many file loading methods, and the starting loading path may be different

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.ResourceBundle;

public class ReflectionTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {

        System.out.println("-----------First kind------------------");
        InputStream fileInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("Test.properties");//Stream loading method, regardless of the operating system, starts writing under src
        /*System.out.println("------------The second kind ------------);
        String path = Thread.currentThread().getContextClassLoader().getResource("Test.properties").getPath();//Write from src
        FileInputStream fileInputStream = new FileInputStream(path);

        System.out.println("----------The third kind ------------ ");
        FileInputStream fileInputStream = new FileInputStream("reflection\\src\\Test.properties");//Start writing under the project

        */
        Properties properties = new Properties();
        properties.load(fileInputStream);
        fileInputStream.close();
        String file = properties.getProperty("file");
        Class name = Class.forName(file);
        Object o = name.newInstance();//An object instantiated
        if (o instanceof User){
            User u =(User)o;
            u.setId(100);
            System.out.println(u);
        }
    }
}

Stream loaded file

 file=User

User class

public class User {
     int id;
     public String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public User() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                '}';
    }
}

Use the reflection mechanism to create a new object and set properties to obtain properties. (the resource binder is the most convenient method to obtain files, but the obtained file suffix is properties)

import java.lang.reflect.Field;
import java.util.Enumeration;
import java.util.ResourceBundle;

public class ReflectionTest4 {
    public static void main(String[] args) throws Exception {
        ResourceBundle bundle = ResourceBundle.getBundle("Test");//The resource binder binds the properties file, and the path starts under src. There is no need to take the properties suffix
        String file = bundle.getString("file");//Get the content corresponding to the "=" sign on the right side of the file
        Class forName = Class.forName(file);//Get the class. If you write the relative path directly, it starts from src and continues to write to the class, connected with "."
        Object obj = forName.newInstance();//new instance
        Field id = forName.getDeclaredField("id");//Get id attribute
        id.set(obj,1001);//assignment
        Field name = forName.getDeclaredField("name");
        name.setAccessible(true);//Break the package
        name.set(obj,"Zhang San");
        System.out.println(id.get(obj)+" "+name.get(obj));
    }
}

Use the reflection mechanism to create a new object and call the instance method

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionTest5 {
    public static void main(String[] args) throws Exception {
        Class methodloginTest = Class.forName("MethodloginTest");
        Object obj = methodloginTest.newInstance();
        Method method = methodloginTest.getDeclaredMethod("login", String.class, String.class);//Get method
        Object o = method.invoke(obj, "1001", "password");//Call the method and pass the initial value (invoke is the call)
        if (o instanceof Boolean){
         boolean oo = (boolean)o;
       System.out.println((oo?"Login succeeded":"Login failed"));}
        Method loginout = methodloginTest.getDeclaredMethod("loginout");
        loginout.invoke(obj);//Call method
    }
}

class MethodloginTest {
    public boolean login(String admin,String password){
        if (admin.equals("1001")&&password.equals("password"))
            return true;
        else
            return false;
    }
    public void loginout(){
        System.out.println("Exit succeeded!");
    }
}

When the newInstance method is called to create an object, the parameterless constructor of the class is automatically called.

import java.lang.reflect.Constructor;

public class ReflectionTest7 {
    public static void main(String[] args) throws Exception{
        Class user = Class.forName("User");
        Object obj = user.newInstance();//Auto call parameterless construction
        Constructor constructor = user.getDeclaredConstructor(int.class, String.class);
        Object newInstance = constructor.newInstance(123, "abc");//Creating objects with parametric constructs
        System.out.println(newInstance);
    }
}

annotation

Annotation is a reference data type that generates a class file after compilation.

Annotations can appear on classes, methods, variables, and attributes.

Definition note:

[modifier list] @ interface annotation name{

Data type variable name 1 (); data type can be basic type, array of basic data type, class, String and String array

Data type variable name (2);

}

If the variable name of the annotation is "value" and the annotation has only one attribute, the annotation does not need "value = value", but only "value". If there is only one value in the array, "{}" can be omitted.

Meta annotation:

Commonly used are: target and retention. Target is used to set the target of the annotation. Retention is used to save the last saved location of the annotation. (generally, the saved location is source or class or runtime (the runtime attribute allows us to use the reflection mechanism))

Common annotations: Override and deprecated.

The method modified by the Override annotation needs to Override the method of the parent class.

Classes or methods modified by the deprecated annotation or other... Will show that they are obsolete.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)//This annotation can only be placed on a class
public @interface MyAnnotationClass {
    int name1();
    String name2();//There can be attributes in the annotation
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//This annotation can only be placed on attributes
@interface MyAnnotationField{
    int value() default 123;//When assigning the value attribute, you only need to write the value in the annotation
    //String[] s(); if there is only one value in the array, do not use parentheses
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CONSTRUCTOR)//This annotation can only be placed on the constructor
@interface MyAnnotationConstructor{}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)//This annotation can only be placed on methods
@interface MyAnnotationMethod{}

Using annotations and getting custom annotation values

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

@MyAnnotationClass(name1 = 123,name2="admin")//When using annotations, assign values to the attributes in the annotations
public class AnnotationTest1 {
    //test
    public static void main(String[] args) throws Exception{
        Class forName = Class.forName("AnnotationTest1");
        boolean ClassAnnotationPresent = forName.isAnnotationPresent(MyAnnotationClass.class);//Judge whether the class has corresponding annotation
        if(ClassAnnotationPresent){
            Annotation classAnnotation = forName.getAnnotation(MyAnnotationClass.class);//Get class annotation value
            System.out.println(classAnnotation);
        }

        Field id = forName.getDeclaredField("id");
        boolean idAnnotationPresent  = id.isAnnotationPresent(MyAnnotationField.class);//Judge whether the attribute has corresponding annotation
        if(idAnnotationPresent){
            MyAnnotationField idAnnotation = id.getAnnotation(MyAnnotationField.class);//Get attribute annotation value
            System.out.println(idAnnotation);
        }

        Method dosome = forName.getDeclaredMethod("dosome");
        boolean dosomeAnnotationPresent = dosome.isAnnotationPresent(MyAnnotationMethod.class);//Judge whether the method has corresponding annotation
        if (dosomeAnnotationPresent){
            MyAnnotationMethod dosomeAnnotation = dosome.getAnnotation(MyAnnotationMethod.class);//Get method annotation value
            System.out.println(dosome);
        }
    }


    @MyAnnotationField(10001)
    private int id;

    private String name;

    @MyAnnotationConstructor
    public AnnotationTest1(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @MyAnnotationMethod
    public void dosome(){
        System.out.println("Method called!");
    }
}

Posted by gilsontech on Tue, 23 Nov 2021 02:43:29 -0800