Let’s just say, in my opinion, Java is the most popular programming language out there (PHP aside). Not only many jobs, easy to find a job, the key is the salary level is also in place, not learning Java, right?

That may be zero basic programming partners will have a headache, most of the technical articles on the Internet about Java are not humorous, not funny enough, not enough series, in urgent need of a can read into the learning manual, then I think my liver of this manual just meet the requirements, and will continue to update.

The first release tentatively covers two areas, Java basics and Java object-oriented programming. Come on, browse the catalogue first.

01, Introduction to Java Basic Syntax 02, Introduction to Java basic data types 03, Introduction to Java Main () method 04, Java flow control statement 05, Introduction to Java package 06, Java Whether value passing or reference passing 07, Java classes and objects 08, Java constructors 09, Java Abstract Classes 10, Java interfaces 11, Java Inheritance 12, this keyword 13, super keyword 14, overwrite and overload 15, static keyword 16, Java enumeration 17, final keyword

Directory finished to appreciate, the next is the time to read the essence of the content, move a small bench, seriously really good to learn, learn is to earn!

Introduction to Java basic syntax

01. Data type

Java has two types of data, basic data type and reference type.

Basic data types are used to store simple types of data, such as int, long, byte, and short for integers, float and double for floating-point numbers, char for characters, and Boolean for booleans.

Different basic data types, with different default values and sizes, to feel the table.

The data type The default value The size of the
boolean false 1 bit
char ‘\u0000’ 2 –
byte 0 1 byte
short 0 2 –
int 0 4 bytes
long 0L 8 bytes
float 0.0 f 4 bytes
double 0.0 8 bytes

The reference type is used to store references to objects (null means an object with no value), and String is the best representation of the reference type, such as String cmower = “Silent King two”.

02. Declare variables

To declare a variable, you must specify its name and type. Here’s a simple example:

int age;
String name;
Copy the code

Count and name get a default value when they are declared, depending on their data type — not local variables (otherwise the Java compiler will remind you to assign values first when you use variables), but class member variables.

public class SyntaxLocalVariable {
    int age;
    String name;

    public static void main(String[] args) {
        SyntaxLocalVariable syntax = new SyntaxLocalVariable();
        System.out.println(syntax.age); / / 0
        System.out.println(syntax.name);  / / output is null}}Copy the code

It is also possible to assign a variable after declaring it using the “=” operator, as follows:

int age = 18;
String name = "Silent King II.";
Copy the code

We define two variables, age of int and name of String. Age is assigned 18 and name is assigned “Silent King 2”.

Each line of code is followed by a “;” , indicating that the current statement ends.

In Java, it is best for variables to follow naming conventions to make code more readable.

  • Start with a letter, underscore (_), or dollar sign ($)
  • Do not use Java reserved words, such as int, as variable names

03, arrays,

Arrays play an important role in Java as the underlying implementation of many collection classes. An array is a reference type that stores data of a specified type.

The general syntax for declaring an array is as follows:

type[] identiier = new type[length];
Copy the code

Type can be any primitive data type or reference type. Consider the following example:

public class ArraysDemo {
    public static void main(String[] args) {
        int [] nums = new int[10];
        nums[0] = 18;
        nums[1] = 19;
        System.out.println(nums[0]); }}Copy the code

The index of the array starts at 0, with the first element having an index of 0 and the second element having an index of 1. Why is it designed this way? If you’re interested, you can explore it.

The element at the specified index is accessed by the variable name [index], and the assignment or value is the same.

04, key words

Keywords are reserved words that have special meanings in Java, such as public, final, static, new, and so on. They cannot be used as variable names. For your reference, I’ve compiled a list of 48 commonly used keywords that you can take a look at.

  1. Abstract: The abstract keyword is used to declare abstract classes, which can have abstract and non-abstract methods.

  2. Boolean: The Boolean keyword is used to declare a variable as a Boolean type. It has only true and false values.

  3. Break: The break keyword is used to break a loop or switch statement.

  4. Byte: The byte keyword is used to declare a variable that can hold eight bits.

  5. Case: The case keyword is used to mark the value of the condition in the switch statement.

  6. Catch: The catch keyword is used to catch exceptions in try statements.

  7. Char: The char keyword is used to declare a variable that can hold Unicode characters with unsigned 16-bit bits.

  8. Class: The class keyword is used to declare a class.

  9. Continue: The continue keyword is used to continue the next loop. It can skip the rest of the code under specified conditions.

  10. Default: The default keyword is used to specify the default code block in the switch statement except for case conditions.

  11. Do: The do keyword is usually used with the while keyword, followed by the body of the loop.

  12. Double: The double keyword is used to declare a variable that can hold a 64-bit floating-point number.

  13. Else: The else keyword is used to indicate alternate branches in an if statement.

  14. Enum: The enum keyword is used to define a fixed set of constants.

  15. Extends: The extends keyword is used to indicate that a class inherits from another class or interface.

  16. Final: The final keyword is used to indicate that the variable is immutable.

  17. The finally: finally keyword is used in conjunction with try-catch to indicate that code ina finally block is always executed whether or not an exception is handled.

  18. Float: The float keyword is used to declare a variable that can hold a 32-bit floating point number.

  19. For: The for keyword is used to start a for loop, which is recommended if the number of loops is fixed.

  20. If: The if keyword is used to specify the condition, and if the condition is true, the corresponding code is executed.

  21. The implements: implements keyword is used to implement an interface.

  22. Import: The import keyword is used to import the corresponding class or interface.

  23. Instanceof: The instanceof keyword is used to determine whether an object belongs to a certain type (class).

  24. Int: The int keyword is used to declare a signed integer variable that can hold 32 bits.

  25. Interface: The interface keyword is used to declare interfaces — only abstract methods.

  26. Long: The long keyword is used to declare a variable that can hold a 64-bit integer.

  27. Native: The native keyword is used to specify that a method is implemented by calling the native interface (not Java).

  28. The new: new keyword is used to create a new object.

  29. Null: If a variable is empty (there is no reference to it), it can be assigned null.

  30. Package: The package keyword is used to declare the package in which the class resides.

  31. Private: The private keyword is an access modifier that indicates that a method or variable is visible only to the current class.

  32. The protected: protected keyword is also an access modifier, indicating that a method or variable is visible to classes and all subclasses within the same package.

  33. Public: The public keyword is another access modifier that allows you to declare classes in addition to methods and variables (visible to all classes). The main() method must be declared public.

  34. Return: The return keyword is used to return (a value) after code execution is complete.

  35. Short: The short keyword is used to declare a variable that can hold a 16-bit integer.

  36. Static: The static keyword indicates that the variable or method is static.

  37. Strictfp: The strictFP keyword is uncommon and is usually used to modify a method to ensure that the floating-point operations in the method body perform the same results on each platform.

  38. Super: The super keyword can be used to call methods or variables of the parent class.

  39. Switch: The switch keyword is usually used for three or more criteria.

  40. Synchronized: The synchronized keyword is used to specify synchronized methods, variables, or code blocks in multithreaded code.

  41. This: The this keyword can be used to reference the current object in a method or constructor.

  42. Throw: the throw keyword actively throws an exception.

  43. Throws: Throws The keyword is used to declare exceptions.

  44. Transient: The transient keyword is used in serialization. The fields it modifies will not be serialized.

  45. Try: The try keyword is used to wrap the block of code to catch the exception.

  46. Void: The void keyword is used to specify that a method has no return value.

  47. Volatile: The volatile keyword guarantees visibility to different threads operating on the variables it modifies. That is, if one thread modifies the value of a variable, the new value is immediately visible to other threads.

  48. While: If the number of loops is not fixed, a while loop is recommended.

05. Operators

In addition to the “=” assignment operator, there are many other Java operators that can be used, so let’s take a look.

① Arithmetic operators

  • Plus (plus sign)
  • — (minus sign)
  • * (multiplication sign)
  • / (divisor)
  • % (mod)

Here’s an example:

public class ArithmeticOperator {
    public static void main(String[] args) {
        int a = 10;
        int b = 5;
        
        System.out.println(a + b);/ / 15
        System.out.println(a - b);/ / 5
        System.out.println(a * b);/ / 50
        System.out.println(a / b);/ / 2
        System.out.println(a % b);/ / 0}}Copy the code

The + sign is special and can also be used for string concatenation. Here’s an example:

String result = "Silent King II." + "An interesting programmer.";
Copy the code

② Logical operators

Logical operators are commonly used in Boolean expressions. Common ones are:

  • && (AND) the result is false if one of the conditions is false
  • | | (OR) multiple conditions as long as have a result to true is true
  • ! (NOT) If true, add “!” Is false, otherwise, and vice versa.

Here’s an example:

public class LogicalOperator {
    public static void main(String[] args) {
        int a=10;
        int b=5;
        int c=20;
        System.out.println(a<b&&a<c);//false
        System.out.println(a>b||a<c);//trueSystem.out.println(! (a<b));// true}}Copy the code

③ Comparison operator

  • <(less than)
  • < =(less than or equal to)
  • >(greater than)
  • > =(Greater than or equal to)
  • = =(equal)
  • ! =(range)

06. Program structure

The smallest unit of program in Java is called a class, and a class can have one or more fields (also known as member variables), one or more methods, and even inner classes.

If a class wants to execute, it must have a main method — the entrance through which the program runs, like a human mouth.

public class StructureProgram {
    public static void main(String[] args) {
        System.out.println("No member variables, only one main method."); }}Copy the code
  • It’s called StructureProgram, and inside it, there’s only one main method.
  • {}The code between is called a code block.
  • The above source code will be stored in a file with the suffix Java.

07. Compile and execute the code

In general, some tutorials cover this by recommending that you compile the source code into a bytecode file by executing javac commands from the command line, and then specifying the code by executing Java commands.

However, I don’t want this situation to continue – it takes courage and patience for a beginner to install and configure the JDK, and if he or she makes a mistake, he or she will give up before getting started. Besides, compiling source code at the command line leads to a lot of unaccountable errors, which can be deadly for beginners — if you ever run into one of these old-fashioned tutorials again, spit it out.

A good way is to download IntelliJ IDEA, referred to as IDEA, which is recognized as the best Java integrated development tool in the industry, especially in intelligent code assistant, code automatic prompt, code reconstruction, code version management (Git, SVN, Maven), unit testing, code analysis and other aspects have a bright play. IDEA is made in the Czech Republic (located in Eastern Europe) and its developers are known for their rigor. IDEA is divided into community version and paid version of two versions, novice directly download the community version is enough to use.

Once the installation is complete, you can start typing code, then right-click to Run it (without even saving), and the results will be displayed in the Run panel, as shown below.

To see the decompiled bytecode, you can find a structureProgram.class file in the SRC sibling directory target/classes (if you can’t find it, right-click on the directory and select Reload from Disk).

You can double-click to open it.

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.cmower.baeldung.basic;

public class StructureProgram {
    public StructureProgram(a) {}public static void main(String[] args) {
        System.out.println("No member variables, only one main method."); }}Copy the code

IDEA by default decompiles the class bytecode into Java code we can read using Fernflower. In fact, the class bytecode (please install show Bytecode) looks like this:

/ / class version 57.65535 (65479) / / access flags 0 x21 public class com/cmower baeldung/basic/StructureProgram {/ / compiled from: StructureProgram.java // access flags 0x1 public <init>()V L0 LINENUMBER 3 L0 ALOAD 0 INVOKESPECIAL java/lang/Object.<init> ()V RETURN L1 LOCALVARIABLE this Lcom/cmower/baeldung/basic/StructureProgram; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 0x9 public static main([Ljava/lang/String;)V L0 LINENUMBER 5 L0 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC"\u6ca1\u6709\u6210\u5458\u53d8\u91cf\uff0c\u53ea\u6709\u4e00\u4e2a main \u65b9\u6cd5"INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;) V L1 LINENUMBER 6 L1 RETURN L2 LOCALVARIABLE args [Ljava/lang/String; L0 L2 0 MAXSTACK = 2 MAXLOCALS = 1 }Copy the code

Novice looks still some meng force, suggested to have an eye addiction on the line.

Introduction to Java basic data types

01, Boolean

Boolean is used to store only two values: true and false, that is, true and false, and is usually used to determine conditions. Code examples:

boolean flag = true;
Copy the code

02, byte

The byte value ranges from -128 to 127, including 127. The minimum value is -128, the maximum value is 127, and the default value is 0.

In the process of network transmission, in order to save space, bytes are commonly used as data transmission mode. Code examples:

byte a = 10;
byte b = -10;
Copy the code

03, short

Short ranges from -32,768 to 32,767, including 32,767. The minimum value is -32,768, the maximum value is 32,767, and the default value is 0. Code examples:

short s = 10000;
short r = -5000;
Copy the code

04, int

The value of int ranges from -2,147,483,648 (-2 ^ 31) to 2,147,483,647 (2 ^ 31-1) (inclusive). The default value is 0. If there are no special requirements, int is used for integer data. Code examples:

int a = 100000;
int b = -200000;
Copy the code

05, long

Long range in – 9223372036854775808-2 ^ (63) and 9223372036854775807 (2 ^ 63-1) to (including), the default value is 0. If int doesn’t fit, long is used, and int is used for integer data. Code examples:

long a = 100000L; 
long b = -200000L;
Copy the code

Long variables are declared with an uppercase “L” to distinguish them from ints. We don’t use a lowercase “L” because it can be confused with the number “1”.

06, float

Float is a single-precision floating-point number that follows IEEE 754 (binary floating-point arithmetic standard) and has an unlimited range of values. The default is 0.0F. Float is not suitable for precise numerical values, such as currency. Code examples:

float f1 = 234.5 f;
Copy the code

To distinguish float from double, float variables are declared with a lowercase “f” at the end. You don’t need to use a capital “F” because lowercase “F” is easy to identify.

07, double

Double is a double-precision floating-point number that follows IEEE 754 (binary floating-point arithmetic standard) and has an unlimited range of values. The default value is 0.0. Double is also not suitable for precise values, such as money. Code examples:

double d1 = 12.3
Copy the code

What is the exact number? It is best to use BigDecimal, which can represent a floating point number of any size with perfect precision. For the value of the currency type, you can also multiply it by 100 to turn it into an integer.

Tips: Single precision is in the format of 1 sign, 8 exponents, 23 decimals and 7 significant digits.

Double precision is the format of 1 bit sign, 11 bit exponent, 52 decimal, and 16 significant digits.

The range of values depends on the exponent bit, and the accuracy of the calculation depends on the decimal place (mantissa). The more decimal places you have, the more numbers you can represent, and the higher the calculation accuracy.

A number is composed of several digits, among which the digits that affect the measurement accuracy are called significant digits, also known as significant digits. Significant digits are the numbers used in scientific calculations to represent the accuracy of a floating point number. Generally, all numbers in a floating point number expressed as a decimal from the first non-zero number. Significant digits such as 1.24 and 0.00124 have three digits.

08, char

Char can represent a 16-bit Unicode character with values between ‘\u0000’ (0) and ‘\ UFFFF ‘(65,535) (included). Code examples:

char letterA = 'A'; // Enclose single quotation marks in English.
Copy the code

Java main(

Every program needs an entry, which in the case of Java programs is the main method.

public static void main(String[] args) {}
Copy the code

Public, static, void public, static, void void public, static, void

  • The public keyword is another access modifier that allows you to declare classes as well as methods and variables (visible to all classes). The main() method must be declared public.

  • The static keyword indicates that the variable or method is static and can be accessed directly through the class without instantiating the object.

  • The void keyword is used to specify that the method does not return a value.

In addition, the main keyword is the name of the method and the Java virtual machine looks for this identifier when executing the program. Args is the name of the argument to the main() method, which is of type String array. That is, when executing programs using Java commands, the main() method can be passed an array of strings as arguments.

Java HelloWorld Silent King two Silent King threeCopy the code

Javac command is used to compile the program, Java command is used to execute the program, HelloWorld is the class name of this program, King of Silence 2 and King of Silence 3 are string arrays separated by Spaces, You can then get the values of the parameters passed through args[0] and args[1] in the main() method.

public class HelloWorld {
    public static void main(String[] args) {
        if ("Silent King II.".equals(args[0]) {}if ("Silent King three.".equals(args[1])) {}}}Copy the code

The main() method is not unique, and there are several other variations, although they may not be common, that you can look at briefly.

Second, place square brackets [] closer to args instead of String:

public static void main(String []args) {}Copy the code

Third, place square brackets [] to the right of args:

public static void main(String args[]) {}Copy the code

Fourth, we can also change the array form to the variable argument form:

public static void main(String... args) {}Copy the code

Fifth, add another modifier, strictfp, to the main() method to emphasize compatibility when dealing with floating point numbers:

public strictfp static void main(String[] args) {}Copy the code

You can also add the final keyword or synchronized keyword to the main() method.

Sixth, you can also add the final keyword to the args argument:

public static void main(final String[] args) {}Copy the code

The seventh, the most complex, includes all the keywords that can be added:

final static synchronized strictfp void main(final String[] args) {}Copy the code

Of course, you don’t have to write the main() method in any of the above forms to make it look like it’s going to work, just use the default form provided by the IDE.

Java flow control statements

In Java, there are three types of process control statements:

  • Conditional branching, used to choose between two or more conditions. Common examples are if/else/else if, ternary operators, and switch statements.

  • Loops, or traversals, are common for, while, and do-while.

  • Break and continue, used to break out of the loop or skip to the next loop.

If statement

The format of the if statement is as follows:

if(Boolean expression){// If the condition is true, execute this code
} 
Copy the code

Draw a flow chart to show it:

Here’s an example:

public class IfExample {
    public static void main(String[] args) {
        int age = 20;
        if (age < 30) {
            System.out.println("Prime of life"); }}}Copy the code

Output:

youthCopy the code

If – else statements

The if-else statement has the following format:

if(Boolean expression){// Block of code to execute when the condition is true
}else{  
// Block of code to execute when the condition is false
}  
Copy the code

Draw a flow chart to show it:

Here’s an example:

public class IfElseExample {
    public static void main(String[] args) {
        int age = 31;
        if (age < 30) {
            System.out.println("Prime of life");
        } else {
            System.out.println("Thirty years old"); }}}Copy the code

Output:

Yao"Copy the code

In addition to this example, there is another example to judge leap years (which are divisible by 4 but not by 100 or by 400) :

public class LeapYear {
    public static void main(String[] args) {
        int year = 2020;
        if (((year % 4= =0) && (year % 100! =0)) || (year % 400= =0)) {
            System.out.println("Leap year");
        } else {
            System.out.println("Ordinary year"); }}}Copy the code

Output:

A leap yearCopy the code

If the statement is simple to execute, the ternary operator can be used instead of the if-else statement. If the condition is true, return? Behind: The preceding value; If the condition is false, return:.

public class IfElseTernaryExample {
    public static void main(String[] args) {
        int num = 13;
        String result = (num % 2= =0)?"Even" : "Odd"; System.out.println(result); }}Copy the code

Output:

An odd numberCopy the code

If – else – if statements

If-else -if statements have the following format:

if(conditions1) {// The code executed when condition 1 is true
}else if(conditions2) {// The code executed when condition 2 is true
}  
else if(conditions3) {// The code executed when condition 3 is true}...else{  
// Code executed when all of the above conditions are false
} 
Copy the code

Draw a flow chart to show it:

Here’s an example:

public class IfElseIfExample {
    public static void main(String[] args) {
        int age = 31;
        if (age < 30) {
            System.out.println("Prime of life");
        } else if (age >= 30 && age < 40 ) {
            System.out.println("Thirty years old");
        } else if (age >= 40 && age < 50 ) {
            System.out.println("Forty years old.");
        } else {
            System.out.println("Knowing destiny"); }}}Copy the code

Output:

Yao"Copy the code

Nested if statements

The format of the if nested statement is as follows:

if(outer condition){// The code executed when the outer condition is true
          if(Inside condition){// The code that executes when the inner condition is true}}Copy the code

Draw a flow chart to show it:

Here’s an example:

public class NestedIfExample {
    public static void main(String[] args) {
        int age = 20;
        boolean isGirl = true;
        if (age >= 20) {
            if (isGirl) {
                System.out.println("Legal age of marriage for girls."); }}}}Copy the code

Output:

The legal age of marriage for girlsCopy the code

Switch statement format:

switch(variable) {caseAn optional value1:    
 // Optional 1 code executed after matching;
 break;  // This keyword is optional
caseAn optional value2:    
 // Optional value 2 code executed after matching;
 break;  // This keyword is optional.default: // This keyword is optional
 // Code executed after all the optional values do not match
}    
Copy the code
  • Variables can have 1 or N values.

  • The value type must be consistent with the variable type and the value must be determined.

  • The value must be unique and cannot be repeated, or the compilation will fail.

  • The break keyword is optional; if not, the next case is executed; if so, the switch statement is jumped.

  • The default keyword is also optional.

Draw a flow chart:

Here’s an example:

public class Switch1 {
    public static void main(String[] args) {
        int age = 20;
        switch (age) {
            case 20 :
                System.out.println("School");
                break;
            case 24 :
                System.out.println("Work in Suzhou");
                break;
            case 30 :
                System.out.println("Luoyang Work");
                break;
            default:
                System.out.println("Unknown");
                break; / / can be omitted}}}Copy the code

Output:

Go to schoolCopy the code

When two values execute the same code, you can write the code to execute in the next case statement, and the previous case statement has nothing in it. Here’s an example:

public class Switch2 {
    public static void main(String[] args) {
        String name = "Silent King II.";
        switch (name) {
            case "James":
                System.out.println("Basketball player");
                break;
            case "Jose Mourinho":
                System.out.println("Football coach");
                break;
            case "Silent King II.":
            case "Silent King three.":
                System.out.println("Table Tennis enthusiast");
                break;
            default:
                throw new IllegalArgumentException(
                        "No match for the name."); }}}Copy the code

Output:

Table tennis enthusiastCopy the code

Enumerations are also common as variables in switch statements, for example:

public class SwitchEnumDemo {
    public enum PlayerTypes {
        TENNIS,
        FOOTBALL,
        BASKETBALL,
        UNKNOWN
    }

    public static void main(String[] args) {
        System.out.println(createPlayer(PlayerTypes.BASKETBALL));
    }

    private static String createPlayer(PlayerTypes playerType) {
        switch (playerType) {
            case TENNIS:
                return "Federer the Tennis player.";
            case FOOTBALL:
                return "Cristiano Ronaldo, soccer player.";
            case BASKETBALL:
                return "James the Basketball Player";
            case UNKNOWN:
                throw new IllegalArgumentException("Unknown");
            default:
                throw new IllegalArgumentException(
                        "Type of athlete:"+ playerType); }}}Copy the code

Output:

Lebron James, basketball playerCopy the code

Loop statement comparison

Compare the way for while do-while
Introduction to the The number of for loops is fixed The number of times in the while loop is variable and the condition true is required The number of do-while loops is also variable, but the loop is executed at least once, and the boring condition is true
When to use The number of cycles is fixed The number of cycles is not fixed The number of loops is not fixed, and the body of the loop must be executed at least once
grammar for(init:condition; ++/–) {// Code to execute} While (condition){// Code to execute} Do {// code to execute}while(condition);

Normal for loop

A normal for loop can be divided into four parts:

1) Initial variables: initial conditions at the start of the loop execution.

2) Condition: the condition to be judged each time the loop is executed. If true, the loop body is executed; If false, the loop is broken. Of course, the condition is optional, and if there is no condition, the loop keeps going.

3) Loop body: a block of code to execute each time through the loop until the condition is false.

4) Autoincrement/autodecrement: the way of variable change.

Take a look at the format of a normal for loop:

for(First knowledge of variables; Conditions; Autoincrement/autodecrement){/ / the loop body
}  
Copy the code

Draw a flow chart:

Here’s an example:

public class ForExample {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            System.out.println("How handsome is The silent King?"); }}}Copy the code

Output:

King Silent is so handsome King Silent is so handsome King Silent is so handsome King Silent is so handsomeCopy the code

Loop statements can also be nested so that they can be printed in a more playful way.

public class PyramidForExample {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j<= i; j++) { System.out.print("❤"); } System.out.println(); }}}Copy the code

What do you print out?

❤❤❤❤❤ ❤❤❤❤❤ ❤Copy the code

for-each

The for-each loop is usually used to iterate over groups of numbers and collections. Its usage rules are simpler than normal for loops. There are no initial variables, no conditions, and no subscripts from increment or decrement. Take a look at the syntax:

for(Element type Element: array or collection){// The code to execute
}  
Copy the code

Take a look at an example:

public class ForEachExample {
    public static void main(String[] args) {
        String[] strs = {"Silent King II."."An interesting programmer."};

        for(String str : strs) { System.out.println(str); }}}Copy the code

Output:

Silent King 2 an interesting programmerCopy the code

Infinite for loop

Want to experience the power of an infinite for loop, that is, an infinite loop?

public class InfinitiveForExample {
    public static void main(String[] args) {
        for(;;) { System.out.println("Can't stop..."); }}}Copy the code

Output:

Can't stop... Can't stop... Can't stop... Can't stop...Copy the code

Once it’s up and running, it can’t be stopped unless it’s stopped by force.

The while loop

while(conditions) {/ / the loop body
}  
Copy the code

Draw a flow chart:

Here’s an example:

public class WhileExample {
    public static void main(String[] args) {
        int i = 0;
        while (true) {
            System.out.println("Silent King II.");
            i++;
            if (i == 5) {
                break; }}}}Copy the code

Guess how many times?

2 Kings of Silence 2 Kings of Silence 2 Kings of Silence 2 Kings of Silence 2 Kings of Silence 2Copy the code

The do while loop

do{  
/ / the loop body
}while(submitted);Copy the code

Draw a flow chart:

Here’s an example:

public class DoWhileExample {
    public static void main(String[] args) {
        int i = 0;
        do {
            System.out.println("Silent King II.");
            i++;
            if (i == 5) {
                break; }}while (true); }}Copy the code

The program output is as follows:

2 Kings of Silence 2 Kings of Silence 2 Kings of Silence 2 Kings of Silence 2 Kings of Silence 2Copy the code

break

The break keyword is commonly used to interrupt a loop or switch statement, which interrupts the current flow of a program under specified conditions. If it is an internal loop, only the internal loop is broken.

You can use the break keyword in all types of loop statements, such as for, while, and do-while.

Let’s draw a flow chart to feel it:

Examples used in a for loop:

for (int i = 1; i <= 10; i++) {
    if (i == 5) {
        break;
    }
    System.out.println(i);
}
Copy the code

Examples used in nested for loops:

for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 3; j++) {
        if (i == 2 && j == 2) {
            break;
        }
        System.out.println(i + ""+ j); }}Copy the code

Examples used in a while loop:

int i = 1;
while (i <= 10) {
    if (i == 5) {
        i++;
        break;
    }
    System.out.println(i);
    i++;
}
Copy the code

Examples used in a do-while loop:

int j = 1;
do {
    if (j == 5) { 
        j++;
        break;
    }
    System.out.println(j);
    j++;
} while (j <= 10);
Copy the code

continue

The continue keyword is used when we need to jump immediately to the next loop in a for or (do) while loop. It is usually used to skip the body of the loop under specified conditions, or only the current loop if the loop is nested.

Here’s an example:

public class ContinueDemo {
    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {
            if (i == 5) {
                Use the continue keyword
                continue;// 5 will be skipped} System.out.println(i); }}}Copy the code

Output:

1, 2, 3, 4, 6, 7, 8, 9, 10Copy the code

5 really gets skipped.

Let’s do another example of loop nesting.

public class ContinueInnerDemo {
    public static void main(String[] args) {
        for (int i = 1; i <= 3; i++) {
            for (int j = 1; j <= 3; j++) {
                if (i == 2 && j == 2) {
                    // skip if I =2 and j=2
                    continue;
                }
                System.out.println(i + ""+ j); }}}}Copy the code

What do you print out?

1, 1, 1, 2, 1, 3, 2, 1, 2, 3, 3, 1, 3, 2, 3, 3Copy the code

“2 2” has no output and is skipped.

Let’s look again at the use of continue in a while loop:

public class ContinueWhileDemo {
    public static void main(String[] args) {
        int i = 1;
        while (i <= 10) {
            if (i == 5) {
                i++;
                continue; } System.out.println(i); i++; }}}Copy the code

Output:

1, 2, 3, 4, 6, 7, 8, 9, 10Copy the code

Note: if you omit “i++” from the if condition, the program will continue in an infinite loop.

Finally, take a look at the use of continue in the do-while loop:

public class ContinueDoWhileDemo {
    public static void main(String[] args) {
        int i=1;
        do{
            if(i==5){
                i++;
                continue;
            }
            System.out.println(i);
            i++;
        }while(i<=10); }}Copy the code

Output:

1, 2, 3, 4, 6, 7, 8, 9, 10Copy the code

Note: also, if you omit “i++” from the if condition, the program will continue in an infinite loop.

Introduction to Java package

In Java, we use packages to group related classes, interfaces, and subpackages. The benefits of this are:

  • Make related types easier to find
  • Avoid naming conflicts, such as com.itwanger.hello is different from com.itwangsan.hello
  • Class visibility is limited by package and access control characters

Create a package

package com.itwanger;
Copy the code

You can use the package keyword to define a package name, noting that this line of code must be the first line in a class. Declaring classes in packages is strongly recommended, rather than default, or you lose the benefits of package structure.

Bags should be named according to the following rules:

  • It should be all lowercase
  • Can contain more than one word, with “between” words. Connect, for examplejava.lang
  • The name is determined by the name of the company or organization in reverse order, for example, the domain name of my personal blog iswww.itwanger.com, so I created the package name iscom.itwanger.xxxx.

Each package or subpackage has its own directory structure on disk. If the Java file is in the com.itwanger. XXXX package, the directory structure of the file should be com->itwanger-> XXXX.

02. Use a package

Let’s create a new Cmower class in a subpackage named Test:

package com.itwanger.test;

public class Cmower {
    private String name;
    private int age;
}
Copy the code

If you need to use the Cmower class in another package, you need to introduce it through the import keyword. There are two options. First, use * to import all classes in the package:

import com.itwanger.test.*;
Copy the code

Second, import the class with the class name:

import com.itwanger.test.Cmower;
Copy the code

There are many packages available from Java and third-party class libraries, and you can import them in the same way.

package com.itwanger.test;

import java.util.ArrayList;
import java.util.List;

public class CmowerTest {
    public static void main(String[] args) {
        List<Cmower> list = new ArrayList<>();
        list.add(newCmower()); }}Copy the code

03, full name,

Sometimes, we might use two classes with the same name from different packages. For example, we might use both java.sql.Date and java.util.Date. When we encounter a naming conflict, we need to use the full name (package name + class name) for at least one class.

List<com.itwanger.test.Cmower> list1 = new ArrayList<>();
list.add(new com.itwanger.test.Cmower());
Copy the code

Is Java passed by value or by reference

There are two common ways of passing parameters to methods, “value passing” and “reference passing.” The C language itself only supports value passing, and its derivative C++ supports both value passing and reference passing, while Java only supports value passing.

01. Value passing VS reference passing

First of all, we need to be clear about what value passing is and what reference passing is, otherwise the discussion of Java as value passing or reference passing is meaningless.

When a parameter is passed as a value between two methods, the caller and the called are actually using two different variables — the variable in the called (the original value) is a copy of the variable in the caller, and changes to either variable will not affect the other.

When a parameter is passed by reference between two methods, the caller and the called are using the same variable, and both are visible when the variable is modified.

The main reason Java programmers confuse value passing with reference passing is that Java has two types of data: a primitive type, such as int, and a reference type, such as String.

Primitives store actual values, while referential variables store references to objects — their memory address. Values and references are stored in the stack, while objects are stored in the heap.

The reason for this difference is that:

  • The advantage of the stack is that access is faster than the heap, second only to registers located directly in the CPU. The downside is that the size and lifetime of the data in the stack must be fixed.
  • The advantage of the heap is that memory can be allocated dynamically, the lifetime of the heap does not have to be told to the compiler in advance, and Java’s garbage collector automatically collects data that is no longer used. But because memory is allocated dynamically at run time, access speed is slow.

02. Basic type of parameter passing

As you know, Java has eight basic data types: int, Long, byte, short, float, double, char, and Boolean. Their values are stored directly on the stack, and each time they are passed as arguments, a new copy of the original value (argument) is made for the parameter. The parameter is cleared from the stack at the end of the called method.

Take a look at this code:

public class PrimitiveTypeDemo {
    public static void main(String[] args) {
        int age = 18;
        modify(age);
        System.out.println(age);
    }

    private static void modify(int age1) {
        age1 = 30; }}Copy the code

1) Age in main is a basic type, so its value 18 is stored directly on the stack.

2) When the modify() method is called, a copy of the age argument (age1) is created, also with the value 18, but elsewhere in the stack.

3) Any modification to the parameter age will only affect itself and not the argument.

03. Parameter passing of reference type

Let’s look at the code that creates a reference type variable:

Writer writer = new Writer(18."Silent King II.");
Copy the code

Is writer an object? Or a reference to an object? To clarify this, we can split the above code into two lines:

Writer writer;
writer = new Writer(18."Silent King II.");
Copy the code

If writer were an object, there would be no need to create the object with the new keyword, right? That is, writer is not an object, just a variable until the “=” operator executes. So who is the object? New Writer(18, “Silent King II “), which is an object, stored in the heap; The “=” operator then assigns a reference to the object to the Writer variable, which should then be called an object reference, which is stored on the stack and holds the address of the object in the heap.

Each time a reference type is passed as an argument, a copy (parameter) of the object reference (argument) is created, which holds the same address as the argument.

Take a look at this code:

public class ReferenceTypeDemo {
    public static void main(String[] args) {
        Writer a = new Writer(18);
        Writer b = new Writer(18);
        modify(a, b);

        System.out.println(a.getAge());
        System.out.println(b.getAge());
    }

    private static void modify(Writer a1, Writer b1) {
        a1.setAge(30);

        b1 = new Writer(18);
        b1.setAge(30); }}Copy the code

1) Before calling modify(), arguments A and b refer to different objects, even though they are both 18.

2) When the modify() method is called, new copies of arguments A and b are created on the stack, a1 and b1 respectively, but to the same objects (A and A1 point to object A, b and b1 point to object B).

3) In the modify() method, we modify the age of parameter A1 to 30, which means that the age of object A has changed from 18 to 30, and the age of object A has changed from 30. Parameter b1 refers to a new object, and the age of b1 is subsequently changed to 30.

Changing the age of A1 means changing the age of A, because they point to the same object; Changing the age of b1 has no effect on B, because they point to two objects.

The output of the program is as follows:

30
18
Copy the code

Sure enough, it fits our analysis.

Java classes and objects

Classes and objects are two of the most basic concepts in Java, and they have made object-oriented programming (OOP) possible. Objects can be any object in reality can see (a maverick pigs), can be imagined any virtual object (sun wukong can seventy-two), the Java class (class) to define the object, what is the state (through the fields, or a member variable definition, such as the color of the pig is pure color or colors), Behavior (defined by means such as pigs eating and sleeping).

Let me define a simple class for you.

public class Pig {
    private String color;

    public void eat(a) {
        System.out.println("Eat"); }}Copy the code

By default, every Java class has an empty constructor, which can be seen by decomcompiling bytecode, even though it is the default in the source code.

public class Pig {
    private String color;

    public Pig(a) {}public void eat(a) {
        System.out.println("Eat"); }}Copy the code

Public Pig() {} public Pig() {} We can use this constructor to create an object with the new keyword, as follows:

 Pig pig = new Pig();
Copy the code

Of course, we can also actively add parameterised constructors.

public class Pig {
    private String color;

    public Pig(String color) {
        this.color = color;
    }

    public void eat(a) {
        System.out.println("Eat"); }}Copy the code

When you look at the decomcompiled bytecode, you’ll see that the default no-argument constructor has disappeared — exactly as the source code did.

public class Pig {
    private String color;

    public Pig(String color) {
        this.color = color;
    }

    public void eat(a) {
        System.out.println("Eat"); }}Copy the code

This means that objects cannot be created using new Pig() — the compiler will remind you to append parameters.

Let’s say you change your code to new Pig(” pure white “), or add a constructor with no arguments.

public class Pig {
    private String color;

    public Pig(String color) {
        this.color = color;
    }

    public Pig(a) {}public void eat(a) {
        System.out.println("Eat"); }}Copy the code

The default state of an object created using the no-argument constructor is null (color string is the reference type) or, if it is a primitive type, the default value of the corresponding primitive type, such as int 0, as shown in the following figure.

(There is an error in the picture, Boolean defaults to false)

Next, let’s create multiple Pig objects, each with a different color.

public class PigTest {
    public static void main(String[] args) {
        Pig pigNoColor = new Pig();
        Pig pigWhite = new Pig("Pure white");
        Pig pigBlack = new Pig("Pure black"); }}Copy the code

As you can see, we’ve created three Pig objects of different colors, all from a single class, which shows the importance of classes that can be used multiple times after being defined once.

What if I want to change the state of the object? What to do? There is no way to do this because there is no way to change the state, and it is not possible to change color directly because its access modifier is private.

The best way to do this is to append getter/setter methods to the Pig class like this:

public String getColor(a) {
    return color;
}

public void setColor(String color) {
    this.color = color;
}
Copy the code

They are modified by the setColor() method, and the status is obtained by the getColor() method. Their permission modifiers are public.

Pig pigNoColor = new Pig();
pigNoColor.setColor("Design and color");
System.out.println(pigNoColor.getColor()); / / design and color
Copy the code

Why is it designed this way? Public = getter/setter = public = getter/setter = getter/setter

Because in some cases, certain fields are not allowed to be modified arbitrarily, it is only initialized once when the object is created, such as the age of the pig, which can only grow one year per year (for example), and there is no moonlight box to change it back.

private int age;

public int getAge(a) {
    return age;
}

public void increaseAge(a) {
    this.age++;
}
Copy the code

You see, age has no setter methods, only an increaseAge() method and a getter method that can be called once a year. If you change the access modifier for age to public, age is completely out of control and can be reset to 0 or negative at will.

Access modifiers are important to Java, and there are four of them: public, private, protected, and default.

A class can only use the public or default modifier. You’ve seen the public modifier class before. Now LET me define a class with the default permission modifier for you to see.

class Dog {}Copy the code

Ha ha, there is nothing to appreciate. The default means that this class can be accessed by other classes in the same package; Public means that the class can be accessed by all classes in the package.

The compiler will get angry if it insists on using private and protected to modify classes.

Private can be used to modify class constructors, fields, and methods that can only be accessed by the current class. Protected can also be used to modify class constructors, fields, and methods, but it has a wider scope and can be accessed by classes in the same package, or by subclasses of the current class.

Here’s a comparison of the four permission modifiers:

  • It can be accessed regardless of the permission modifier in the same class;
  • In the same package, the private modifier is not accessible;
  • Subclasses can access public and protected;
  • The public modifier faces the world, ha ha, and can be accessed anywhere.

Java constructor

Suppose we now have a Writer class with two fields, name and age:

public class Writer {
    private String name;
    private int age;

    @Override
    public String toString(a) {
        return "Writer{" +
                "name='" + name + '\' ' +
                ", age=" + age +
                '} '; }}Copy the code

Overrides the toString() method to print the details of the Writer class. The absence of a constructor means that when we create the Writer object, its field values are not initialized:

Writer writer = new Writer();
System.out.println(writer.toString());
Copy the code

The following output is displayed:

Writer{name='null', age=0}
Copy the code

Name is a string, so the default value is null, and age is an int, so the default value is 0.

Let’s take the initiative to add a no-argument constructor to the Writer class:

public Writer(a) {
    this.name = "";
    this.age = 0;
}
Copy the code

A constructor is also a method, except that it does not return a value. By default, it returns the type of the object that was created. Note that the current constructor takes no parameters; it is called a no-parameter constructor. If we do not actively create a no-parameter constructor, the compiler implicitly automatically adds a no-parameter constructor. This is why, although there is no constructor, you can use New Writer() to create objects in the first place, except that all fields are initialized to default values.

Next, let’s add a constructor with arguments:

public Writer(String name, int age) {
    this.name = name;
    this.age = age;
}
Copy the code

Now, when we create the Writer object, we can initialize the values of the fields.

Writer writer1 = new Writer("Silent King II.".18);
System.out.println(writer1.toString());
Copy the code

Take a look at the print:

Writer{name='The Silent King ii', age=18}
Copy the code

We can add constructors for different numbers of arguments depending on the number of fields. For example, we can add a separate constructor for the name field:

public Writer(String name) {
    this.name = name;
}
Copy the code

To accommodate the age field, we can call another constructor using the this keyword:

public Writer(String name) {
    this(name,18);
}
Copy the code

Set the author’s age to 18 by default. If you want to use the constructor of the parent class, you can also use the super keyword, as described later in the manual.

Java Abstract classes

Java’s abstract classes come in handy when the task we want to accomplish is certain, but the specific way to do it requires a vote at a later meeting. How to understand this sentence? Take a little bench and let me tell you something.

Five key points about abstract classes

1) When you define an abstract class, you need to use the keyword abstract.

public abstract class AbstractPlayer {}Copy the code

As for the naming of Abstract classes, the Java development manual produced by Ali emphasizes that “Abstract class names should start with Abstract or Base”, remember that.

2) Abstract classes cannot be instantiated, but can have subclasses.

If you try to instantiate using the new keyword, the compiler will report an error saying “class is abstract and cannot be instantiated”.

Abstract classes can be inherited using the extends keyword, and the BasketballPlayer class is a subclass of AbstractPlayer.

public class BasketballPlayer extends AbstractPlayer {}Copy the code

3) If a class defines one or more abstract methods, the class must be abstract.

When an abstract method is defined in a normal class without the abstract keyword modifier, the compiler gets two errors.

The first is at the class level, which tells you that “this class must be defined by the abstract keyword.” The or message is not necessary, as shown in the figure below.

The second is at the method level, which reminds you that “the class in which an abstract method resides is not abstract,” as shown in the figure below.

4) An abstract class may declare both abstract and concrete methods, or none at all, but it is not necessary. Like this:

public abstract class AbstractPlayer {
    abstract void play(a);
    
    public void sleep(a) {
        System.out.println("Athletes should rest instead of pushing the envelope."); }}Copy the code

5) Subclasses derived from an abstract class must implement the abstract methods defined in the parent class. For example, if the play() method is defined in an abstract class, it must be implemented in a subclass.

public class BasketballPlayer extends AbstractPlayer {
    @Override
    void play(a) {
        System.out.println("I'm Wilt Chamberlain. I scored 100 points on the basketball court."); }}Copy the code

If there is no implementation, the compiler will remind you that “subclasses must implement abstract methods”, as shown below.

02. When to Use Abstract classes

Another concept closely related to abstract classes is interfaces, which we’ll save for the next article because there’s a lot more to cover. All you need now is the notion that an interface is an abstraction of behavior, and an abstract class is an abstraction of the entire class (including its member variables and behavior).

(Don’t worry, just wait for the next article to come out)

In addition to interfaces, there is also the concept of concrete classes, which are ordinary classes that are not decorated with Abstract, as defined in the following code.

public class BasketballPlayer {
   public void play(a) {
        System.out.println("I'm James, the first man alive."); }}Copy the code

You have interfaces, you have concrete classes, so when should you use abstract classes?

1) We want some common functionality to be reused by multiple subclasses. For example, the AbstractPlayer abstract class has a common method called sleep() that indicates that all athletes need to rest, and this method can be reused by subclasses.

public abstract class AbstractPlayer {
    public void sleep(a) {
        System.out.println("Athletes should rest instead of pushing the envelope."); }}Copy the code

Although AbstractPlayer classes may not be abstract — removing the abstract modifier can satisfy this scenario. But AbstractPlayer classes may also have one or more abstract methods.

BasketballPlayer inherits AbstractPlayer class, and thus has the sleep() method.

public class BasketballPlayer extends AbstractPlayer {}Copy the code

A BasketballPlayer object can call the sleep() method directly:

BasketballPlayer basketballPlayer = new BasketballPlayer();
basketballPlayer.sleep();
Copy the code

FootballPlayer inherits AbstractPlayer class and has the sleep() method.

public class FootballPlayer extends AbstractPlayer {}Copy the code

FootballPlayer objects can also call sleep() directly:

FootballPlayer footballPlayer = new FootballPlayer();
footballPlayer.sleep();
Copy the code

2) We need to define the API in an abstract class and extend the implementation in subclasses. For example, the AbstractPlayer abstract class has an abstract method play() that defines that all athletes can play a sport, but requires subclasses to extend the implementation.

public abstract class AbstractPlayer {
    abstract void play(a);
}
Copy the code

BasketballPlayer extends the AbstractPlayer class to implement its own play() method.

public class BasketballPlayer extends AbstractPlayer {
    @Override
    void play(a) {
        System.out.println("I'm Wilt Chamberlain, I've scored 100 points on the basketball court,"); }}Copy the code

FootballPlayer extends the AbstractPlayer class to implement its own Play () method.

public class FootballPlayer extends AbstractPlayer {
    @Override
    void play(a) {
        System.out.println("I'm Cristiano Ronaldo. I can catch a header from any height."); }}Copy the code

3) If the relationship between the parent class and the child class conforms to the hierarchy of IS-A, we can use abstract classes, such as basketball players are athletes, football players are athletes.

03. Specific examples

To further illustrate the nature of abstract classes, let’s look at a concrete example. Suppose you have a file with a very simple “Hello World” in it, and now you need a reader to read it out, preferably in uppercase or lowercase.

In this case, it is best to define an abstract class, such as BaseFileReader:

public abstract class BaseFileReader {
    protected Path filePath;

    protected BaseFileReader(Path filePath) {
        this.filePath = filePath;
    }

    public List<String> readFile(a) throws IOException {
        return Files.lines(filePath)
                .map(this::mapFileLine).collect(Collectors.toList());
    }

    protected abstract String mapFileLine(String line);
}
Copy the code

FilePath is the filePath, protected, indicating that the member variable can be accessed by subclasses if needed.

The readFile() method is used to read files, and the abstract method mapFileLine() is called inside the method body — which requires subclasses to extend the way capitalization is implemented.

As you can see, BaseFileReader is designed to be reasonable and easy to extend, and subclasses just need to focus on the specific case implementation.

Lower case:

public class LowercaseFileReader extends BaseFileReader {
    protected LowercaseFileReader(Path filePath) {
        super(filePath);
    }

    @Override
    protected String mapFileLine(String line) {
        returnline.toLowerCase(); }}Copy the code

Uppercase:

public class UppercaseFileReader extends BaseFileReader {
    protected UppercaseFileReader(Path filePath) {
        super(filePath);
    }

    @Override
    protected String mapFileLine(String line) {
        returnline.toUpperCase(); }}Copy the code

You see, the code that reads from a file line by line is reused by subclasses — the ordinary method readFile() defined in the abstract BaseFileReader class. In the meantime, subclasses just focus on what they do, LowercaseFileReader reads files in lower case and UppercaseFileReader reads files in upper case.

Next, let’s create a new test class FileReaderTest:

public class FileReaderTest {
    public static void main(String[] args) throws URISyntaxException, IOException {
        URL location = FileReaderTest.class.getClassLoader().getResource("helloworld.txt");
        Path path = Paths.get(location.toURI());
        BaseFileReader lowercaseFileReader = new LowercaseFileReader(path);
        BaseFileReader uppercaseFileReader = newUppercaseFileReader(path); System.out.println(lowercaseFileReader.readFile()); System.out.println(uppercaseFileReader.readFile()); }}Copy the code

The project has a text file in the resource directory called helloworld.txt.

You can get the URI path of the file using classLoader.getResource (), and then use LowercaseFileReader and UppercaseFileReader to read the text.

The following output is displayed:

[hello world]
[HELLO WORLD]
Copy the code

10. Java interface

Abstraction is an attractive feature of object-oriented programming. If a programmer is poor at abstract thinking, he will have a lot of difficulty in programming, and he will not be able to turn business into concrete code. In Java, abstraction can be achieved in two forms: abstract classes and interfaces.

If you want to know the difference between an abstract class and an interface right now, I can give you one in advance:

  • A class can inherit only one abstract class, but can implement multiple interfaces.

Of course, this distinction can be a little difficult to understand without figuring out exactly what an interface is and what it does.

What is an interface

An interface is defined by the interface keyword, which can contain constants and methods, as shown in the following example.

public interface Electronic {
    / / constant
    String LED = "LED";

    // Abstract methods
    int getElectricityUse(a);

    // Static method
    static boolean isEnergyEfficient(String electtronicType) {
        return electtronicType.equals(LED);
    }

    // The default method
    default void printDescription(a) {
        System.out.println("Electronic"); }}Copy the code

1) Variables defined in the interface are automatically compiled with the public static final modifier, meaning that the LED variable is actually a constant.

The official Java documentation has this declaration:

Every field declaration in the body of an interface is implicitly public, static, and final.

In other words, interfaces can be used as constant classes and omit public static final, which seems like a good choice, right?

But that is not an option. Because interfaces are meant to abstract methods, constant interfaces cause namespace contamination of variables in subclasses.

2) Methods that do not use the private, default, or static keywords are implicitly abstract, and the public abstract modifier is automatically added at compile time. That is, getElectricityUse() is an abstract method with no body — that’s what defines the interface.

3) Starting with Java 8, static methods are allowed in interfaces, such as the isEnergyEfficient() method.

Static methods cannot by (implements this interface) the object of the class calls, it can only be called by the name of the interface, such as Electronic, isEnergyEfficient (” LED “).

The purpose of defining static methods in the interface is to improve the competitiveness of the interface by providing a simple mechanism to invoke methods without creating objects.

4) The default method is also allowed in interfaces since Java 8, such as printDescription(), which always consists of a block of code that provides a default implementation for classes that implement the interface without overriding the method. That is, a “; “cannot be used directly. To end the default method — the compiler will give an error.

There is a good reason to allow default methods to be defined in an interface, because an interface can have multiple implementation classes that must implement the abstract classes defined in the interface or the compiler will report an error. If we need to append a specific method to all implementation classes, we would have to modify the implementation classes one by one without the help of the default method.

If you look at the decompressed bytecode of the Electronic interface, you’ll see that the public keyword is automatically added to any variable or method defined in the interface — remember the decompressed bytecode if you want to know what the compiler is doing behind the scenes.

public interface Electronic
{

    public abstract int getElectricityUse(a);

    public static boolean isEnergyEfficient(String electtronicType)
    {
        return electtronicType.equals("LED");
    }

    public void printDescription(a)
    {
        System.out.println("\u7535\u5B50");
    }

    public static final String LED = "LED";
}
Copy the code

Some readers may ask, “Brother, why is my decompiled bytecode different from yours, and what decompiled tool did you use?” In fact, there is no secret, wechat search “silent king 2” reply keyword “JAD” can be obtained for free, super easy to use.

02. Precautions for defining interfaces

From the previous examples, we can draw the following conclusions:

  • Interface allows you to define variables
  • The interface allows you to define abstract methods
  • Allow static methods to be defined in interfaces (after Java 8)
  • Allows default methods to be defined in interfaces (after Java 8)

In addition, we should also know:

1) Interfaces are not allowed to be instantiated directly.

You need to define a class to implement the interface and then instantiate it.

public class Computer implements Electronic {

    public static void main(String[] args) {
        new Computer();
    }

    @Override
    public int getElectricityUse(a) {
        return 0; }}Copy the code

2) Interfaces can be empty, defining neither variables nor methods.

public interface Serializable {}Copy the code

Serializable is typically an empty interface. I previously shared a post on Java Serializable: An empty interface. If you are interested, check out my personal blog to see what an empty interface means.

www.itwanger.com/java/2019/1…

3) Do not use the final keyword when defining an interface, otherwise a compilation error will be reported, because the interface is intended for subclasses, and final prevents this behavior.

4) The abstract methods of the interface cannot be private, protected, or final.

5) Interface variables are implicitly public static final, so their values cannot be changed.

03. What can interfaces do

1) Make certain implementation classes have the desired functionality. For example, classes that implement the Cloneable interface have the ability to copy and classes that implement Comparable or Comparator have the ability to compare.

Like Serializable, Cloneable and Serializable are both markup interfaces and are internally empty. Class implements the Cloneable interface can use Object. The clone () method, otherwise will throw CloneNotSupportedException.

public class CloneableTest implements Cloneable {
    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        CloneableTest c1 = newCloneableTest(); CloneableTest c2 = (CloneableTest) c1.clone(); }}Copy the code

No error is reported after running. Now drop Implements Cloneable.

public class CloneableTest {
    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        CloneableTest c1 = newCloneableTest(); CloneableTest c2 = (CloneableTest) c1.clone(); }}Copy the code

After running throw CloneNotSupportedException:

Exception in thread "main" java.lang.CloneNotSupportedException: com.cmower.baeldung.interface1.CloneableTest
	at java.base/java.lang.Object.clone(Native Method)
	at com.cmower.baeldung.interface1.CloneableTest.clone(CloneableTest.java:6)
	at com.cmower.baeldung.interface1.CloneableTest.main(CloneableTest.java:11)
Copy the code

For the purposes of Comparable and Comparator, please refer to my previous article, Come on, Get your head around Comparable and Comparator in Java.

www.itwanger.com/java/2020/0…

2) Java supports only single inheritance in principle, but multiple inheritance can be achieved through interfaces.

Some readers may ask, “Brother, why does Java only support single inheritance?” Let me explain it briefly.

If two classes inherit (extends) a parent class with a particular method, that method is overridden by both subclasses. Then, if you decide to inherit both subclasses, when you call the override method, the compiler cannot recognize which subclass’s method you are calling. This is the famous diamond problem, as shown in the figure below.

ClassC inherits both ClassA and ClassB. When ClassC objects call overloaded methods in ClassA and ClassB, they do not know whether the method is ClassA or ClassB.

Interfaces have no such problems. To define two interfaces, Fly and Run.

public interface Fly {
    void fly(a);
}
public interface Run {
    void run(a);
}
Copy the code

Then have a class implement both interfaces.

public class Pig implements Fly.Run{
    @Override
    public void fly(a) {
        System.out.println("Flying pigs.");
    }

    @Override
    public void run(a) {
        System.out.println("Pigs that can run."); }}Copy the code

In a way, this achieves the purpose of multiple inheritance: in the real world, pigs can only run, but in Lei jun’s eyes, pigs standing in the wind can fly, which requires giving the pig more abilities, which cannot be achieved through abstract classes, but only through interfaces.

3) Implement polymorphism.

What is polymorphism? Popular understanding is that the same event will produce different results on different objects. Click the X number on the window with the left mouse button to close the window, and click the hyperlink to open a new webpage.

Polymorphism can be implemented through an extends relationship or in the form of an interface. Here’s an example.

Shape means a Shape.

public interface Shape {
    String name(a);
}
Copy the code

A circle is a shape.

public class Circle implements Shape {
    @Override
    public String name(a) {
        return "Circle"; }}Copy the code

A square is also a shape.

public class Square implements Shape {
    @Override
    public String name(a) {
        return "Square"; }}Copy the code

Then look at the test class.

List<Shape> shapes = new ArrayList<>();
Shape circleShape = new Circle();
Shape squareShape = new Square();

shapes.add(circleShape);
shapes.add(squareShape);

for (Shape shape : shapes) {
    System.out.println(shape.name());
}
Copy the code

The existence of polymorphism requires three conditions:

Circle and Square overwrite the name() method of their parent class. Circle and Square overwrite the name() method of their parent class. CircleShape and squareShape are both of type Shape, but the former points to a Circle and the latter to a Square.

Then, let’s take a look at the test results:

Round squareCopy the code

That means that even though shape is of type shape in the for loop, when we call name(), it knows that Circle should call the name() method of the Circle class, The Square object should call the name() method of the Square class.

The difference between an interface and an abstract class

Okay, you should have everything figured out about interfaces. Now back to that comment from spring, summer, fall and winter, “Tell me, brother, the difference between an abstract class and an interface?”

1) Grammar level

  • Public and protected methods cannot be used in interfaces, they can be used in abstract classes.
  • A variable in an interface can only be an implicit constant, and an abstract class can have variables of any type.
  • A class can inherit only one abstract class, but can implement multiple interfaces.

2) Design level

Abstract class is a kind of abstraction of class, the class inheriting abstract class and abstract class itself is an IS-A relationship.

An interface is an abstraction of the behavior of a class. There is no strong relationship between the interface and the class. All classes can implement the Serializable interface, thus having serialization functionality.

That’s all, and I’m sure the interviewer won’t give you a hard time.

Java inheritance

In Java, a class can inherit from another class or implement multiple interfaces, which I think most readers already know. Another thing that I’m not sure you know is that an interface can inherit from another interface, as follows:

public interface OneInterface extends Cloneable {}Copy the code

What’s the good of that? As I’m sure some readers have guessed, classes that implement the OneInterface interface can also use the object.clone () method.

public class TestInterface implements OneInterface {
    public static void main(String[] args) throws CloneNotSupportedException {
        TestInterface c1 = newTestInterface(); TestInterface c2 = (TestInterface) c1.clone(); }}Copy the code

In addition, we can define other abstract methods (such as deep copy) in the OneInterface interface to provide functionality that Cloneable does not.

public interface OneInterface extends Cloneable {
    void deepClone(a);
}
Copy the code

See? This is the benefit of inheritance: the child interface has the methods of the parent interface, causing the child interface to have the same behavior as the parent interface; At the same time, the subinterface can also freely play on this basis, add their own behavior.

Above, replace “interface” with “class”, the conclusion also holds. Let’s define a common parent class, Wanger:

public class Wanger {
    int age;
    String name;
    void write(a) {
        System.out.println("I wrote the Count of Monte Cristo."); }}Copy the code

We then define a subclass, Wangxiaoer, that extends from its parent class, Wanger, using the extends keyword:

public class Wangxiaoer extends Wanger{
    @Override
    void write(a) {
        System.out.println("I wrote La Traviata."); }}Copy the code

We can put common methods and member variables in the parent class to achieve the purpose of code reuse; Special methods and member variables are then placed in subclasses, in addition to which subclasses can override methods of the parent class (such as the write() method). In this way, subclasses take on new life.

Java supports only single inheritance, which I mentioned in my last article on interfaces. If a class is defined without the extends keyword, it implicitly inherits the Java.lang. Object class — which, in my opinion, is the real reason Java is called an Object of everything.

So what exactly does a subclass inherit from its parent?

Subclasses can inherit non-private member variables from their parent class. To verify this, let’s look at the following example.

public class Wanger {
    String defaultName;
    private String privateName;
    public String publicName;
    protected String protectedName;
}
Copy the code

The parent Wanger class defines four types of member variables: defaultName, private privateName, public publicName, and Protected protectedName.

Define a test method testVariable() in subclass Wangxiaoer:

You can confirm that all three types of member variables can be inherited, except for the private privateName.

Similarly, subclasses can inherit non-private methods from their parent class. To verify this, let’s look at the following example.

public class Wanger {
    void write(a) {}private void privateWrite(a) {}public void publicWrite(a) {}protected void protectedWrite(a) {}}Copy the code

The parent Wanger class defines four types of methods: default write, private privateWrite(), public publicWrite(), and Protected protectedWrite().

Define a main method in subclass Wangxiaoer and create a new subclass object using the new keyword: Wangxiaoer

You can confirm that all three types of methods can be inherited, except for the private privateWrite().

However, subclasses cannot inherit the constructor of their parent class. If the constructor of the parent class takes parameters, the code looks like this:

public class Wanger {
    int age;
    String name;

    public Wanger(int age, String name) {
        this.age = age;
        this.name = name; }}Copy the code

You must explicitly call the super keyword in the constructor of the subclass, otherwise the compiler will prompt the following error:

The repaired code looks like this:

public class Wangxiaoer extends Wanger{
    public Wangxiaoer(int age, String name) {
        super(age, name); }}Copy the code

Is-a is an obvious feature of inheritance, which means that the object reference type of a subclass can be a superclass type.

public class Wangxiaoer extends Wanger{
    public static void main(String[] args) {
        Wanger wangxiaoer = newWangxiaoer(); }}Copy the code

Similarly, the object reference type of the implementation class of a subinterface can also be a parent interface type.

public interface OneInterface extends Cloneable {}public class TestInterface implements OneInterface {
    public static void main(String[] args) {
        Cloneable c1 = newTestInterface(); }}Copy the code

Although a class can only inherit from one class, a class can implement multiple interfaces, as I mentioned in my last article. In addition, I mentioned that after Java 8, the default method can be defined in the interface, which is convenient, but also introduces new problems:

If a class implements multiple interfaces that define a default method with the same signature, the class overrides the method or the compilation fails.

FlyInterface is a flying interface with a default method signed sleep() :

public interface FlyInterface {
    void fly(a);
    default void sleep(a) {
        System.out.println("Sleeping fly"); }}Copy the code

RunInterface is a running interface that also has a default method signed sleep() :

public interface RunInterface {
    void run(a);
    default void sleep(a) {
        System.out.println("Sleep run."); }}Copy the code

The Pig class implements both FlyInterface and RunInterface, but compilation errors occur.

The default method was originally designed to provide a default implementation for classes that implement the interface without overriding the method. Now, the sleep() method signed by the same method confuses the compiler and has to be rewritten.

public class Pig implements FlyInterface.RunInterface {

    @Override
    public void fly(a) {
        System.out.println("Flying pigs.");
    }

    @Override
    public void sleep(a) {
        System.out.println("It has to be rewritten.");
    }

    @Override
    public void run(a) {
        System.out.println("Pigs that can run."); }}Copy the code

Although classes cannot inherit from multiple classes, interfaces can inherit from multiple interfaces, which I do not know if I have touched the knowledge blind area of some readers.

public interface WalkInterface extends FlyInterface.RunInterface{
    void walk(a);
}
Copy the code

12. This keyword

In Java, the this keyword refers to a reference to the current object whose method is being called. If you don’t understand, let’s move on.

If you don’t understand, come over and punch me, I promise not to fight back, as long as you don’t hit your face.

01. Disambiguate fields

I would bet a dime that all readers, young and old, will know this usage, since they write constructors all the time. Who does not know, come here, I give you a dime red envelope, as long as you have thick skin.

public class Writer {
    private int age;
    private String name;

    public Writer(int age, String name) {
        this.age = age;
        this.name = name; }}Copy the code

The Writer class has two member variables, age and name. When using a parameterized constructor, if the parameter name is the same as the name of the member variable, use this keyword to disambiguate: this.age refers to the member variable, and age refers to the constructor parameter.

Other constructors for reference classes

When a class has multiple constructors that intersect, you can use the this keyword to call different constructors to reduce the amount of code.

For example, calling a parameterized constructor from a parameterless constructor:

public class Writer {
    private int age;
    private String name;

    public Writer(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public Writer(a) {
        this(18."Silent King II."); }}Copy the code

A no-parameter constructor can also be called from a parameterized constructor:

public class Writer {
    private int age;
    private String name;

    public Writer(int age, String name) {
        this(a);this.age = age;
        this.name = name;
    }

    public Writer(a) {}}Copy the code

Note that this() must be the first statement in the constructor, or an error will be reported.

03. Pass as a parameter

In the following example, we have a constructor with no arguments that calls the print() method and takes only the this keyword.

public class ThisTest {
    public ThisTest(a) {
        print(this);
    }

    private void print(ThisTest thisTest) {
        System.out.println("print " +thisTest);
    }

    public static void main(String[] args) {
        ThisTest test = new ThisTest();
        System.out.println("main "+ test); }}Copy the code

Let’s print the result:

print com.cmower.baeldung.this1.ThisTest@573fd745
main com.cmower.baeldung.this1.ThisTest@573fd745
Copy the code

As you can see from the result, this is the ThisTest object we created in the main() method using the new keyword.

04. Chain call

For those of you who have learned JavaScript or jQuery, you may be familiar with chained calls, similar to a.b().c().d(), which seem to go on forever.

In Java, the proper name for this is The Builder pattern. Take a look at an example.

public class Writer {
    private int age;
    private String name;
    private String bookName;
    
    public Writer(WriterBuilder builder) {
        this.age = builder.age;
        this.name = builder.name;
        this.bookName = builder.bookName;
    }

    public static class WriterBuilder {
        public String bookName;
        private int age;
        private String name;

        public WriterBuilder(int age, String name) {
            this.age = age;
            this.name = name;
        }

        public WriterBuilder writeBook(String bookName) {
            this.bookName = bookName;
            return this;
        }

        public Writer build(a) {
            return new Writer(this); }}}Copy the code

The Writer class has three member variables, age, name, and bookName, and a corresponding constructor that takes an internal static class, WriterBuilder.

The WriterBuilder constructor has three member variables, the same as the WriterBuilder constructor. The WriterBuilder constructor has only age and name. Another member variable, bookName, is assigned via a separate method, writeBook(). Note that this method returns WriterBuilder and returns this with return.

The final build() method creates a Writer object, taking the this keyword, which is the current WriterBuilder object.

In this case, the Writer object can be created through chain calls.

Writer writer = new Writer.WriterBuilder(18."Silent King II.")
                .writeBook("The Road to Full Stack Development for the Web")
                .build();
Copy the code

Access external class objects from inner classes

To be honest, since the advent of functional programming in Java 8, this has rarely been used to access external class objects from an inner class. Take a look at an example:

public class ThisInnerTest {
    private String name;
    
    class InnerClass {
        public InnerClass(a) {
            ThisInnerTest thisInnerTest = ThisInnerTest.this; String outerName = thisInnerTest.name; }}}Copy the code

In the constructor of the InnerClass, we get the outer class object from the.this class, and then we can use the member variables of the outer class, such as name.

The super keyword

In short, the super keyword is used to access the parent class.

First, the parent class:

public class SuperBase {
    String message = "Parent";

    public SuperBase(String message) {
        this.message = message;
    }

    public SuperBase(a) {}public void printMessage(a) { System.out.println(message); }}Copy the code

Let’s look at subclasses:

public class SuperSub extends SuperBase {
    String message = "Child";

    public SuperSub(String message) {
        super(message);
    }

    public SuperSub(a) {
        super.printMessage();
        printMessage();
    }

    public void getParentMessage(a) {
        System.out.println(super.message);
    }

    public void printMessage(a) { System.out.println(message); }}Copy the code

1) The super keyword can be used to access the constructor of the parent class

You see, subclasses can call the constructor of their parent class with super(message). Now create a new SuperSub object and see what the output looks like:

SuperSub superSub = new SuperSub("Subclass message");
Copy the code

The new keyword initializes the message of the parent class through the super keyword when the constructor is called to create the subclass object, so the message of the parent class will output “message of the subclass”.

2) The super keyword can access variables of the parent class

In the SuperSub class in the example above, getParentMessage() passes the message member variable of the same name from the super.message method’s parent.

3) When a method is overwritten, the super keyword can access a method of the same name in the parent class

As in the SuperSub class in the example above, the no-argument constructor SuperSub() calls the parent’s method of the same name with super.printMessage().

Rewrite and overloading

Let’s start with a piece of rewritten code.

class LaoWang{
    public void write(a) {
        System.out.println("Old Wang wrote the Count of Monte Cristo."); }}public class XiaoWang extends LaoWang {
    @Override
    public void write(a) {
        System.out.println("Xiao Wang wrote La Traviata."); }}Copy the code

The two methods overridden have the same name and the same number of method parameters; But one method is in the parent class and the other is in the child class. As if the parent class LaoWang had a write() method (with no arguments) whose body was to write a book called the Count of Monte Cristo; * subclass XiaoWang () rewrite write();

Let’s write some test code.

public class OverridingTest {
    public static void main(String[] args) {
        LaoWang wang = newXiaoWang(); wang.write(); }}Copy the code

Guess what?

Xiao Wang wrote La TraviataCopy the code

In the above code, we declare a variable wang of type LaoWang. During compilation, the compiler checks to see if the LaoWang class contains a write() method. It finds that the LaoWang class does, and the compilation passes. At runtime, new a XiaoWang object and assign it to Wang, at which point the Java virtual machine knows that Wang refers to XiaoWang. The write() method of subclass XiaoWang is called instead of the write() method of parent class LaoWang, so the output result is “XiaoWang wrote a book of La Traviata”.

Let’s look at one more piece of overloaded code.

class LaoWang{
    public void read(a) {
        System.out.println("Lao Wang read a book called The Road to Progress in Web Full-stack Development.");
    }
    
    public void read(String bookname) {
        System.out.println(Lao Wang read a copy of" + bookname + "" "); }}Copy the code

The overloaded two methods have the same name, but different numbers of method arguments, and there is no inheritance involved. The two methods are in the same class. It is as if the class LaoWang has two methods named read(), but one takes arguments (the title of the book) and the other does not (can only read and write a dead book).

Let’s write some test code.

public class OverloadingTest {
    public static void main(String[] args) {
        LaoWang wang = new LaoWang();
        wang.read();
        wang.read("Golden Vase plum"); }}Copy the code

That’s a no-brainer. The variable wang is of type LaoWang, and wang.read() invokes the read() method with no arguments. Wang. Read (” Jin Ping Mei “) invokes the read(bookname) method with reference, so it outputs “Lao Wang read a book of Jin Ping Mei”. At compile time, the compiler knows that the two read() methods are different because their method signatures (= method names + method parameters) are different.

To summarize briefly:

1) The compiler cannot decide which overridden method to call because the type of the variable is not determinable at runtime; But the compiler knows exactly which overloaded method to call because the reference type is fixed and the number of arguments determines which method to call.

2) Polymorphism targets overwriting, not overloading.

Ah, regret ah, in the early years if I can understand this interview question, also need not be made difficult by old horse. Sing a poem about your life.

The sunflower in the green garden, the morning dew and the sunrise. Spring budeze, all things give birth to brilliance. Often fear autumn festival to, kun Huanghua leaf failure. Hundred sichuan east to the sea, when to return to the west? A young idler, an old beggar.

In addition, I would like to tell you that Override and Overload are two very important concepts in Java. Beginners often get confused by them because their English names are so similar that the Chinese translation is only one word short. Hard, too hard.

Static keyword

Let me start by outlining:

The static keyword can be used for variables, methods, code blocks, and inner classes to indicate that a particular member belongs only to the class itself, and not to an object of that class.

01. Static variables

A static variable is also called a class variable. It belongs to a class, not an object of that class.

public class Writer {
    private String name;
    private int age;
    public static int countOfWriters;

    public Writer(String name, int age) {
        this.name = name;
        this.age = age;
        countOfWriters++;
    }

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge(a) {
        return age;
    }

    public void setAge(int age) {
        this.age = age; }}Copy the code

CountOfWriters is called a static variable, which is distinct from the name and age member variables because it is preceded by the modifier static.

This means that no matter how many times the class is initialized, the value of the static variable is shared among objects of all classes.

Writer w1 = new Writer("Silent King II.".18);
Writer w2 = new Writer("Silent King three.".16);

System.out.println(Writer.countOfWriters);
Copy the code

By that logic, you should be able to deduce that countOfWriters should be written with a 2 instead of a 1. From a memory perspective, static variables will be stored in a specific pool in the Java virtual machine called “Metaspace” (meta-space, after Java 8).

Static variables are very different from member variables. The value of a member variable belongs to an object and is not shared between different objects. A static variable is not. It can be used to count the number of objects because it is shared. Like countOfWriters in the example above, it has a value of 1 when one object is created and 2 when two objects are created.

A quick summary:

1) Since static variables belong to a class, they should be accessed directly by the class name rather than by an object reference;

2) Access static variables without initializing the class.

public class WriterDemo {
    public static void main(String[] args) {
        System.out.println(Writer.countOfWriters); / / 0}}Copy the code

02. Static methods

Static methods, also known as class methods, are similar to static variables in that they belong to a class rather than an object of that class.

public static void setCountOfWriters(int countOfWriters) {
    Writer.countOfWriters = countOfWriters;
}
Copy the code

SetCountOfWriters () is a static method decorated with the static keyword.

If you’ve ever worked with the Java.lang. Math class or some of Apache’s utility classes (such as StringUtils), static methods will be familiar.

Almost all of the methods of the Math class are static and can be invoked directly from the class name, without the need to create an object for the class.

A quick summary:

1) Static methods in Java are resolved at compile time because static methods cannot be overridden (method overwriting occurs at run time, for polymorphism).

2) Abstract methods cannot be static.

3) Static methods cannot use this and super keywords.

4) Member methods can directly access other member methods and member variables.

Member methods can also directly method static methods and static variables.

6) Static methods can access all other static methods and static variables.

7) Static methods cannot directly access member methods and variables.

Static code blocks

Static blocks of code can be used to initialize static variables, although static methods can also be initialized directly at declaration time, but sometimes we need more than one line of code to complete the initialization.

public class StaticBlockDemo {
    public static List<String> writes = new ArrayList<>();

    static {
        writes.add("Silent King II.");
        writes.add("Silent King three.");
        writes.add("The Silent King iv.");

        System.out.println("The first piece");
    }

    static {
        writes.add("The Silent Five.");
        writes.add("The Sixth King of Silence.");

        System.out.println("The second piece"); }}Copy the code

Writes is a static ArrayList, so it’s unlikely to be initialized at declaration time, so it needs to be initialized in a static block of code.

A quick summary:

1) A class can have more than one static code block.

2) Static code blocks are parsed and executed in the same order as their position in the class. To verify this, add an empty main method to the StaticBlockDemo class, and the result will look like this:

The first piece, the second pieceCopy the code

Static inner class

Java allows us to declare an inner class within a class, which provides a compelling way to use a few variables in just one place, making code more organized and readable.

There are four common inner classes: member inner class, local inner class, anonymous inner class and static inner class. Due to space reasons, the first three are not covered in this article, but will be discussed in more detail later.

public class Singleton {
    private Singleton(a) {}

    private static class SingletonHolder {
        public static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance(a) {
        returnSingletonHolder.instance; }}Copy the code

This is a way to create a Singleton. Instance is not initialized when the Singleton class is first loaded. The Java virtual machine starts loading the SingletonHolder and initializing instance only when the getInstance() method is called for the first time, ensuring not only thread-safety but also the uniqueness of the Singleton class. However, a more elegant way to create singletons is to use enumerations.

A quick summary:

1) A static inner class cannot access all member variables of the outer class.

2) Static inner classes can access all static variables of external classes, including private static variables.

3) External classes cannot be declared static.

Java enumeration

To cut to the quick, enum is a keyword introduced in Java 1.5 that represents a special type of class that inherits by default from java.lang.enum.

To prove this, let’s create a new enumerated PlayerType:

public enum PlayerType {
    TENNIS,
    FOOTBALL,
    BASKETBALL
}
Copy the code

Two keywords with a class name, curly braces, and three uppercase words. Don’t worry. A watched pot never boils. A look at the decompiled bytecode using JAD makes it crystal clear.

public final class PlayerType extends Enum
{

    public static PlayerType[] values()
    {
        return (PlayerType[])$VALUES.clone();
    }

    public static PlayerType valueOf(String name)
    {
        return (PlayerType)Enum.valueOf(com/cmower/baeldung/enum1/PlayerType, name);
    }

    private PlayerType(String s, int i)
    {
        super(s, i);
    }

    public static final PlayerType TENNIS;
    public static final PlayerType FOOTBALL;
    public static final PlayerType BASKETBALL;
    private static final PlayerType $VALUES[];

    static 
    {
        TENNIS = new PlayerType("TENNIS".0);
        FOOTBALL = new PlayerType("FOOTBALL".1);
        BASKETBALL = new PlayerType("BASKETBALL".2);
        $VALUES = (newPlayerType[] { TENNIS, FOOTBALL, BASKETBALL }); }}Copy the code

See yet? The PlayerType class is final and inherits from the Enum class. We programmers don’t do this work, the compiler does it for us quietly. In addition, it comes with several useful static methods, such as values() and valueOf(String name).

01, internal enumeration

Okay, so you guys already know what enumerations look like? Since enumeration is a special class, it can be defined inside a class so that its scope can be restricted to the external class.

public class Player {
    private PlayerType type;
    public enum PlayerType {
        TENNIS,
        FOOTBALL,
        BASKETBALL
    }
    
    public boolean isBasketballPlayer(a) {
      return getType() == PlayerType.BASKETBALL;
    }

    public PlayerType getType(a) {
        return type;
    }

    public void setType(PlayerType type) {
        this.type = type; }}Copy the code

PlayerType is the equivalent of a Player’s inner class, and the isBasketballPlayer() method is used to determine if a Player is a basketball Player.

Since enumerations are final, ensuring that there is only one constant object in the Java virtual machine (see the decomcompiled static block “static keyword with curly braces”), we can safely use the “==” operator to compare two enumerations for equality. See isBasketballPlayer().

So why not use equals()?

if(player.getType().equals(Player.PlayerType.BASKETBALL)){};
if(player.getType() == Player.PlayerType.BASKETBALL){};
Copy the code

When the “==” operator compares two objects that are both null, NullPointerException does not occur, as does equals().

In addition, the “==” operator checks at compile time and gives an error if the types on both sides do not match, whereas the equals() method does not.

02. Enumeration can be used in switch statements

I explained this in detail in my previous article. If you are interested, you can click the link to jump to the past and have a look.

switch (playerType) {
        case TENNIS:
            return "Federer the Tennis player.";
        case FOOTBALL:
            return "Cristiano Ronaldo, soccer player.";
        case BASKETBALL:
            return "James the Basketball Player";
        case UNKNOWN:
            throw new IllegalArgumentException("Unknown");
        default:
            throw new IllegalArgumentException(
                    "Type of athlete:" + playerType);

    }
Copy the code

Enumerations can have constructors

If the enumeration needs to contain more information, you can add fields to it, such as Name in the following example. In this case, you need to add a constructor with parameters to the enumeration so that the corresponding name can be added when the enumeration is defined.

public enum PlayerType {
    TENNIS("Tennis"),
    FOOTBALL("Football"),
    BASKETBALL("Basketball");

    private String name;

    PlayerType(String name) {
        this.name = name; }}Copy the code

04, enumsets

EnumSet is an implementation class for the Set interface for enumeration types. It is a very efficient tool for handling enumeration data (the internal implementation is bit vectors, which I don’t understand).

Because EnumSet is an abstract class, you cannot use the new keyword when creating EnumSet. However, EnumSet provides a number of useful static factory methods:

The following example uses noneOf() to create an empty EnumSet of PlayerType; Use allOf() to create an EnumSet containing all playerTypes.

public class EnumSetTest {
    public enum PlayerType {
        TENNIS,
        FOOTBALL,
        BASKETBALL
    }

    public static void main(String[] args) { EnumSet<PlayerType> enumSetNone = EnumSet.noneOf(PlayerType.class); System.out.println(enumSetNone); EnumSet<PlayerType> enumSetAll = EnumSet.allOf(PlayerType.class); System.out.println(enumSetAll); }}Copy the code

The program output is as follows:

[]
[TENNIS, FOOTBALL, BASKETBALL]
Copy the code

With EnumSet in place, we can use some of the methods of Set:

05, EnumMap

EnumMap is an implementation class for the Map interface for enumeration types that can use enumeration constants as keys. EnumMap is even more efficient than HashMap, and elements can be accessed directly by array subscript (ordinal value of enumeration).

Unlike EnumSet, EnumMap is not an abstract class, so the new keyword can be used to create EnumMap:

EnumMap<PlayerType, String> enumMap = new EnumMap<>(PlayerType.class);
Copy the code

Once you have the EnumMap object, you can use some of the Map methods:

In much the same way as using HashMap, consider the following example:

EnumMap<PlayerType, String> enumMap = new EnumMap<>(PlayerType.class);
enumMap.put(PlayerType.BASKETBALL,"Basketball player");
enumMap.put(PlayerType.FOOTBALL,"Football player.");
enumMap.put(PlayerType.TENNIS,"Tennis player.");
System.out.println(enumMap);

System.out.println(enumMap.get(PlayerType.BASKETBALL));
System.out.println(enumMap.containsKey(PlayerType.BASKETBALL));
System.out.println(enumMap.remove(PlayerType.BASKETBALL));
Copy the code

The program output is as follows:

{TENNIS= TENNIS player, FOOTBALL= FOOTBALL player, BASKETBALL= BASKETBALL playertrueBasketball playerCopy the code

06, singleton

In general, implementing a singleton is not an easy task. Take a look at this code

public class Singleton {  
    private volatile static Singleton singleton; 
    private Singleton (a){}  
    public static Singleton getSingleton(a) {  
    if (singleton == null) {
        synchronized (Singleton.class) { 
        if (singleton == null) {  
            singleton = newSingleton(); }}}returnsingleton; }}Copy the code

But enumerations reduce the code to the extreme:

public enum EasySingleton{
    INSTANCE;
}
Copy the code

We’re done. It was super short, wasn’t it? Enumeration implements the Serializable interface by default, so the Java VIRTUAL machine can guarantee that the class is a singleton, unlike the traditional implementation. Traditionally, we had to ensure that singletons could not create any new instances during deserialization.

07. Enumerations interact with databases

We can work with Mybatis to convert database fields to enumerated types. Now suppose we have a database field check_type of the following type:

`check_type` int(1) DEFAULT NULL COMMENT 'Check type (1: failed, 2: passed)'.Copy the code

Its corresponding enumeration type is CheckType and the code is as follows:

public enum CheckType {
	NO_PASS(0."Failed"), PASS(1."通过");
	private int key;

	private String text;

	private CheckType(int key, String text) {
		this.key = key;
		this.text = text;
	}

	public int getKey(a) {
		return key;
	}

	public String getText(a) {
		return text;
	}

	private static HashMap<Integer,CheckType> map = new HashMap<Integer,CheckType>();
	static {
		for(CheckType d : CheckType.values()){ map.put(d.key, d); }}public static CheckType parse(Integer index) {
		if(map.containsKey(index)){
			return map.get(index);
		}
		return null; }}Copy the code

Select * from CheckType where key = int and text = String;

CheckType parse(Integer index) public static CheckType parse(Integer index) converts an Integer to an enumerated type by matching the key.

So now we can use typeHandler in the Mybatis configuration file to convert database fields to enumerated types.

<resultMap id="CheckLog" type="com.entity.CheckLog">
  <id property="id" column="id"/>
  <result property="checkType" column="check_type" typeHandler="com.CheckTypeHandler"></result>
</resultMap>
Copy the code

The class corresponding to the checkType field is as follows:

public class CheckLog implements Serializable {

    private String id;
    private CheckType checkType;

    public String getId(a) {
        return id;
    }

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

    public CheckType getCheckType(a) {
        return checkType;
    }

    public void setCheckType(CheckType checkType) {
        this.checkType = checkType; }}Copy the code

The CheckTypeHandler converter class source code is as follows:

public class CheckTypeHandler extends BaseTypeHandler<CheckType> {

	@Override
	public CheckType getNullableResult(ResultSet rs, String index) throws SQLException {
		return CheckType.parse(rs.getInt(index));
	}

	@Override
	public CheckType getNullableResult(ResultSet rs, int index) throws SQLException {
		return CheckType.parse(rs.getInt(index));
	}

	@Override
	public CheckType getNullableResult(CallableStatement cs, int index) throws SQLException {
		return CheckType.parse(cs.getInt(index));
	}

	@Override
	public void setNonNullParameter(PreparedStatement ps, int index, CheckType val, JdbcType arg3) throws SQLException { ps.setInt(index, val.getKey()); }}Copy the code

The core function of CheckTypeHandler is to convert database fields by calling the Parse () method of the CheckType enumeration class.

With all due respect, I think my friends are sure to use Java enumeration, if not, come and hack me!

The final keyword

Although inheritance allows us to reuse existing code, there are times when we really need to limit extensibility for some reason, and the final keyword can help us do that.

01, final class

If a class uses the final keyword modifier, it cannot be inherited. If you look carefully, Java has many final classes, such as the most common String class.

public final class String
    implements java.io.Serializable.Comparable<String>, CharSequence.Constable.ConstantDesc {}
Copy the code

Why is the String class designed to be final? There are three reasons for this:

  • To implement a string constant pool
  • For thread safety
  • For immutability of HashCode

For more details on why, check out an article I wrote earlier.

Any attempt to inherit from a final class will result ina compilation error. To verify this, let’s look at the following example, where the Writer class is final.

public final class Writer {
    private String name;

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name; }}Copy the code

If you try to inherit it, the compiler will tell you that the Writer class is final and cannot be inherited.

However, just because a class is final does not mean that its objects are immutable.

Writer writer = new Writer();
writer.setName("Silent King II.");
System.out.println(writer.getName()); // The King of Silence
Copy the code

The default value of Writer’s name field is NULL, but it can be changed to Silent King ii via settter method. That is, if a class is only final, it is not all that is immutable.

If you want to know the whole truth about immutable classes, check out my previous post about immutable classes. Suddenly, I realized that writing a series of articles is really good, so many related concepts are covered. I really surprised myself.

There are security reasons for making a class final, but this should not be done intentionally, because defining a class as final means that it cannot be inherited, and if there are problems with some of the class’s methods, we cannot rewrite them to fix them.

02. Final methods

Methods decorated with final cannot be overridden. If we’re designing a class and we think that some method shouldn’t be overridden, we should make it final.

The Thread class is an example. It is not final itself, which means we can extend it, but its isAlive() method is final:

public class Thread implements Runnable {
    public final native boolean isAlive(a);
}
Copy the code

It is important to note that this method is a native method used to verify that the thread is active. The local method is determined by the operating system, so overriding it is not easy.

The Actor class has a final method show() :

public class Actor {
    public final void show(a) {}}Copy the code

When we try to override this method, we get a compilation error:

If certain methods ina class are called by other methods, consider that the method being called is final; otherwise, overwriting the method will affect the use of the calling method.

What is the difference between a class that is final and a class that is not final, but all of its methods are final?

One thing I can think of is that the former can’t be inherited, which means methods can’t be overridden; The latter can be inherited and appended with non-final methods. Is it all right? Look how smart I am.

03. Final variables

Variables modified by final cannot be reassigned. In other words, a final variable, once initialized, cannot be changed. I was asked by a friend before, what is effective final and what is final? I have also explained this point in the previous article, so here is the address:

www.itwanger.com/java/2020/0…

1) The base data type of the final modifier

To declare a final variable of type int:

final int age = 18;
Copy the code

Try changing it to 30 and the compiler gets angry:

2) Final modifier reference type

We now have a normal Pig class that has a field name:

public class Pig {
   private String name;

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name; }}Copy the code

Declare a final modified Pig object in the test class:

 final Pig pig = new Pig();
Copy the code

The compiler also gets angry if it tries to reassign pig:

We can still modify the Pig field:

final Pig pig = new Pig();
pig.setName("Maverick");
System.out.println(pig.getName()); // Be a maverick
Copy the code

3) final

Final fields can be static or non-static, as in the following:

public class Pig {
   private final int age = 1;
   public static final double PRICE = 36.5;
}
Copy the code

Non-static final fields must have a default value, otherwise the compiler will warn that there is no initialization:

Static final fields, also called constants, should have uppercase names and can be initialized at declaration time or through static code blocks.

  1. Final modifier

The final keyword can also modify parameters, which means that parameters cannot be modified within the method body:

public class ArgFinalTest {
    public void arg(final int age) {}public void arg1(final String name) {}}Copy the code

If you try to modify it, the compiler prompts the following error:

.

Follow-up will continue to update, but some partners may not be able to help, this little white manual has no PDF version can white piao ah, that must have ah, directly “silent King 2” public account background reply “little white” can, don’t be soft, feel good, please share more — give a person rose, hand has lingering fragrance oh.

If not, scan the QR code above, and reply “xiao Bai”.

I am the Silent King 2, a programmer with good looks but mediocre talent. Attention can improve learning efficiency, don’t forget three even ah, like, collect, message, I don’t pick, hee hee.