Java knowledge summary 1 - Java program foundation

Keywords: Java jvm JDK Eclipse

1.1 Java introduction

What is Java

Java is a programming language developed by James Gosling of SUN (acquired by Oracle) in the early 1990s. It was officially released in 1995.

Java is a cross platform language based on JVM

Programming languages are compiled and interpreted. Compiled languages such as C, C + +, source code needs to be compiled into machine code to run. Because different platforms (x86, ARM, etc.) have different instruction sets of CPU s, it is necessary to compile the corresponding machine code of each platform. Interpretive languages such as Python and Ruby do not need to be compiled. They can be loaded directly by the interpreter and run at the cost of low efficiency.

Java is between compiled and interpreted languages. Java first compiles code into bytecode, which is similar to abstract CPU instructions. Different platforms have corresponding Java virtual machines (abbreviated as JVMs). The JVMs are responsible for loading bytecodes and running them, thus realizing the effect of "compile once, run everywhere". Of course, this is for Java developers (who write java code), and for those who develop JVMs, they need to develop JVMs for each platform. The Java bytecode of the lower version can run normally on the JVM of the higher version.

Java is divided into three versions (Edition)

  • Java SE: Standard Edition (Standard Edition, including standard JVM and standard library)
  • Java EE: Enterprise Edition (based on Java SE, a large number of API s and libraries are added to facilitate the development of Web applications, databases, message services, etc.)
  • Java ME: Micro Edition (for embedded devices, there is no standard JVM and standard library, only the JVM and Library of "thin version")

That is to say, Java EE includes Java SE, and Java SE includes Java ME.

Java SE is the core of the whole Java platform. You should learn Java SE first, then Java EE. Java ME has been replaced by Android, so there's no need to learn.

Java Version

time edition
1995 1.0
1998 1.2
2000 1.3
2002 1.4
2004 1.5 / 5.0
2005 1.6 / 6.0
2011 1.7 / 7.0
2014 1.8 / 8.0
2017/9 1.9 / 9.0
2018/3 10
2018/9 11
2019/3 12
2019/9 13
2020/3 14

The relationship among JVM, JRE and JDK

  • JRE: Java Runtime Environment (Java Runtime Environment, including JVM and Library)
  • JDK: Java Development Kit (java development kit, including JRE, compiler, debugger)

That is, JDK contains JRE, and JRE contains JVM.

java source running steps: first start the compiler in JDK (the program named javac) to compile the source file (ending with the. java suffix) into a bytecode file (ending with the. class suffix), and then start the JVM (the program named java) to load the bytecode file and run it.

Install JDK

Search JDK 14 to make sure that the Oracle's official website Download the latest stable JDK:

Find the download link of JDK and download and install it.

Setting environment variables

Run a program in the command line terminal tool. If you do not enter the full Path of the program, the system will find the program in the current directory or in the directory set by the Path environment variable. Later, we will run Java compiler or virtual machine and other programs in the command-line terminal tool. These two programs are placed in the bin directory of the JDK installation directory. If you need to locate the directory or enter the full Path before running them, it is very troublesome. Therefore, you should set that directory as the environment variable:

  1. Set a Java_ The environment variable of home points to the installation directory of JDK. The setting of environment variables under Windows system is similar to the following figure:

    On Mac, it's in ~ /. Bash_ In profile or ~ /. zprofile:

    export JAVA_HOME=`/usr/libexec/java_home -v 14`
    
  2. Java_ The bin directory of home is attached to the system environment variable PATH. The settings under Windows system are as follows:

    On Mac, it's in ~ /. Bash_ In profile or ~ /. zprofile, it is as follows:

    export PATH=$JAVA_HOME/bin:$PATH
    

After the environment variables are configured, Java can be run in any folder. Open the command prompt window (press and hold the Windows+R shortcut key to pop up the running window under the Windows system, and then enter cmd and enter to open it). Enter the command java version. If everything is normal, you will see that the Java version number is output:

If the prompt is wrong, it is usually the previous JAVA_HOME and Path are misconfigured and need to be rechecked.

Program files in JDK

In the bin directory of the JDK installation directory, there are many executable files, such as:

  • java: This is actually the JVM;
  • javac: This is the compiler of Java;
  • jar: used to package a group of. class files into a. jar file for easy release;
  • javadoc: used to automatically extract comments from Java source code and generate documents;
  • jdb: Java debugger, which is used for running debugging in the development phase.

Write the first Java program

Basic structure of Java program

Java source code is essentially a text file, so you need to use a text editor. Open the text editor (Notepad + + is recommended), and enter the following code:

/**
 * Comments that can be used to automatically create documents
 */
public class Hello {
    public static void main(String[] args) {
        // Output text to screen:
        System.out.println("Hello, world!");
        /* Multiline comment start
        Note Content 
        End of comment */
    }
} // End of class definition

The above code is the basic structure of a complete Java program.

notes

In Java programs, annotation is a kind of text for people to read, not a part of the program, so the compiler will automatically ignore the annotation.

Java has three kinds of comments, the first is a single line of comments, starting with a double slash and ending at the end of the line:

//This is the comment

Multi line comments start with / * and end with * / can have multiple lines:

/*
This is the note
blablabla...
It's also a comment
*/

There is also a special multiline comment that starts with / *, and ends with * /. If there are multiple lines, each line usually begins with an asterisk:

/**
 * Comments that can be used to automatically create documents
 * 
 * @auther xxx
 */
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

This particular multiline comment needs to be written at the definition of classes and methods and can be used to automatically create documents.

class

A definition similar to the following code is called class.

public class Hello {
	...
}

Hello here is the class name, which is used to define a class. Both public and class are Java keywords, which must be lowercase. Curly bracket {} is the definition of the class.

Public is the access modifier, indicating that the class is public. You can compile correctly without writing public, but this class will not execute from the command line. Only one class of public type can be defined in a Java source file.

Naming rules for class:

  • Class names must begin with a letter followed by a combination of letters, numbers, and underscores
  • Habit of starting with capital letters

It is better to follow the naming habit, generally using Pascal nomenclature, i.e. capitalize the initial of each word:

  • Hello
  • NoteBook
  • VRPlayer
method

Within the class, you can define several method s:

	public static void main(String[] args) {
        ...
    }

Method is an executable block of code. Here, main is the method name, surrounded by () is the method "parameter". Here, the main method has a parameter, the parameter type is String [], and the parameter name is args. Public and static are used to modify methods. Public indicates that the method is public, and static indicates that the method is static. void is the return type of the method, indicating that there is no return value. In the middle of curly braces {} is the code inside the method, that is, the "statement" inside the method, which is used by each line of statements. At the end, these statements will be executed in sequence, here there is only one line of statements:

		System.out.println("Hello, world!");

It is used to print (display) the string "Hello, world!" to the screen.

Java stipulates that the public static void main(String[] args) defined by a class is the fixed entry method of Java programs, so Java programs always start from the main method.

The naming rule of method name is the same as that of class. The naming habit is lowercase (i.e. hump naming method):

  • main
  • goodMorning
  • playVR
Programming habits

Although programming habits do not affect the correctness of the program, but develop good programming habits, can make the code easy to read and maintain. You should develop the following programming habits:

  1. As mentioned above, naming rules should be used for class names and method names.

  2. Follow the coding format agreed by the Java community, such as code indentation. After using indentation, it is easy to see the beginning and end of the code block. Generally, indentation is 4 spaces or a tab.

    Generally, IDE has the function of providing code formatting. For example, eclipse provides the shortcut key Ctrl+Shift+F (MAC OS is ⌘ + ⇧ + F) to help us format the code quickly. Eclipse formats the code according to the agreed coding format. The specific code format requirements can be viewed in the Java code style in eclipse settings.

preservation

After the above code is written, it needs to be saved as a file.

The code can be saved many times during writing (the shortcut key is usually Ctrl+S). It is not necessary to save the code after all the codes are written, so as to avoid the loss of code due to software crash, power failure, crash and other problems during writing. When we save the code as a file, the file name (except for the. Java suffix) should be exactly the same as the class name we defined, so it must be Hello.java , pay attention to case.

Running Java programs

  1. Use javac to compile. java source code into. class bytecode:

    stay Hello.java Execute the command javac in the directory where the file is located Hello.java . If there is no error in the source code, there will be no output after the above command is executed, and a Hello.class Bytecode file.

  2. Run the bytecode file in java (the parameter is the class name, and the virtual machine will automatically find the corresponding class file and execute it):

    Execute the command java Hello.

The executable javac is the compiler, and the executable java is the virtual machine.

After completing the above two steps, the program starts to run. If it runs normally, you will see the output of "Hello, world!".

Using IDE

The advantage of IDE (Integrated Development Environment) is that it can write code, organize project, compile, run and debug in one environment, which can greatly improve the development efficiency.

The development efficiency of IDE mainly depends on the following points:

  • The editor's automatic prompt can greatly improve the speed of code tapping;
  • After the code is modified, it can be recompiled automatically and run directly;
  • Breakpoint debugging is easy.

Currently, common ides for Java development are:

Eclipse

Eclipse It is an IDE developed by IBM and donated to the open source community. It is also the most widely used ide at present. Eclipse is characterized by its own Java development, and based on plug-in structure, even the support for Java development is realized through plug-in JDT.

In addition to Java development, Eclipse plug-ins can also be used as C/C + + development environment, PHP development environment, and Rust development environment.

IntelliJ Idea

IntelliJ Idea It is a powerful IDE developed by JetBrains, which is divided into free version and commercial paid version. JetBrains IDE platform is also based on IDE platform + language plug-in mode, supporting Python development environment, Ruby development environment, PHP development environment, etc., which are also divided into free version and paid version.

1.2 variables

What are variables?

Variable is the algebra concept of junior high school mathematics, for example, a simple equation, x and y are variables:

y=x2+1

In Java, data is divided into basic type and reference type. Variables are used to store data. Therefore, variables are also divided into two types: basic type and reference type.

Definition and assignment of variables

Definition and initial value assignment of variables

Variables must be defined before use. When defining variables, you can assign them an initial value. For example:

int x = 1;

The above statement defines a variable of int type with the name of x and the initial value of 1. Not writing the initial value is equivalent to giving it a default value. The default value is always 0.

Take a look at a complete definition of variables, and then print an example of variable values:

public class Main {
    public static void main(String[] args) {
        int x = 100; // Define the int type variable x and give the initial value 100
        System.out.println(x); // Print the value of the variable
    }
}

Variable can be reassigned

For example, for variable x, first assign 100, then 200, and observe the results of two printing:

public class Main {
    public static void main(String[] args) {
        int x = 100; // Define the int type variable x and give the initial value 100
        System.out.println(x); // Print the value of the variable and observe whether it is 100
        x = 200; // Reassign to 200
        System.out.println(x); // Print the value of the variable and observe if it is 200
    }
}

Note that when the variable x is reassigned, the variable x already exists and cannot be defined repeatedly. Therefore, the variable type int cannot be specified. The statement x = 200; must be used;.

Variables can also be assigned to other variables

public class Main {
    public static void main(String[] args) {
        int n = 100; // Define variable n and assign it to 100 at the same time
        System.out.println("n = " + n); // Print the value of n

        n = 200; // Variable n is assigned 200
        System.out.println("n = " + n); // Print the value of n

        int x = n; // The variable x is assigned n (the value of n is 200, so the value of X after assignment is also 200)
        System.out.println("x = " + x); // Print the value of x

        x = x + 100; // Variable x is assigned as x+100 (the value of X is 200, so the value of X after assignment is 200 + 100 = 300)
        System.out.println("x = " + x); // Print the value of x
        System.out.println("n = " + n); // Print the value of N again. Should n be 200 or 300?
   }
}

We analyze the code execution process line by line:

Execute int n = 100; this statement defines the variable n and assigns a value of 100. Therefore, the JVM allocates a "storage unit" to the variable n in memory and fills in the value of 100:

      n
      │
      ▼
┌───┬───┬───┬───┬───┬───┬───┐
│   │100│   │   │   │   │   │
└───┴───┴───┴───┴───┴───┴───┘

When n = 200; is executed, the JVM writes 200 to the storage unit of variable n, so the original value is overwritten, and now the value of n is 200:

      n
      │
      ▼
┌───┬───┬───┬───┬───┬───┬───┐
│   │200│   │   │   │   │   │
└───┴───┴───┴───┴───┴───┴───┘

When int x = n; is executed, a new variable x is defined, and X is assigned at the same time. Therefore, the JVM needs to assign a new storage unit to variable x, and write the same value as variable n. as a result, the value of variable x changes to 200:

      n           x
      │           │
      ▼           ▼
┌───┬───┬───┬───┬───┬───┬───┐
│   │200│   │   │200│   │   │
└───┴───┴───┴───┴───┴───┴───┘

When x = x + 100; is executed, the JVM first calculates the value x + 100 on the right side of the equation, and the result is 300 (because the value of X at this time is 200), and then writes the result 300 to the storage unit of X, so the final value of variable x becomes 300:

      n           x
      │           │
      ▼           ▼
┌───┬───┬───┬───┬───┬───┬───┐
│   │200│   │   │300│   │   │
└───┴───┴───┴───┴───┴───┴───┘

Note that equal sign = is an assignment statement, not a mathematical equivalent, otherwise x = x + 100 cannot be interpreted.

constant

When defining a variable, if the final modifier is added, the variable becomes a constant:

final double PI = 3.14; // PI is a constant
double r = 5.0;
double area = PI * r * r;
PI = 300; // compile error!

Constants cannot be assigned again after initialization at definition time, which will lead to compilation errors.

The function of a constant is to avoid magic numbers by using meaningful variable names. For example, instead of writing 3.14 everywhere in your code, define a constant. If we need to improve the calculation accuracy in the future, we only need to modify the definition of constant, for example, to 3.1416 instead of replacing 3.14 in all places.

By convention, constant names are usually all uppercase.

var keyword

Sometimes, the type name is too long, so it's more difficult to write. For example:

StringBuilder sb = new StringBuilder();

At this time, if you want to omit variable types, you can use the var keyword:

var sb = new StringBuilder();

The compiler will automatically infer that the type of variable sb is StringBuilder according to the assignment statement. For compilers, statements:

var sb = new StringBuilder();

It actually automatically becomes:

StringBuilder sb = new StringBuilder();

Therefore, using var to define variables is only to write less variable types.

Action range of variable

In Java, multiline statements are enclosed in {}. Many control statements, such as condition judgment and loop, take {} as their own scope, for example:

if (...) { // if start
    ...
    while (...) { while start
        ...
        if (...) { // if start
            ...
        } // if end
        ...
    } // while end
    ...
} // if end

As long as these {} are nested correctly, the compiler can recognize the beginning and end of the statement block. The variables defined in the statement block have a scope from the definition to the end of the statement block. If these variables are referenced beyond the scope, the compiler will report an error. for instance:

{
    ...
    int i = 0; // Variable i is defined here
    ...
    {
        ...
        int x = 1; // Variable x is defined here
        ...
        {
            ...
            String s = "hello"; // Variable s is defined here
            ...
        } // This concludes the scope of variable s
        ...
        // Note that this is a new variable s, which has the same name as the above variable,
        // But because of the scope, they are two different variables:
        String s = "hi";
        ...
    } // This concludes the scope of variables x and s
    ...
} // This is the end of the variable i Scope

When defining variables, we should follow the principle of scope minimization, define variables in the smallest possible scope, and do not reuse variable names.

1.3 data type

Basic type (value type)

The basic data type is the type that the CPU can perform operations directly. Java defines the following basic data types:

  • Integer type (integer): byte, short, int, long
  • Floating point type: float (single precision floating point type), double (double precision floating point type)
  • Character type: char
  • boolean type: boolean

What's the difference between these basic data types defined by Java? To understand these differences, we must have a brief understanding of the basic structure of computer memory.

The minimum storage unit of computer memory is byte, a byte is an 8-bit binary number, that is, 8 bits. Its binary representation range is from 00000000 to 11111111, which is 0 to 255 in decimal system and 00 to FF in hexadecimal system.

Memory units are numbered from 0, called memory addresses. Each memory unit can be regarded as a room, and the memory address is the house number.

  0   1   2   3   4   5   6  ...
┌───┬───┬───┬───┬───┬───┬───┐
│   │   │   │   │   │   │   │...
└───┴───┴───┴───┴───┴───┴───┘

A byte is 1 byte, 1024 bytes are 1K, 1024K is 1M, 1024M is 1G, 1024G is 1T. The number of bytes of a computer with 4T memory is:

4T = 4 x 1024G
   = 4 x 1024 x 1024M
   = 4 x 1024 x 1024 x 1024K
   = 4 x 1024 x 1024 x 1024 x 1024
   = 4398046511104

Different data types use different bytes. Let's look at the number of bytes occupied by the Java basic data type:

       ┌───┐
  byte │   │
       └───┘
       ┌───┬───┐
 short │   │   │
       └───┴───┘
       ┌───┬───┬───┬───┐
   int │   │   │   │   │
       └───┴───┴───┴───┘
       ┌───┬───┬───┬───┬───┬───┬───┬───┐
  long │   │   │   │   │   │   │   │   │
       └───┴───┴───┴───┴───┴───┴───┴───┘
       ┌───┬───┬───┬───┐
 float │   │   │   │   │
       └───┴───┴───┴───┘
       ┌───┬───┬───┬───┬───┬───┬───┬───┐
double │   │   │   │   │   │   │   │   │
       └───┴───┴───┴───┴───┴───┴───┴───┘
       ┌───┬───┐
  char │   │   │
       └───┴───┘

Byte is exactly one byte, while long and double need 8 bytes.

integer

For integer types, Java only defines signed integers, so the highest bit represents the sign bit (0 for positive, 1 for negative). The maximum range of integers can be expressed as follows:

  • byte: -128 ~ 127
  • short: -32768 ~ 32767
  • int: -2147483648 ~ 2147483647
  • long: -9223372036854775808 ~ 9223372036854775807

Let's take an example of defining an integer:

public class Main {
    public static void main(String[] args) {
        int i = 2147483647;
        int i2 = -2147483648;
        int i3 = 2_000_000_000; // Underline for easier identification
        int i4 = 0xff0000; // 16711680 in hex
        int i5 = 0b1000000000; // 512 in binary representation
        long l = 9000000000000000000L; // L is required at the end of long type
    }
}

Note: the representation of different bases of the same number is exactly the same, for example, 15=0xf = 0b1111.

float

Floating point numbers are decimals. When decimal numbers are expressed by scientific counting method, the decimal point can be "floating". For example, 1234.5 can be expressed as 12.345x102 or 1.2345x103, so it is called floating point.

Here is an example of defining a floating-point number:

float f1 = 3.14f;
float f2 = 3.14e38f; // 3.14x10^38 represented by scientific counting method
double d = 1.79e308;
double d2 = -1.79e308;
double d3 = 4.9e-324; // 4.9x10^-324 expressed by scientific counting method

For float types, you need to add the f suffix.

Floating point numbers can represent a very large range, float type can represent a maximum of 3.4x1038, and double type can represent a maximum of 1.79x10308.

Boolean type

boolean has only two values: true and false. boolean is always the result of relational operation

boolean b1 = true;
boolean b2 = false;
boolean isGreater = 5 > 3; // Calculation result is true
int age = 12;
boolean isAdult = age >= 18; // The calculation result is false

Java language does not stipulate the storage of boolean type, because in theory, only 1 bit is needed to store boolean type, but usually the JVM will express Boolean as a 4-byte integer.

Character type

Character type char represents a character:

public class Main {
    public static void main(String[] args) {
        char a = 'A';
        char zh = 'in';
        System.out.println(a);
        System.out.println(zh);
    }
}

Note that values of type char are enclosed in single quotes' and have only one character, which should be distinguished from the string type of double quotes'.

Because Java always uses Unicode to represent characters in memory, an English character and a Chinese character are represented by a char type, both of which take up two bytes. To display a character's Unicode encoding, simply assign the char type directly to the int type:

int n1 = 'A'; // The Unicode code for the letter "A" is 65
int n2 = 'in'; // The Unicode code of Chinese character "Zhong" is 20013

You can also directly use escape character \ u+Unicode encoding to represent a character:

// Note hex:
char c3 = '\u0041'; // 'A' because hex 0041 = decimal 65
char c4 = '\u4e2d'; // 'medium' because hex 4e2d = decimal 20013

reference type

Store an address inside a variable of reference type

In addition to the above basic types, the rest of the data types are reference types. For example, the most common reference type is a String string.

Variable of reference type is similar to pointer of C language. It stores an address inside and points to the location of an object in memory. We will discuss the concept of class in detail later.

String type

Different from char type, String type String is reference type. We use double quotation marks "..." to represent String. A String can store 0 to any character:

String s = ""; // Empty string containing 0 characters
String s1 = "A"; // Contains one character
String s2 = "ABC"; // Contains 3 characters
String s3 = "chinese ABC"; // Contains 6 characters with a space
Escape character

Because strings use double quotation marks "..." to indicate start and end, what if the string itself contains exactly one "character? For example, "abc"xyz ", the compiler cannot determine whether the middle quotation mark is part of the string or represents the end of the string. At this time, we need to use the escape character \:

String s = "abc\"xyz"; // Contains 7 characters: a, b, c, ", x, y, z

Because \ is an escape character, two \ \, representing a \ character:

String s = "abc\\xyz"; // Contains 7 characters: a, b, c, \, x, y, z

Common escape characters include:

  • \"Represent character"
  • \'for character'
  • \Represent character\
  • \n for line break
  • \r for carriage return
  • \t for Tab
  • \u × represents a Unicode encoded character

For example:

String s = "ABC\n\u4e2d\u6587"; // Contains 6 characters: A, B, C, line feed, Chinese, text
String connection

Java compilers take special care of strings. You can use + to connect arbitrary strings and other data types, which greatly facilitates the processing of strings. For example:

public class Main {
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "world";
        String s = s1 + " " + s2 + "!";
        System.out.println(s);
    }
}

If you use + to connect strings and other data types, the other data types will be automatically converted to strings before connecting:

public class Main {
    public static void main(String[] args) {
        int age = 25;
        String s = "age is " + age;
        System.out.println(s);
    }
}
Multiline string

If we want to represent multiline strings, it is very inconvenient to use the + sign connection:

String s = "first line \n"
         + "second line \n"
         + "end";

Starting from Java 13, strings can use "..." to represent multi line strings (Text Blocks). for instance:

public class Main {
    public static void main(String[] args) {
        String s = """
                   SELECT * FROM
                     users
                   WHERE id > 100
                   ORDER BY name DESC
                   """;
        System.out.println(s);
    }
}

The above multiline string is actually 5 lines, followed by the last DESC \ n. If we don't want to add one at the end of the string, we need to write as follows:

String s = """ 
           SELECT * FROM
             users
           WHERE id > 100
           ORDER BY name DESC""";

It should also be noted that the common space before the multiline string is removed, that is:

String s = """
...........SELECT * FROM
...........  users
...........WHERE id > 100
...........ORDER BY name DESC
...........""";

The spaces marked with. Will be removed.

If the layout of multiline strings is irregular, the space removed will be as follows:

String s = """
.........  SELECT * FROM
.........    users
.........WHERE id > 100
.........  ORDER BY name DESC
.........  """;

That is, it is always based on the shortest leading space.

Finally, because multiline strings are implemented as Preview Language Features, we need to add parameters to the compiler when compiling:

javac --source 14 --enable-preview Main.java
Immutable characteristic

Java string is not only a reference type, but also an important feature, that is, the string is immutable. Review the following codes:

public class Main {
    public static void main(String[] args) {
        String s = "hello";
        System.out.println(s); // Show hello
        s = "world";
        System.out.println(s); // Show world
    }
}

Observe the execution result. Does the string s change? In fact, what changes is not the string, but the "point" of the variable s.

When executing String s = "hello", the JVM virtual machine first creates the string "hello", and then points the string variable s to it:

      s
      │
      ▼
┌───┬───────────┬───┐
│   │  "hello"  │   │
└───┴───────────┴───┘

Next, when s = world is executed, the JVM virtual machine first creates the string "world", and then points the string variable s to it:

      s ──────────────┐
                      │
                      ▼
┌───┬───────────┬───┬───────────┬───┐
│   │  "hello"  │   │  "world"  │   │
└───┴───────────┴───┴───────────┴───┘

The original string "hello" is still there, but we can't access it through the variable s. Therefore, immutability of string means that the content of string is immutable.

char is the basic type, String is the reference type, the variable of the basic type is hold a value, and the variable of the reference type is point to an object.

null

A variable of reference type can point to a null value, which means it does not exist, that is, it does not point to any object. For example:

String s1 = null; // s1 is null
String s2; // No initial value assigned, s2 is also null
String s3 = s1; // s3 is also null
String s4 = ""; // s4 points to an empty string, not null

Note that to distinguish between null and empty string '', empty string is a valid string object, which is not equal to null.

Array type

An array is a collection of the same data type, and the array itself is a reference type.

Definition and assignment of array variables

If we have a set of variables of the same type, for example, the scores of five students, we can write as follows:

public class Main {
    public static void main(String[] args) {
        // Results of 5 students:
        int n1 = 68;
        int n2 = 79;
        int n3 = 91;
        int n4 = 85;
        int n5 = 62;
    }
}

But there is no need to define five int variables. You can use arrays to represent a set of int types. The code is as follows:

public class Main {
    public static void main(String[] args) {
        // Results of 5 students:
        int[] ns = new int[5];
        ns[0] = 68;
        ns[1] = 79;
        ns[2] = 91;
        ns[3] = 85;
        ns[4] = 62;
    }
}

Define a variable of array type, using array type [], for example, int []. Unlike a single basic type variable, array variable initialization must use the new int[5] representation to create an array that can hold five int elements.

You can also directly specify the initialized elements when defining an array, so that you do not have to write out the array size, but the compiler automatically calculates the array size. For example:

public class Main {
    public static void main(String[] args) {
        // Results of 5 students:
        int[] ns = new int[] { 68, 79, 91, 85, 62 };
        System.out.println(ns.length); // The compiler automatically calculates the array size as 5
    }
}

It can also be further simplified as:

int[] ns = { 68, 79, 91, 85, 62 };

Arrays have several characteristics:

  • All elements of the array are initialized to the default value, the integer type is 0, the floating-point type is 0.0, and the boolean type is false;
  • Once an array is created, its size cannot be changed.
Accessing array elements

To access an element in an array, you need to use an index. The array index starts from 0, for example, an array of 5 elements, with an index range of 0-4. Array is a reference type. When using index to access array elements, if the index is out of range, an error will be reported at runtime:

public class Main {
    public static void main(String[] args) {
        // Results of 5 students:
        int[] ns = new int[5];
        int n = 5;
        System.out.println(ns[n]); // Index n cannot be out of range
    }
}

You can modify an element in an array and use an assignment statement, for example, ns[1] = 79;.

Get array size

You can use the array variable. length to get the array size:

public class Main {
    public static void main(String[] args) {
        // Results of 5 students:
        int[] ns = new int[5];
        System.out.println(ns.length); // 5
    }
}
Array size is immutable

Note that the array is of reference type and the array size is immutable. Let's look at the following code:

public class Main {
    public static void main(String[] args) {
        // Results of 5 students:
        int[] ns;
        ns = new int[] { 68, 79, 91, 85, 62 };
        System.out.println(ns.length); // 5
        ns = new int[] { 1, 2, 3 };
        System.out.println(ns.length); // 3
    }
}

Has the array size changed? It looks like it has changed, but it hasn't changed at all.

For array ns, when ns = New Int [] {68, 79, 91, 85, 62}; is executed, it points to an array of five elements:

     ns
      │
      ▼
┌───┬───┬───┬───┬───┬───┬───┐
│   │68 │79 │91 │85 │62 │   │
└───┴───┴───┴───┴───┴───┴───┘

When ns = New Int [] {1, 2, 3}; is executed, it points to an array of three new elements:

     ns ──────────────────────┐
                              │
                              ▼
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│   │68 │79 │91 │85 │62 │   │ 1 │ 2 │ 3 │   │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘

However, the original array of 5 elements has not changed, just can not be referred to them through the variable ns.

String array

If an array element is not a basic type, but a reference type, what are the differences between modifying an array element?

String is a reference type, so we define a string array first:

String[] names = {
    "ABC", "XYZ", "zoo"
};

For array variable names of type String [], it actually contains three elements, but each element points to a String object:

          ┌─────────────────────────┐
    names │   ┌─────────────────────┼───────────┐
      │   │   │                     │           │
      ▼   │   │                     ▼           ▼
┌───┬───┬─┴─┬─┴─┬───┬───────┬───┬───────┬───┬───────┬───┐
│   │░░░│░░░│░░░│   │ "ABC" │   │ "XYZ" │   │ "zoo" │   │
└───┴─┬─┴───┴───┴───┴───────┴───┴───────┴───┴───────┴───┘
      │                 ▲
      └─────────────────┘

Assign a value to names[1], for example, names[1] = "cat"; the effect is as follows:

          ┌─────────────────────────────────────────────────┐
    names │   ┌─────────────────────────────────┐           │
      │   │   │                                 │           │
      ▼   │   │                                 ▼           ▼
┌───┬───┬─┴─┬─┴─┬───┬───────┬───┬───────┬───┬───────┬───┬───────┬───┐
│   │░░░│░░░│░░░│   │ "ABC" │   │ "XYZ" │   │ "zoo" │   │ "cat" │   │
└───┴─┬─┴───┴───┴───┴───────┴───┴───────┴───┴───────┴───┴───────┴───┘
      │                 ▲
      └─────────────────┘

It is noted that the original name [1] pointed to the string "XYZ" has not changed, only the reference to the name [1] has been changed from pointing to "XYZ" to pointing to "cat", and the result is that the string "XYZ" can no longer be accessed through the name [1].

1.4 operation

Integer operation

add , subtract , multiply and divide

Integer operation follows four operation rules, and any nested parentheses can be used. The four operation rules are consistent with elementary mathematics. For example:

public class Main {
    public static void main(String[] args) {
        int i = (100 + 200) * (99 - 88); // 3300
        int n = 7 * (5 + (i - 9)); // 23072
        System.out.println(i);
        System.out.println(n);
    }
}

Note that the division of two integers can only get the integer part of the result:

int x = 12345 / 67; // 184
Find Yu Yunsuan

% is used for co operation:

int y = 12345 % 67; // The remainder of 12345 ÷ 67 is 17

Special note: integer division will report an error when the divisor is 0, but the compiler will not report an error.

Abbreviated operator

They are + =, - =, * =, / =, and are used as follows:

n += 100; // 3409, equivalent to n = n + 100;
n -= 100; // 3309, equivalent to n = n - 100;
Auto increase / Auto decrease

Java also provides + + operations and -- operations, which can add and subtract 1 to an integer:

public class Main {
    public static void main(String[] args) {
        int n = 3300;
        n++; // 3301, equivalent to n = n + 1;
        n--; // 3300, equivalent to n = n - 1;
        int y = 100 + (++n); // Don't write like that
        System.out.println(y);
    }
}

Note that the calculation results written before and after + + are different, + + n means adding 1 first and then referring to N, and N + + means adding n first and then referring to 1. It's not recommended to mix + + operation with conventional operation, so it's easy to confuse yourself.

overflow

In particular, due to the range limitation of integers, if the calculation result exceeds the range, an overflow will be generated, and the overflow will not be wrong, but it will get a strange result:

public class Main {
    public static void main(String[] args) {
        int x = 2147483640;
        int y = 15;
        int sum = x + y;
        System.out.println(sum); // -2147483641
    }
}

To explain the above results, we change the integers 2147483640 and 15 to binary to add:

  0111 1111 1111 1111 1111 1111 1111 1000
+ 0000 0000 0000 0000 0000 0000 0000 1111
-----------------------------------------
  1000 0000 0000 0000 0000 0000 0000 0111

Since the highest order result is 1, the addition result becomes a negative number.

To solve the above problem, you can change int to long type. Because long can represent a wider range of integers, the result will not overflow:

long x = 2147483640;
long y = 15;
long sum = x + y;
System.out.println(sum); // 2147483655

Shift operation

In a computer, integers are always represented in binary form. For example, an int type integer 7 has a 4-byte binary as follows:

00000000 0000000 0000000 00000111

You can shift integers. Moving 1 bit to the left of integer 7 will result in integer 14, and moving 2 bits to the left will result in integer 28:

int n = 7;       // 00000000 00000000 00000000 00000111 = 7
int a = n << 1;  // 00000000 00000000 00000000 00001110 = 14
int b = n << 2;  // 00000000 00000000 00000000 00011100 = 28
int c = n << 28; // 01110000 00000000 00000000 00000000 = 1879048192
int d = n << 29; // 11100000 00000000 00000000 00000000 = -536870912

When you move 29 bits to the left, because the highest bit becomes 1, the result becomes a negative number.

Similarly, the integer 28 is shifted to the right as follows:

int n = 7;       // 00000000 00000000 00000000 00000111 = 7
int a = n >> 1;  // 00000000 00000000 00000000 00000011 = 3
int b = n >> 2;  // 00000000 00000000 00000000 00000001 = 1
int c = n >> 3;  // 00000000 00000000 00000000 00000000 = 0

If you move a negative number to the right and the highest 1 does not move, the result is still a negative number:

int n = -536870912;
int a = n >> 1;  // 11110000 00000000 00000000 00000000 = -268435456
int b = n >> 2;  // 11111000 00000000 00000000 00000000 = -134217728
int c = n >> 28; // 11111111 11111111 11111111 11111110 = -2
int d = n >> 29; // 11111111 11111111 11111111 11111111 = -1

There is also an unsigned right shift operation, which uses > >, which is characterized by the following of sign bits. Therefore, when a negative number is moved to the right, it will become a positive number, because the highest 1 becomes a 0:

int n = -536870912;
int a = n >>> 1;  // 01110000 00000000 00000000 00000000 = 1879048192
int b = n >>> 2;  // 00111000 00000000 00000000 00000000 = 939524096
int c = n >>> 29; // 00000000 00000000 00000000 00000111 = 7
int d = n >>> 31; // 00000000 00000000 00000000 00000001 = 1

When you shift byte and short types, they are first converted to int and then shifted.

Through careful observation, it can be found that the left shift is actually constant × 2, and the right shift is actually constant ÷ 2.

Bitwise operation

Bitwise operation is the operation of and, or, non and exclusive or by bit.

The rule of and operation is that two numbers must be 1 at the same time, and the result is 1:

n = 0 & 0; // 0
n = 0 & 1; // 0
n = 1 & 0; // 0
n = 1 & 1; // 1

The rule of or operation is that as long as any one is 1, the result is 1:

n = 0 | 0; // 0
n = 0 | 1; // 1
n = 1 | 0; // 1
n = 1 | 1; // 1

The rule of non operation is that 0 and 1 are interchanged:

n = ~0; // 1
n = ~1; // 0

The rule of exclusive or operation is that if two numbers are different, the result is 1, otherwise 0:

n = 0 ^ 0; // 0
n = 0 ^ 1; // 1
n = 1 ^ 0; // 1
n = 1 ^ 1; // 0

To do bit operations on two integers is actually to align them bit by bit, and then operate on each bit in turn. For example:

public class Main {
    public static void main(String[] args) {
        int i = 167776589; // 00001010 00000000 00010001 01001101
        int n = 167776512; // 00001010 00000000 00010001 00000000
        System.out.println(i & n); // 167776512
    }
}

The above bitwise and operation can actually be regarded as IP addresses 10.0.17.77 and 10.0.17.0 represented by two integers. Through and operation, it can quickly determine whether an IP is in a given network segment.

Operation priority

In Java's calculation expression, the order of operation priority from high to low is:

  • ()
  • ! ~ ++ --
  • * / %
  • + -
  • << >> >>>
  • &
  • |
  • += -= *= /=

It doesn't matter if you can't remember it. You only need to add parentheses to ensure that the priority of the operation is correct.

Type automatic promotion and forced transformation

In the process of operation, if the two types of numbers involved in the operation are not the same, the calculation result is an integer of larger type. For example, for short and int calculations, the result is always int, because short is first automatically converted to int:

public class Main {
    public static void main(String[] args) {
        short s = 1234;
        int i = 123456;
        int x = s + i; // s Auto transform to int
        short y = s + i; // Compilation error!
    }
}

The result can also be forced to transform, that is, a large range of integers into a small range of integers. Force transformation uses (type), for example, to force int transformation to short:

int i = 12345;
short s = (short) i; // 12345

It should be noted that the forced transformation beyond the scope will get the wrong result, because during the transformation, the two high-order bytes of int are directly thrown away, and only the two low-order bytes are retained:

public class Main {
    public static void main(String[] args) {
        int i1 = 1234567;
        short s1 = (short) i1; // -10617
        System.out.println(s1);
        int i2 = 12345678;
        short s2 = (short) i2; // 24910
        System.out.println(s2);
    }
}

You should choose an appropriate range of integers (int or long), and there is no need to use byte and short for integer operations to save memory.

Floating point operation

Only addition, subtraction, multiplication and division can be performed

Compared with integer operation, floating-point operation can only add, subtract, multiply and divide these numerical calculations, but not do bit operation and shift operation.

The integer operation will report an error when the divisor is 0, while the floating-point operation will not report an error when the divisor is 0, but will return several special values:

  • NaN means Not a Number
  • Infinity means infinity
  • -Infinity means negative infinity

For example:

double d1 = 0.0 / 0; // NaN
double d2 = 1.0 / 0; // Infinity
double d3 = -1.0 / 0; // -Infinity

These three special values are rarely encountered in the actual operation, we only need to understand them.

Floating point number cannot be expressed accurately

In the computer, although floating-point numbers represent a wide range, floating-point numbers have a very important feature, that is, floating-point numbers are often not accurately represented.

Here's a chestnut:

Floating point number 0.1 can't be expressed precisely in the computer, because the conversion of decimal 0.1 to binary is an infinite cyclic decimal. Obviously, no matter using float or double, only one approximate value of 0.1 can be stored. However, the floating-point number 0.5 can be expressed accurately.

Because floating-point numbers are often not accurately represented, floating-point operations can produce errors:

public class Main {
    public static void main(String[] args) {
        double x = 1.0 / 10;
        double y = 1 - 9.0 / 10;
        // x and y are not equal:
        System.out.println(x);
        System.out.println(y);
    }
}

Because of the operation error of floating-point numbers, it is often wrong to compare whether two floating-point numbers are equal. The correct comparison method is to determine whether the absolute value of the difference between two floating-point numbers is less than a very small number:

// To compare whether x and y are equal, first calculate the absolute value of the difference:
double r = Math.abs(x - y);
// Then judge whether the absolute value is small enough:
if (r < 0.00001) {
    // Can be considered equal
} else {
    // Unequal
}

The representation of floating-point numbers in memory is more complex than integer ratio. Java's floating point numbers are completely compliant IEEE-754 Standard, which is also supported by most computer platforms.

Type promotion

If one of the two numbers involved in the operation is an integer, the integer can be automatically promoted to a floating-point type:

public class Main {
    public static void main(String[] args) {
        int n = 5;
        double d = 1.2 + 24.0 / n; // 6.0
        System.out.println(d);
    }
}

It should be noted that in a complex four operation, the operation of two integers will not be promoted automatically. For example:

double d = 1.2 + 24 / 5; // 5.2

The result is 5.2, because when the compiler calculates the sub expression 24 / 5, it operates on two integers, and the result is still the integer 4.

Forced transformation

You can cast floating-point numbers to integers. In the transformation, the decimal part of floating-point number will be lost. If the maximum range that an integer can represent is exceeded after transformation, the maximum value of the integer will be returned. For example:

int n1 = (int) 12.3; // 12
int n2 = (int) 12.7; // 12
int n2 = (int) -12.7; // -12
int n3 = (int) (12.7 + 0.5); // 13
int n4 = (int) 1.2e20; // 2147483647

Boolean operation

For boolean type Booleans, there are always only two values, true and false.

Relational operators

Boolean operation is a relational operation, which includes the following categories:

  • Comparison operators: >=
  • And operator&&
  • Or operator||
  • Non operator!

Here are some examples:

boolean isGreater = 5 > 3; // true
int age = 12;
boolean isZero = age == 0; // false
boolean isNonZero = !isZero; // true
boolean isAdult = age >= 18; // false
boolean isTeenager = age >6 && age <18; // true

The order of precedence for relational operators is:

  • !
  • >,>=,<,<=
  • ==,!=
  • &&
  • ||

Short circuit operation

An important feature of Boolean operation is "short circuit operation". If the expression of a Boolean operation can determine the result in advance, the subsequent calculation will not be executed and the result will be returned directly. And operations, or operations, ternary operations are short-circuit operations.

Since the result of false & & X is always false, no matter whether x is true or false, the and operation will return false directly after the first value is determined to be false.

Example:

public class Main {
    public static void main(String[] args) {
        boolean b = 5 < 3;
        boolean result = b && (5 / 0 > 0);
        System.out.println(result);
    }
}

If there is no short circuit operation, & & the following expression will report an error because the divisor is 0, but in fact, the statement does not report an error, because the operation is short circuit operation and the result is false in advance.

If the value of variable b is true, the expression becomes true & & (5 / 0 > 0). Because the short-circuit operation cannot be performed, the expression must report an error due to the divisor of 0, which can be tested by itself.

Similarly, for a |, as long as the first value can be determined to be true, subsequent calculations will not be performed, but will directly return true:

boolean result = true || (5 / 0 > 0); // true

Ternary operator

Ternary operation b? X: y will first calculate b, if b is true, only x will be calculated, otherwise, only y will be calculated, so ternary operation is also a short-circuit operation. In addition, X and y must be of the same type, because the return value is not a boolean, but one of X and y.

Example:

public class Main {
    public static void main(String[] args) {
        int n = -100;
        int x = n >= 0 ? n : -n;
        System.out.println(x);
    }
}

The meaning of the above statement is to determine whether n > = 0 is tenable. If it is true, then n is returned, otherwise - n is returned. This is actually an expression for absolute values.

1.5 input and output on the command line

output

println() and print()

In the previous code, we always used System.out.println() to output something to the screen.

println is the abbreviation of print line, which means output and line feed. Therefore, if you don't want to wrap lines after output, you can use print():

public class Main {
    public static void main(String[] args) {
        System.out.print("A,");
        System.out.print("B,");
        System.out.print("C.");
        System.out.println();
        System.out.println("END");
    }
}

printf()

Java also provides the ability to format output. Why format the output? Because the data represented by the computer is not necessarily suitable for people to read:

public class Main {
    public static void main(String[] args) {
        double d = 12900000;
        System.out.println(d); // 1.29E7
    }
}

If we want to display the data in the desired format, we need to use the format output function. Format output use System.out.printf(), by using the placeholder%?, printf() can format the following parameters into the specified format:

public class Main {
    public static void main(String[] args) {
        double d = 3.1415926;
        System.out.printf("%.2f\n", d); // Display two decimal places 3.14
        System.out.printf("%.4f\n", d); // Display 4 decimal places 3.1416
    }
}

The format function of Java provides a variety of placeholders, which can "format" various data types into specified strings:

placeholder explain
%d Format output integer
%x Format output hexadecimal integer
%f Format output floating point number
%e Format the floating point number represented by the output scientific notation
%s format string

Note that since% represents a placeholder, two consecutive% s,%, represent a% character itself.

Placeholders themselves can also have more detailed formatting parameters. The following example formats an integer into hexadecimal and complements 8 bits with 0:

public class Main {
    public static void main(String[] args) {
        int n = 12345000;
        // Output n=12345000, hex=00bc5ea8
        System.out.printf("n=%d, hex=%08x", n, n); // Note that two% placeholders must pass in two numbers
    }
}

Please refer to the JDK documentation for detailed formatting parameters java.util.Formatter

input

Java's input is much more complex than its output.

Let's start with an example of reading a string and an integer from the console:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // Create Scanner object
        System.out.print("Input your name: "); // Printing tips
        String name = scanner.nextLine(); // Read a line of input and get a string
        System.out.print("Input your age: "); // Printing tips
        int age = scanner.nextInt(); // Read a line of input and get an integer
        System.out.printf("Hi, %s, you are %d\n", name, age); // Format output
    }
}

First, we import through the import statement java.util.Scanner Import is a statement to import a class. It must be placed at the beginning of Java source code. Later, we will explain how to use import in detail in java package.

Then, create the Scanner object and pass in the System.in . System.out Represents the standard output stream, and System.in Represents the standard input stream. Direct use System.in Although it is possible to read user input, more complex code is required, and subsequent code can be simplified through Scanner.

With the scanner object, to read the string entered by the user, use the scanner.nextLine(), to read the integer entered by the user, use the scanner.nextInt(). Scanner automatically converts data types, so you don't have to convert them manually.

Execution result of the above code:

Input your name: Bob
Input your age: 12
Hi, Bob, you are 12

After inputting a string and an integer respectively according to the prompts, we get the formatted output.

1.6 process control

In Java programs, the JVM always executes statements ending in semicolons; sequentially by default. However, in the actual code, the program often needs to make condition judgment and circulation. Therefore, a variety of process control statements are needed to realize the function of jump and circulation of the program.

if judgment

In Java programs, if you want to decide whether to execute a piece of code according to the conditions, you need the if statement.

grammar

Basic grammar

The basic syntax of the if statement is:

if (condition){
    //Execute when conditions are met
}

Depending on whether the if evaluates (true or false), the JVM decides whether to execute the if statement block (that is, all statements contained in curly braces {}).

Let's take an example:

public class Main {
    public static void main(String[] args) {
        int n = 70;
        if (n >= 60) {
            System.out.println("Passed");
        }
        System.out.println("END");
    }
}

When the condition n > = 60 evaluates to true, the if statement block is executed and "passed" will be printed, otherwise, the if statement block will be skipped. Modify the value of n to see the execution effect.

Note that if statements contain blocks that can contain multiple statements:

public class Main {
    public static void main(String[] args) {
        int n = 70;
        if (n >= 60) {
            System.out.println("Passed");
            System.out.println("congratulations");
        }
        System.out.println("END");
    }
}
Omitting curly braces {} is not recommended

When the if statement block has only one line of statements, curly braces {} can be omitted:

public class Main {
    public static void main(String[] args) {
        int n = 70;
        if (n >= 60)
            System.out.println("Passed");
        System.out.println("END");
    }
}

However, omitting curly braces is not always a good idea. Suppose that at some time, when you suddenly want to add a statement to the if statement block:

public class Main {
    public static void main(String[] args) {
        int n = 50;
        if (n >= 60)
            System.out.println("Passed");
            System.out.println("congratulations"); // Note that this statement is not part of the if statement block
        System.out.println("END");
    }
}

Because of the use of indentation format, it is easy to regard both lines of statements as the execution block of if statements, but in fact, only the first line of statements is the execution block of if statements. It's easier to have problems when using git, which is a version control system that automatically merges, so it's not recommended to ignore the curly bracket.

else

if statement can also write an else {...}. When the condition is false, the statement block of else will be executed:

public class Main {
    public static void main(String[] args) {
        int n = 70;
        if (n >= 60) {
            System.out.println("Passed");
        } else {
            System.out.println("I'm not a student");
        }
        System.out.println("END");
    }
}

Note that else is not required.

You can also use multiple if... Else if... In series. For example:

public class Main {
    public static void main(String[] args) {
        int n = 70;
        if (n >= 90) {
            System.out.println("excellent");
        } else if (n >= 60) {
            System.out.println("Passed");
        } else {
            System.out.println("I'm not a student");
        }
        System.out.println("END");
    }
}

The effect of series connection is equivalent to:

if (n >= 90) {
    // N > = 90 is true:
    System.out.println("excellent");
} else {
    // N > = 90 is false:
    if (n >= 60) {
        // N > = 60 is true:
        System.out.println("Passed");
    } else {
        // N > = 60 is false:
        System.out.println("I'm not a student");
    }
}

When using multiple if in series, pay special attention to the judgment order. Look at the following code:

public class Main {
    public static void main(String[] args) {
        int n = 100;
        if (n >= 60) {
            System.out.println("Passed");
        } else if (n >= 90) {
            System.out.println("excellent");
        } else {
            System.out.println("I'm not a student");
        }
    }
}

It is found that when n = 100, the condition n > = 90 is met, but the output is not "excellent", but "passed". The reason is that when the if statement is executed from top to bottom, first judge that n > = 60 is successful, then else will no longer execute. Therefore, if (n > = 90) has no chance to execute.

The correct way is to judge according to the range from large to small:

// From big to small:
if (n >= 90) {
    // ...
} else if (n >= 60) {
    // ...
} else {
    // ...
}

Or rewrite it to judge from small to large:

// From small to large:
if (n < 60) {
    // ...
} else if (n < 90) {
    // ...
} else {
    // ...
}

boundary condition

When using if, pay special attention to the boundary conditions. For example:

public class Main {
    public static void main(String[] args) {
        int n = 90;
        if (n > 90) {
            System.out.println("excellent");
        } else if (n >= 60) {
            System.out.println("Passed");
        } else {
            System.out.println("I'm not a student");
        }
    }
}

Assuming that we expect 90 points or higher to be "excellent", the above code outputs "pass", because the effect of > and > = is different.

As mentioned above, floating-point numbers are often not accurately represented in computers, and there may be errors in calculation. Therefore, it is not reliable to use = = to judge the equality of floating-point numbers

public class Main {
    public static void main(String[] args) {
        double x = 1 - 9.0 / 10;
        if (x == 0.1) {
            System.out.println("x is 0.1");
        } else {
            System.out.println("x is NOT 0.1");
        }
    }
}

The correct method is to use the difference value less than a certain critical value to judge:

public class Main {
    public static void main(String[] args) {
        double x = 1 - 9.0 / 10;
        if (Math.abs(x - 0.1) < 0.00001) {
            System.out.println("x is 0.1");
        } else {
            System.out.println("x is NOT 0.1");
        }
    }
}

Judge that the reference types are equal

In Java, the = = operator can be used to determine whether the variables of value type are equal. However, to determine whether the variables of reference type are equal, = = indicates whether the reference is equal, or whether it points to the same object. For example, the contents of the following two String types are the same, but they point to different objects respectively. Judge with = = and the result is false:

public class Main {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "HELLO".toLowerCase();
        System.out.println(s1);
        System.out.println(s2);
        if (s1 == s2) {
            System.out.println("s1 == s2");
        } else {
            System.out.println("s1 != s2");
        }
    }
}

To determine whether the variable contents of a reference type are equal, you must use the equals() method:

public class Main {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "HELLO".toLowerCase();
        System.out.println(s1);
        System.out.println(s2);
        if (s1.equals(s2)) {
            System.out.println("s1 equals s2");
        } else {
            System.out.println("s1 not equals s2");
        }
    }
}

Note: when executing statement s1.equals(s2), if variable S1 is null, NullPointerException will be reported:

public class Main {
    public static void main(String[] args) {
        String s1 = null;
        if (s1.equals("hello")) {
            System.out.println("hello");
        }
    }
}

To avoid NullPointerException errors, use the short circuit operator & &:

public class Main {
    public static void main(String[] args) {
        String s1 = null;
        if (s1 != null && s1.equals("hello")) {
            System.out.println("hello");
        }
    }
}

You can also put the object "hello" which must not be null in front of you: for example: if ("hello".equals(s)) {...}.

switch multiple choice

In addition to the if statement, there is also a conditional judgment that performs different branches according to the result of an expression.

For example, in the game, let the user choose an option:

  1. single mode
  2. Multiplayer mode
  3. Quit the game

At this point, the switch statement comes in handy.

grammar

Basic grammar

The switch statement jumps to the matching case result according to the result calculated by the switch (expression), and then continues to execute the subsequent statement until the break is encountered.

Let's take an example:

public class Main {
    public static void main(String[] args) {
        int option = 1;
        switch (option) {
        case 1:
            System.out.println("Selected 1");
            break;
        case 2:
            System.out.println("Selected 2");
            break;
        case 3:
            System.out.println("Selected 3");
            break;
        }
    }
}

If the value of option does not match any case, such as option = 99, then the switch statement does not execute any statements. In this case, you can add a default to the switch statement. When no case is matched, execute default:

public class Main {
    public static void main(String[] args) {
        int option = 99;
        switch (option) {
        case 1:
            System.out.println("Selected 1");
            break;
        case 2:
            System.out.println("Selected 2");
            break;
        case 3:
            System.out.println("Selected 3");
            break;
        default:
            System.out.println("Not selected");
            break;
        }
    }
}

if the switch statement is translated into an if statement, the above code is equivalent to:

if (option == 1) {
    System.out.println("Selected 1");
} else if (option == 2) {
    System.out.println("Selected 2");
} else if (option == 3) {
    System.out.println("Selected 3");
} else {
    System.out.println("Not selected");
}

For multiple = = judgments, the switch structure is more clear. At the same time, note that the above "translation" can only correspond to each case if the break statement is correctly written in the switch statement.

Penetration effect

When using switch, note that the case statement does not have curly braces {}, and that the case statement has "penetrability". Omission of break will lead to unexpected results:

public class Main {
    public static void main(String[] args) {
        int option = 2;
        switch (option) {
        case 1:
            System.out.println("Selected 1");
        case 2:
            System.out.println("Selected 2");
        case 3:
            System.out.println("Selected 3");
        default:
            System.out.println("Not selected");
        }
    }
}

When option = 2, "Selected 2", "Selected 3" and "Not selected" will be output in turn, because from matching to case 2, all subsequent statements will be executed until the break statement is encountered. So don't forget to write break at any time.

If several case statements execute the same set of statement blocks, you can write as follows:

public class Main {
    public static void main(String[] args) {
        int option = 2;
        switch (option) {
        case 1:
            System.out.println("Selected 1");
            break;
        case 2:
        case 3:
            System.out.println("Selected 2, 3");
            break;
        default:
            System.out.println("Not selected");
            break;
        }
    }
}

When using the switch statement, as long as the break is guaranteed, the order of case does not affect the program logic:

switch (option) {
case 3:
    ...
    break;
case 2:
    ...
    break;
case 1:
    ...
    break;
}

However, it is still recommended to arrange them in natural order for easy reading.

When matching strings, compare "content is equal"

The switch statement can also match strings. When a string matches, it compares "content is equal.". For example:

public class Main {
    public static void main(String[] args) {
        String fruit = "apple";
        switch (fruit) {
        case "apple":
            System.out.println("Selected apple");
            break;
        case "pear":
            System.out.println("Selected pear");
            break;
        case "mango":
            System.out.println("Selected mango");
            break;
        default:
            System.out.println("No fruit selected");
            break;
        }
    }
}

The switch statement can also use enumeration types, which we will explain later.

Compile check

When using IDE, you can automatically check whether the break statement and default statement are missing, by opening the IDE compilation check.

In Eclipse, select Preferences - Java - Compiler - Errors/Warnings - Potential programming problems, and mark the following checks as Warning:

  • 'switch' is missing 'default' case
  • 'switch' case fall-through

In Idea, select Preferences - Editor - Inspections - Java - Control flow issues, and mark the following checks as Warning:

  • Fallthrough in 'switch' statement
  • 'switch' statement without 'default' branch

When there is a problem with the switch statement, you can get a warning prompt in the IDE.

switch expression

No need for break statement, no penetration effect

When using switch, if break is missed, it will cause serious logical errors, and it is not easy to find errors in the source code. From Java 12, the switch statement has been upgraded to a more concise expression syntax, using a method similar to Pattern Matching to ensure that only one path will be executed, and no break statement is required:

public class Main {
    public static void main(String[] args) {
        String fruit = "apple";
        switch (fruit) {
        case "apple" -> System.out.println("Selected apple");
        case "pear" -> System.out.println("Selected pear");
        case "mango" -> {
            System.out.println("Selected mango");
            System.out.println("Good choice!");
        }
        default -> System.out.println("No fruit selected");
        }
    }
}

Note that the new syntax uses - > and if there are multiple statements, they need to be enclosed with {}. Because the new syntax only executes matching statements, there is no penetration effect.

Return value

In many cases, we may also use the switch statement to assign a value to a variable. For example:

int opt;
switch (fruit) {
case "apple":
    opt = 1;
    break;
case "pear":
case "mango":
    opt = 2;
    break;
default:
    opt = 0;
    break;
}

With the new switch syntax, you can also return values directly. Rewrite the above code as follows:

public class Main {
    public static void main(String[] args) {
        String fruit = "apple";
        int opt = switch (fruit) {
            case "apple" -> 1;
            case "pear", "mango" -> 2;
            default -> 0;
        }; // Note that the assignment statement ends with
        System.out.println("opt = " + opt);
    }
}

This gives you cleaner code.

yield

Most of the time, inside the switch expression, we return a simple value.

However, if complex statements are needed, we can also write many statements, put them in {...}, and then use yield to return a value as the return value of the switch statement:

public class Main {
    public static void main(String[] args) {
        String fruit = "orange";
        int opt = switch (fruit) {
            case "apple" -> 1;
            case "pear", "mango" -> 2;
            default -> {
                int code = fruit.hashCode();
                yield code; // switch statement return value
            }
        };
        System.out.println("opt = " + opt);
    }
}

while loop

Circular statement is to let the computer do circular calculation according to the conditions, continue the cycle when the conditions are met, and exit the cycle when the conditions are not met.

For example, calculate the sum from 1 to 100:

1 + 2 + 3 + 4 + ... + 100 = ?

In addition to using the sequence formula, the computer can do 100 cycles of accumulation. Because the characteristic of the computer is that the calculation speed is very fast, we let the computer cycle 100 million times, and it takes less than 1 second, so many calculation tasks can not be calculated by people, but the computer calculation, using the simple and crude method of cycle, can quickly get the results.

grammar

Let's first look at the while condition loop provided by Java. Its basic usage is:

while (conditional expression){
    Loop statement
}
//Continue with subsequent code

Before the start of each cycle, the while loop first determines whether the condition is true. If the result is true, execute the statement inside the loop once. If the result is false, skip to the end of the while loop and continue to execute.

We use the while loop to accumulate 1 to 100, which can be written as follows:

public class Main {
    public static void main(String[] args) {
        int sum = 0; // Cumulative sum, initialized to 0
        int n = 1;
        while (n <= 100) { // Cycle condition is n < = 100
            sum = sum + n; // Add n to sum
            n ++; // n self plus 1
        }
        System.out.println(sum); // 5050
    }
}

It is noted that the while cycle is to judge the cycle conditions first and recycle them. Therefore, it is possible to not do one cycle at a time.

boundary condition

Special attention should be paid to the boundary conditions for the judgment of cyclic conditions and the treatment of self increasing variables. Think about why the following code didn't get the right result:

public class Main {
    public static void main(String[] args) {
        int sum = 0;
        int n = 0;
        while (n <= 100) {
            n ++;
            sum = sum + n;
        }
        System.out.println(sum);
    }
}
Dead cycle

If the cycle condition is always satisfied, the cycle becomes a dead cycle. The dead cycle will lead to 100% CPU usage, and users will feel that the computer is running slowly, so it is necessary to avoid writing dead cycle code.

Logic error of loop condition

If the logic of the loop condition is written in a wrong way, unexpected results will be generated:

public class Main {
    public static void main(String[] args) {
        int sum = 0;
        int n = 1;
        while (n > 0) {
            sum = sum + n;
            n ++;
        }
        System.out.println(n); // -2147483648
        System.out.println(sum);
    }
}

On the surface, the above while loop is a dead loop. However, the int type of Java has a maximum value. When the maximum value is reached, adding 1 will become a negative number. As a result, the while loop exits unexpectedly.

do while loop

In Java, the while loop is to determine the loop condition first and then execute the loop. The other do while loop is to execute the loop first, and then judge the conditions. When the conditions are met, the loop continues, and when the conditions are not met, the loop exits. Its usage is:

do {
    Execute loop statement
 }while (conditional expression);

As you can see, the do while loop will loop at least once.

Let's rewrite the sum of 1 to 100 with do while loop:

public class Main {
    public static void main(String[] args) {
        int sum = 0;
        int n = 1;
        do {
            sum = sum + n;
            n ++;
        } while (n <= 100);
        System.out.println(sum);
    }
}

for loop

In addition to the while and do while loops, Java is most widely used for loops.

grammar

Basic grammar

The for loop is very powerful, it uses counters to implement the loop. The for loop initializes the counter first, then detects the loop condition before each loop, and updates the counter after each loop. The counter variable is usually named i.

Let's rewrite the sum of 1 to 100 with a for loop:

public class Main {
    public static void main(String[] args) {
        int sum = 0;
        for (int i=1; i<=100; i++) {
            sum = sum + i;
        }
        System.out.println(sum);
    }
}

Before the for loop is executed, the initialization statement int i=1 will be executed first. It defines the counter variable I and assigns the initial value to 1. Then, check the loop condition I < = 100 before the loop, and execute I + + automatically after the loop. Therefore, compared with the while loop, the for loop unifies the code for updating the counter. Inside the loop body of the for loop, you do not need to update the variable I.

Therefore, the use of the for loop is:

for (initial condition; loop detection condition; update counter after loop){
    //Execute statement
}

If we want to sum all elements of an integer array, we can use the for loop to implement:

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 4, 9, 16, 25 };
        int sum = 0;
        for (int i=0; i<ns.length; i++) {
            System.out.println("i = " + i + ", ns[i] = " + ns[i]);
            sum = sum + ns[i];
        }
        System.out.println("sum = " + sum);
    }
}

The loop condition of the above code is i< ns.length . Because the length of NS array is 5, when the value of i is updated to 5 after 5 cycles, the cycle condition is not satisfied, so the for cycle ends.

Note that the initialization counter of the for loop is always executed, and the for loop may also loop 0 times.

Do not modify the counter in the loop body

When using for loop, never modify the counter in the loop body! Modifying counters in the body of a loop often leads to inexplicable logic errors. For the following code:

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 4, 9, 16, 25 };
        for (int i=0; i<ns.length; i++) {
            System.out.println(ns[i]);
            i = i + 1;
        }
    }
}

Although no error is reported, the array element is only half printed, because i = i + 1 inside the loop causes the counter variable to actually add 2 to each loop (because the for loop also automatically executes i + +). Therefore, in the for loop, do not change the value of the counter. The initialization, judgment conditions and update conditions of the counter after each cycle can be put into the for() statement at a glance.

If you want to access only array elements with an odd index, you should rewrite the for loop as follows:

int[] ns = { 1, 4, 9, 16, 25 };
for (int i=0; i<ns.length; i=i+2) {
    System.out.println(ns[i]);
}

This effect is achieved by updating the statement i=i+2 of the counter, thus avoiding modifying the variable i in the loop body.

Counter variables should be defined in the for loop as much as possible

When using the for loop, the counter variable i should be defined in the for loop as much as possible:

int[] ns = { 1, 4, 9, 16, 25 };
for (int i=0; i<ns.length; i++) {
    System.out.println(ns[i]);
}
// Unable to access i
int n = i; // compile error!

If the variable i is defined outside the for loop:

int[] ns = { 1, 4, 9, 16, 25 };
int i;
for (i=0; i<ns.length; i++) {
    System.out.println(ns[i]);
}
// i can still be used
int n = i;

Then, after exiting the for loop, variable i can still be accessed, which breaks the principle that variables should be minimized.

Flexible use of for loop

For loops can also be missing initialization statements, loop conditions, and each loop UPDATE statement, for example:

// Do not set end condition:
for (int i=0; ; i++) {
    ...
}
// Do not set end condition and update statement:
for (int i=0; ;) {
    ...
}
// Nothing to set:
for (;;) {
    ...
}

This is generally not recommended, but in some cases, you can omit some statements of the for loop.

for each loop

The for loop is often used to traverse an array, because each element of the array can be accessed by the counter according to the index:

int[] ns = { 1, 4, 9, 16, 25 };
for (int i=0; i<ns.length; i++) {
    System.out.println(ns[i]);
}

However, most of the time, what we really want to access is the value of each element of the array. Java also provides another for each loop, which can directly traverse each element of an array:

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 4, 9, 16, 25 };
        for (int n : ns) {
            System.out.println(n);
        }
    }
}

Compared with the for loop, the variable n of the for each loop is no longer a counter, but directly corresponds to each element of the array. However, the for each loop cannot specify the traversal order or get the index of the array.

In addition to arrays, the for each loop can traverse all "iteratable" data types, including List, Map, and so on.

break and continue

Whether it's a while loop or a for loop, there are two special statements that can be used: a break statement and a continue statement.

break

During a loop, you can use the break statement to jump out of the current loop. Let's take an example:

public class Main {
    public static void main(String[] args) {
        int sum = 0;
        for (int i=1; ; i++) {
            sum = sum + i;
            if (i == 100) {
                break;
            }
        }
        System.out.println(sum);
    }
}

When we use for loop calculation from 1 to 100, we do not set the detection condition of loop exit in for(). However, inside the loop, we use if to judge that if i==100, we exit the loop through break.

Therefore, break statements are usually used in conjunction with if statements. In particular, break statements always jump out of their own loop. For example:

public class Main {
    public static void main(String[] args) {
        for (int i=1; i<=10; i++) {
            System.out.println("i = " + i);
            for (int j=1; j<=10; j++) {
                System.out.println("j = " + j);
                if (j >= i) {
                    break;
                }
            }
            // break jumps here
            System.out.println("breaked");
        }
    }
}

The above code is nested with two for loops. Because the break statement is in the inner for loop, it will jump out of the inner for loop, but not out of the outer for loop.

continue

break will jump out of the current loop, that is, the entire loop will not execute. continue, on the other hand, ends this cycle ahead of time and directly continues the next cycle. Let's take an example:

public class Main {
    public static void main(String[] args) {
        int sum = 0;
        for (int i=1; i<=10; i++) {
            System.out.println("begin i = " + i);
            if (i % 2 == 0) {
                continue; // The continue statement ends the loop
            }
            sum = sum + i;
            System.out.println("end i = " + i);
        }
        System.out.println(sum); // 25
    }
}

Observe the effect of the continue statement. When i is odd, the entire loop is executed completely, so begin i=1 and end i=1 are printed. When i is even, the continue statement ends the loop ahead of time, so begin i=2 is printed but end i = 2 is not.

In a multi nested loop, the continue statement also ends the loop it is in.

1.7 array operation

Traversal array

Use standard for loop

Arrays can be traversed through the for loop. Because each element of an array can be accessed through an index, a standard for loop can be used to traverse an array:

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 4, 9, 16, 25 };
        for (int i=0; i<ns.length; i++) {
            int n = ns[i];
            System.out.println(n);
        }
    }
}

In order to implement for loop traversal, the initial condition is i=0, because the index always starts from 0 and the condition to continue the loop is i< ns.length Because when i=ns.length When, i is out of index range (index range is 0~ ns.length -1) , after each cycle, i + +.

Using the for each loop

The second way is to use the for each loop to directly iterate over each element of the array:

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 4, 9, 16, 25 };
        for (int n : ns) {
            System.out.println(n);
        }
    }
}

Obviously, the for each loop is more concise. However, the for each loop cannot get the index of the array, so which for loop to use depends on our needs.

Print array contents

Print the array variables directly to get the reference address of the array in the JVM:

int[] ns = { 1, 1, 2, 3, 5, 8 };
System.out.println(ns); // Similar[ I@7852e922

This doesn't make sense because we want to print the element contents of the array. Therefore, use the for each loop to print it:

int[] ns = { 1, 1, 2, 3, 5, 8 };
for (int n : ns) {
    System.out.print(n + ", ");
}

Using the for each loop to print is also cumbersome. Fortunately, the Java standard library provides Arrays.toString(), can quickly print array contents:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 1, 2, 3, 5, 8 };
        System.out.println(Arrays.toString(ns));
    }
}

Array sorting

Sorting arrays is a very basic requirement in a program. The common sorting algorithms are bubble sort, insert sort and fast sort.

Bubble sorting

Let's see how to use bubble sorting algorithm to sort an integer array from small to large:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
        // Before sorting:
        System.out.println(Arrays.toString(ns));
        for (int i = 0; i < ns.length - 1; i++) {
            for (int j = 0; j < ns.length - i - 1; j++) {
                if (ns[j] > ns[j+1]) {
                    // Exchange ns[j] and ns[j+1]:
                    int tmp = ns[j];
                    ns[j] = ns[j+1];
                    ns[j+1] = tmp;
                }
            }
        }
        // After sorting:
        System.out.println(Arrays.toString(ns));
    }
}

The characteristic of bubble sorting is that after each cycle, the largest number is exchanged to the end, so the last number can be "planed" in the next cycle, and each cycle is one place ahead of the end of the previous cycle.

In addition, note that swapping the values of two variables requires a temporary variable. It's wrong to write like this:

int x = 1;
int y = 2;

x = y; // x is now 2
y = x; // y is still 2

The correct way of writing is:

int x = 1;
int y = 2;

int t = x; // Save the value of x in the temporary variable t, which is now 1
x = y; // x is now 2
y = t; // y is now the value 1 of t

Arrays.sort()

In fact, Java standard library has built-in sorting function, we only need to call the Arrays.sort() to sort:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
        Arrays.sort(ns);
        System.out.println(Arrays.toString(ns));
    }
}

Sorting an array directly modifies the array itself

It must be noted that sorting arrays actually modifies the array itself. For example, the array before sorting is:

int[] ns = { 9, 3, 6, 5 };

In memory, this integer array is represented as follows:

      ┌───┬───┬───┬───┐
ns───>│ 9 │ 3 │ 6 │ 5 │
      └───┴───┴───┴───┘

When we call Arrays.sort(ns); after that, the integer array changes to:

      ┌───┬───┬───┬───┐
ns───>│ 3 │ 5 │ 6 │ 9 │
      └───┴───┴───┴───┘

That is, the contents of the array pointed to by the variable ns have been changed.

If you want to sort an array of strings, for example:

String[] ns = { "banana", "apple", "pear" };

Before sorting, the array is represented in memory as follows:

                   ┌──────────────────────────────────┐
               ┌───┼──────────────────────┐           │
               │   │                      ▼           ▼
         ┌───┬─┴─┬─┴─┬───┬────────┬───┬───────┬───┬──────┬───┐
ns ─────>│░░░│░░░│░░░│   │"banana"│   │"apple"│   │"pear"│   │
         └─┬─┴───┴───┴───┴────────┴───┴───────┴───┴──────┴───┘
           │                 ▲
           └─────────────────┘

call Arrays.sort(ns); after sorting, the array is represented in memory as follows:

                   ┌──────────────────────────────────┐
               ┌───┼──────────┐                       │
               │   │          ▼                       ▼
         ┌───┬─┴─┬─┴─┬───┬────────┬───┬───────┬───┬──────┬───┐
ns ─────>│░░░│░░░│░░░│   │"banana"│   │"apple"│   │"pear"│   │
         └─┬─┴───┴───┴───┴────────┴───┴───────┴───┴──────┴───┘
           │                              ▲
           └──────────────────────────────┘

The original three strings have no change in memory, but each element of the ns array points to a change.

Multidimensional array

Two dimensional array

Definition, assignment and element access of 2D array

A two-dimensional array is an array of arrays. Define a 2D array as follows:

public class Main {
    public static void main(String[] args) {
        int[][] ns = {
            { 1, 2, 3, 4 },
            { 5, 6, 7, 8 },
            { 9, 10, 11, 12 }
        };
        System.out.println(ns.length); // 3
    }
}

Because ns contains three arrays, so, ns.length Is 3. In fact, the structure of NS in memory is as follows:

                    ┌───┬───┬───┬───┐
         ┌───┐  ┌──>│ 1 │ 2 │ 3 │ 4 │
ns ─────>│░░░│──┘   └───┴───┴───┴───┘
         ├───┤      ┌───┬───┬───┬───┐
         │░░░│─────>│ 5 │ 6 │ 7 │ 8 │
         ├───┤      └───┴───┴───┴───┘
         │░░░│──┐   ┌───┬───┬───┬───┐
         └───┘  └──>│ 9 │10 │11 │12 │
                    └───┴───┴───┴───┘

If we define an ordinary array arr0, then assign ns[0] to it:

public class Main {
    public static void main(String[] args) {
        int[][] ns = {
            { 1, 2, 3, 4 },
            { 5, 6, 7, 8 },
            { 9, 10, 11, 12 }
        };
        int[] arr0 = ns[0];
        System.out.println(arr0.length); // 4
    }
}

In fact, arr0 gets the 0 th element of the ns array. Because each element of ns array is also an array, the array that arr0 points to is {1, 2, 3, 4}. In memory, the structure is as follows:

            arr0 ─────┐
                      ▼
                    ┌───┬───┬───┬───┐
         ┌───┐  ┌──>│ 1 │ 2 │ 3 │ 4 │
ns ─────>│░░░│──┘   └───┴───┴───┴───┘
         ├───┤      ┌───┬───┬───┬───┐
         │░░░│─────>│ 5 │ 6 │ 7 │ 8 │
         ├───┤      └───┴───┴───┴───┘
         │░░░│──┐   ┌───┬───┬───┬───┐
         └───┘  └──>│ 9 │10 │11 │12 │
                    └───┴───┴───┴───┘

To access an element of a 2D array, you need to use array[row][col], for example:

System.out.println(ns[1][2]); // 7

The length of each array element of a 2D array is not required to be the same. For example, an ns array can be defined as follows:

int[][] ns = {
    { 1, 2, 3, 4 },
    { 5, 6 },
    { 7, 8, 9 }
};

The structure of this two-dimensional array in memory is as follows:

                    ┌───┬───┬───┬───┐
         ┌───┐  ┌──>│ 1 │ 2 │ 3 │ 4 │
ns ─────>│░░░│──┘   └───┴───┴───┴───┘
         ├───┤      ┌───┬───┐
         │░░░│─────>│ 5 │ 6 │
         ├───┤      └───┴───┘
         │░░░│──┐   ┌───┬───┬───┐
         └───┘  └──>│ 7 │ 8 │ 9 │
                    └───┴───┴───┘
Print 2D array

To print a 2D array, you can use two nested for loops:

for (int[] arr : ns) {
    for (int n : arr) {
        System.out.print(n);
        System.out.print(', ');
    }
    System.out.println();
}

Or using Java standard library Arrays.deepToString() to print multidimensional arrays:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[][] ns = {
            { 1, 2, 3, 4 },
            { 5, 6, 7, 8 },
            { 9, 10, 11, 12 }
        };
        System.out.println(Arrays.deepToString(ns));
    }
}

3D array

A three-dimensional array is an array of two-dimensional arrays. You can define a 3D array as follows:

int[][][] ns = {
    {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    },
    {
        {10, 11},
        {12, 13}
    },
    {
        {14, 15, 16},
        {17, 18}
    }
};

Its structure in memory is as follows:

                              ┌───┬───┬───┐
                   ┌───┐  ┌──>│ 1 │ 2 │ 3 │
               ┌──>│░░░│──┘   └───┴───┴───┘
               │   ├───┤      ┌───┬───┬───┐
               │   │░░░│─────>│ 4 │ 5 │ 6 │
               │   ├───┤      └───┴───┴───┘
               │   │░░░│──┐   ┌───┬───┬───┐
        ┌───┐  │   └───┘  └──>│ 7 │ 8 │ 9 │
ns ────>│░░░│──┘              └───┴───┴───┘
        ├───┤      ┌───┐      ┌───┬───┐
        │░░░│─────>│░░░│─────>│10 │11 │
        ├───┤      ├───┤      └───┴───┘
        │░░░│──┐   │░░░│──┐   ┌───┬───┐
        └───┘  │   └───┘  └──>│12 │13 │
               │              └───┴───┘
               │   ┌───┐      ┌───┬───┬───┐
               └──>│░░░│─────>│14 │15 │16 │
                   ├───┤      └───┴───┴───┘
                   │░░░│──┐   ┌───┬───┐
                   └───┘  └──>│17 │18 │
                              └───┴───┘

If we want to access an element of a 3D array, for example, ns[2][0][1], we just need to find the corresponding final element 15 along the location.

Theoretically, we can define any N-dimensional array. But in practical application, in addition to the two-dimensional array in some cases can also be used, higher dimensional array is rarely used.

Command line arguments

The Java program's entry is the main method, which can take a command line parameter, which is a String [] array.

This command line parameter is received by the JVM and passed to the main method:

public class Main {
    public static void main(String[] args) {
        for (String arg : args) {
            System.out.println(arg);
        }
    }
}

We can use the received command line parameters to execute different codes according to different parameters. For example, implement a - version parameter to print the program version number:

public class Main {
    public static void main(String[] args) {
        for (String arg : args) {
            if ("-version".equals(arg)) {
                System.out.println("v 1.0");
                break;
            }
        }
    }
}

When executing, pass it a - version parameter:

$ java Main -version
v 1.0

In this way, the program can make different responses according to the command line parameters passed in.

Posted by Kurt on Sun, 21 Jun 2020 22:09:13 -0700