Hey guys, here is a programmer cxuan, welcome you to my latest article, this article I added some contents about the Java core basis, modified the part wrong character and statement is not smooth, and internal classes, such as generic content was added, and in my article gives some links in some places, These links are all hardcore articles I wrote myself, which can better help you understand the Java language, so no more nonsense, the body begins.

Java overview

What is Java?

Java is a programming language and computing platform first released by Sun Microsystems in 1995. Programming languages are relatively easy to understand, but what are computing platforms?

A computing platform is the environment in which applications (software) run on a computer, both hardware and software. A general system platform includes a computer’s hardware architecture, operating system, and runtime library.

Java is fast, secure and reliable. From laptops to data centers, from game consoles to scientific supercomputers, from mobile phones to the Internet, Java is everywhere! Java is divided into three main versions:

  • JavaSE(J2SE)(Java Platform Standard Edition)

JavaSE is the foundation of JavaEE and JavaME, which is based on the JDK and JRE, and includes classes that support Java Web services development

  • JavaEE(J2EE)(Java 2 Platform,Enterprise Edition, Java Platform Enterprise Edition)

JavaEE, originally called J2EE and later renamed JavaEE, is an extension of JavaSE, a version of our enterprise-level development that includes some Java Web toolkits.

  • JavaME(J2ME)(Java 2 Platform Micro Edition)

JavaME is typically used to provide a robust and flexible environment for applications running on mobile and embedded devices such as cell phones, PDAs, TV set-top boxes, and printers.

The characteristics of the Java

  • Java is a doorobject-orientedProgramming language

What is object orientation? Object Oriented is a software development idea. It is an abstraction of the real world, and object orientation organizes related data and methods into a holistic view.

The opposite of that is process oriented development. What is process oriented? Procedure Oriented is a process – centered programming idea.

Another example: If you are a student, how many things do you need to do to go to school every day?

Get up, get dressed, wash your face and brush your teeth, eat, go to school. Usually a sequence of actions is performed sequentially.

class student {
		void student_wakeUp(a){... }void student_cloth(a){... }void student_wash(a){... }void student_eating(a){... }void student_gotoSchool(a){...}
}
Copy the code

And object orientation can abstract the student, so this example will become

class student(a){
  	void wakeUp(a){... }void cloth(a){... }void wash(a){... }void eating(a){... }void gotoSchool(a){...}
}
Copy the code

You can perform each action in a different order. That’s characteristic number one.

  • Java eliminates the concepts of multiple inheritance, Pointers, and memory management that are difficult to understand in C++. There is no need to manually manage the life cycle of an object, which is characteristic two.
  • Java language has two characteristics of powerful and easy to use, now enterprise development, rapid and agile development, especially the emergence of various frameworks, make Java become more and more popular a language. This is characteristic number three.
  • Java is a static language. A static language is one in which data types are known at compile time, checked for correctness before execution, and cannot be changed once they are determined, as in this example.
public void foo(a) {
    int x = 5;
    boolean b = x;
}
Copy the code

Static languages include Pascal, Perl, C/C++, JAVA, C#, Scala, etc.

In contrast, dynamic languages do not have any specific situation where you need to specify the type of a variable, the data type determined at run time. Lisp, Perl, Python, Ruby, JavaScript, etc.

From a design point of view, all languages are designed to translate human-readable code into machine instructions. Below is a map of language classification.

Dynamic languages are designed to allow programmers to code more efficiently, so you can use less code to implement features. Static language design is designed to make hardware execution more efficient, so programmers need to write accurate code to make your code execute as quickly as possible. From this point of view, static languages are more efficient and faster than dynamic languages. This is characteristic four.

  • Java is platform independent and portable

Java has a famous slogan: Write once, run Anywhere. Write once, run anywhere. Why is Java able to make this kind of noise? The core is the JVM. We know that a lot of details are hidden between computer applications and hardware, and they rely on the operating system for scheduling and coordination between them. The rough architecture is as follows

Then with Java applications, the JVM architecture becomes the following

Java is cross-platform, and compiled Java programs can run on any platform with a JVM. You can write code on Windows and run it on Linux. How do you do that?

First you need to write Java code in your application;

Compile Java code into.class files using Eclipse or Javac;

Then type your.class file into a.jar file;

Then your.jar file will run on Windows, Mac OS X, and Linux. Different operating systems have different JVM implementations, so there is no need to compile your Java code again when switching platforms. This is characteristic number five.

  • Java can easily implement multithreading

Java is a high-level language, and high-level languages shield users from many of the low-level implementation details. For example, how Java implements multithreading. From the point of view of the operating system, there are several main ways to achieve multithreading

Implement multithreading in user space

Implement multithreading in kernel space

Mix implementation threads in user and kernel space

In my opinion, Java should be multithreaded in user space, and the kernel is unaware of the existence of multithreading in Java. This is characteristic six.

  • Java has high performance

The code we write, compiled by the JavAC compiler and called bytecode, is converted into machine code by an interpreter embedded in the JVM, which is interpreted execution, a less efficient process. However, some JVM implementations such as Hotspot JVM provide a Just-in-time (JIT) compiler, also known as a dynamic compiler 􏱆. The JIT can compile 􏲀 hot code into machine code at run Time, which is more efficient. So Java is more than just a language to explain execution. This is characteristic seven.

  • The Java language is robust

Java’s strong typing mechanism, exception handling and automatic garbage collection are important guarantees for the robustness of Java programs. This is an important difference between Java and C. This is characteristic eight.

  • Java makes it easy to develop distributed projects

Java language supports the development of Internet applications. There is NET API in Java, which provides class libraries for network application programming, including URL, URLConnection, Socket, ServerSocket and so on. Java’s RMI (Remote method activation) mechanism is also an important means of developing distributed applications. This is characteristic nine.

A small example illustrates the difference between face processing and object orientation

First, process oriented

In order to get the elephant into the fridge, it takes three steps.

Ideas:

1. Leave the fridge door open (get the fridge with the door open).

2. Put the elephant in (open the door and get the refrigerator with the elephant in it).

3, close the refrigerator door (after opening the door and loading the elephant, get a closed refrigerator).

According to the above thinking, it can be seen that each process has a phased goal, which can be completed in turn to put the elephant in the refrigerator.

Second, object-oriented

In order to get an elephant into the fridge, there are three actions (or behaviors). Every action has an actor, which is the object.

Ideas:

1, refrigerator, you open the door for me.

2, refrigerator, you put the elephant for me (or, elephant, you get me into the refrigerator).

Refrigerator, you close the door for me.

Do these in turn, and you can load the elephant.

Java Development environment

JDK

The Java Development Kit (JDK), known as the Java Development Kit or Java Development tool, is a program Development environment for writing Java Applet small programs and applications. The JDK is the core of Java, including the Java Runtime Environment (Java Runtime Environment), some Java tools, and Java’s core class libraries (Java apis).

We can take a close look at this Diagram, which includes almost all concepts in Java. I use JDK1.8. If you click on the Description of Java Conceptual Diagram, you can find that it contains all descriptions of Java.

Oracle provides two implementations of the Java platform, the Java Development Standard Toolkit (JDK) and the Java Runtime Environment (JRE). The JDK has much more functionality than the JRE.

JRE

The JRE is a runtime environment and the JDK is a development environment. So you need the JDK to write Java programs, and you need the JRE to run Java programs. The JDK already includes the JRE, so as long as the JDK is installed, you can edit Java programs and run them normally. However, because the JDK contains a lot of non-runtime content and takes up a lot of space, it is not necessary to install the JDK to run ordinary Java programs, but only the JRE can be installed.

Java development environment configuration

Here are some JDK installation and configuration blogs:

Download and install the Windows JDK

MAC version JDK download and installation

Basic Java Syntax

After configuring the Java development environment and downloading the Java development tools (Eclipse, IDEA, etc.), you are ready to write Java programs. Since this tutorial is to comb through the Java architecture from scratch, it is necessary to start with the basic concepts.

The data type

In Java, there are only four types and eight types of data types.

  • Integer types: byte, short, int, and long

Byte is a byte. 1 byte equals 8 bits. The default byte value is 0.

Short takes up two bytes (16 bits). 1 short = 16 bits, which also defaults to 0.

1 int = 32 bits, default is 0;

Long takes up eight bytes, that is, 64 bits, 1 long = 64 bits, default is 0L;

So the size of the integer is long > int > short > byte

  • floating-point

Floating-point types have two data types: float and double

1 float = 32 bits. The default value is 0.0f.

1 double = 64 bits. Default value: 0.0d;

  • character

The char type is a single 16-bit Unicode character with a minimum value of \u0000 (0) and a maximum value of \ uFFFF (65535). The char data type can store any character, such as char A = ‘a’.

  • The Boolean

Boolean refers to Boolean. Boolean has only two values, true or false, representing only one bit. The default value is false.

The above X bits refer to the memory usage.

Basic grammar

  • Case sensitive: Java is a case-sensitive language. For example, Hello is different from Hello, which is the Java string representation.
  • Class name: For all classes, the first letter should be capitalized, e.gMyFirstClass.
  • Package name: The package name should be lowercase as much as possible, for examplemy.first.package.
  • Method name: The first letter of the method name must be lowercase and each subsequent letter must be uppercase, for examplemyFirstMethod().

The operator

Operators are special symbols used for mathematical functions, some types of assignment statements, and logical comparisons. Let’s take Java as an example to look at operators.

  • The assignment operator

The assignment operator is represented by the operator =, which means to copy the value to the right of the = sign to the left. The value on the right can be any constant, variable, or expression, but the value on the left must be an explicit, defined variable. So int a is equal to 4.

For objects, however, it is not the value of the object that is copied, but the reference to the object, so if you copy an object to another object, you are actually assigning a reference to one object to another object.

  • Arithmetic operator

Arithmetic operators are similar to numerical calculations in mathematics

Arithmetic operators need to be aware of is the priority problem, when there are multiple operators in an expression, the priority order of operator determines the calculation order of the simplest rule is first, then add and subtract, (the) highest priority, there is no need to remember all the priority order of uncertain with () directly.

  • Increment and decrement operators

This does not explain the text, the explanation is not as clear as looking at examples directly

int a = 5;
b = ++a;
c = a++;
Copy the code
  • Comparison operator

Comparison operators are used to compare variables in a program, between variables and arguments, and other types of information.

The result of the comparison operator is Boolean. The result of the operation is true if the relation of the operator is true, false otherwise. There are six comparison operators, which are usually used in conditional statements.

  • Logical operator

There are three main types of logical operators, and, or, and not

Here is the true/false symbol table for the logical operators

  • Bitwise operators

Bitwise operators are used to operate on each bit in the basic type of integers, that is, binary bits. Bitwise operators perform Boolean algebra on the corresponding bits of the two arguments and ultimately produce a result.

If the two sides of the comparison are numbers, the comparison becomes bitwise.

Bitwise AND: The operation (AND) is performed bitwise. The result is 1 only if the middle bit of both operands is 1. Otherwise, the result is 0. You need to first convert both sides of the comparison to binary and then compare each bit

Bitwise OR: To operate OR (OR) by bitwise, so that if either of the two bits is 1, the result is 1, otherwise it is 0.

XOR by bit: XOR by bit, the result is 1 if the bit is 0 and 0 if the bit is 1.

Bitwise NOT: When the operation is carried out by bit (NOT), the result is 0 if the bits of two operands are the same and 1 if they are different.

  • Shift operator

The shift operator is used to move the operand in a direction (left or right) by a specified number of bits.

  • Ternary operator

Ternary operators are similar to if… else… This operator has the syntax: conditional expression? Expression 1: expression 2. The position in front of the question mark is the condition to determine if the result is Boolean. Expression 1 is called when it is true and expression 2 is called when it is false.

Java executes the control flow

Control flow in Java is actually the same as C. In Java, flow control involves if-else, while, do-while, for, return, break and the selection statement switch. Let’s analyze this.

Conditional statements

Conditional statement Different statements can be executed according to different conditions. Includes if conditional statements and switch multi-branch statements.

If conditional statement

The if statement can determine the result of an expression alone, indicating the execution result of the expression, for example:

int a = 10;
if(a > 10) {return true;
}
return false;
Copy the code

if… Else conditional statement

An if statement can also be used with an else, and usually behaves as if one condition is met, and another if not.

int a = 10;
int b = 11;
if(a >= b){
  System.out.println("a >= b");
}else{
  System.out.println("a < b");
}
Copy the code

The expression in () after if must be Boolean. If true, the compound statement after if is executed. If false, the compound statement after else is executed.

if… Else if multi-branch statement

The above if… Else is a single and two branch judgment. If there are multiple criteria, use if… Else if.

int x = 40;
if(x > 60) {
  System.out.println("X is greater than 60.");
} else if (x > 30) {
  System.out.println("X is greater than 30 but less than 60.");
} else if (x > 0) {
  System.out.println("X is greater than 0 but less than 30.");
} else {
  System.out.println("X is less than or equal to 0.");
}
Copy the code

Switch Case Multi-branch statement

Than a * * the if… A more elegant way to use the else if ** statement is to use the switch multi-branch statement, as shown in the following example:

switch (week) {
  case 1:
    System.out.println("Monday");
    break;
  case 2:
    System.out.println("Tuesday");
    break;
  case 3:
    System.out.println("Wednesday");
    break;
  case 4:
    System.out.println("Thursday");
    break;
  case 5:
    System.out.println("Friday");
    break;
  case 6:
    System.out.println("Saturday");
    break;
  case 7:
    System.out.println("Sunday");
    break;
  default:
    System.out.println("No Else");
    break;
}
Copy the code

Looping statements

A loop statement is an operation that executes an expression repeatedly under certain conditions until it satisfies the requirements of a loop statement. The loop statements used are **for, do… While (), while **.

While loop statement

The while loop uses a condition to control whether to continue executing the statement repeatedly. The format of the while loop statement is as follows:

while(Boolean value){expression}Copy the code

It means that when (Boolean) is true, we execute the following expression, and when (Boolean) is false, we end the loop. A Boolean is also an expression, such as:

int a = 10;
while(a > 5){
  a--;
}
Copy the code

do… The while loop

While with the do… The only difference in the while loop is do… The while statement is executed at least once, even if the expression is false the first time. In the while loop, if the condition is false the first time, the statement is not executed at all. In practice, while is better than do… While is more widely used. Its general form is as follows:

int b = 10;
// do···while loop
do {
  System.out.println("b == " + b);
  b--;
} while(b == 1);
Copy the code

For loop

The for loop is the most common type of loop that is initialized before the first iteration. It has the following form:

forInitialization; Boolean expression; Step by step) {}Copy the code

Boolean expressions are tested before each iteration. If the result is false, the code following the for statement is executed; At the end of each loop, the next loop is executed with the values of the step.

Comma operator

The one not to be ignored here is the comma operator, which is used only in Java for loop control statements. In the initialization part of an expression, you can use a series of comma-separated statements; With the comma operator, you can define multiple variables within a for statement, but they must have the same type.

for(int i = 1,j = i + 10; i <5; i++, j = j *2) {}Copy the code

For-each statements

A more concise way to iterate over arrays and collections was introduced in Java JDK 1.5, called the for-each statement:

int array[] = {7.8.9};

for (int arr : array) {
     System.out.println(arr);
}
Copy the code

Jump statements

In the Java language, there are three types of jump statements: break, continue, and return.

Break statement

The break statement we have seen in switch is used to terminate the loop. In fact, the break statement is used in the for, while, do···while loop statements to force out of the current loop, for example:

for(int i = 0; i <10; i++){if(i == 5) {break; }}Copy the code

The continue statement

Continue can also be placed in a loop statement. It has the opposite effect of the break statement. It is used to execute the next loop, not to exit the current loop.

for(int i = 0; i <10; i++){ System.out.printl(" i = " + i );
	if(i == 5){
    System.out.printl("continue ... ");
    continue; }}Copy the code

Return statement

A return statement can return from a method and give control to the calling statement.

public void getName(a) {
    return name;
}
Copy the code

object-oriented

Object-oriented learning Java is a very important development ideas, but object-oriented is not unique to Java ideas, here we do not get confused.

Let’s talk about object-oriented thinking, which has gradually replaced procedural thinking. Java is an object-oriented high-level programming language, and object-oriented languages have the following characteristics

  • Object oriented is a common idea, which is in line with people’s thinking habits.

  • Object orientation can simplify complex business logic and enhance code reuse.

  • Object-oriented has the characteristics of abstraction, encapsulation, inheritance, polymorphism and so on.

Object-oriented programming languages are: C++, Java, C# and so on.

So you must be familiar with object-oriented thinking to write Java programs.

A class is also an object

Now we come to know a new concept of object oriented – class, what is the class, it was quite a series of abstract objects, such as books, class rather then the cover of the book, most object-oriented languages use the class to define a class, it tells you define what kind of objects are inside it, we usually use the following to define the class

class ClassName {
	// body;
}
Copy the code

There is a new concept involved in the code snippet //, which we will talk about later. Above, you declared a class. Now, you can use new to create this object

ClassName classname = new ClassName();
Copy the code

In general, class naming follows the hump principle, which is defined as follows:

Camel-Case is a set of naming rules (conventions) used in computer programming. As the name CamelCase implies, it refers to the use of a mixture of upper and lower case letters to form variable and function names. In order to make it easier for programmers to communicate their code among peers, they often adopt uniform and readable naming methods.

Object creation

In Java, everything is an object. Although everything is considered an object, you are manipulating a reference to an object. Here’s a good analogy: you can think of car keys and cars as a combination of object references and objects. When you want to drive, you first need to take out the car keys and click the lock option. When parking, you need to click lock to lock the car. The car key is equivalent to reference, the car is the object, by the car key to drive the car lock and unlock. Also, even if there is no car, the car key is a separate entity, that is, you have an object reference, but you don’t necessarily need an object associated with it, i.e

Car carKey;
Copy the code

This is a reference, not an object, but if you want to use the s reference, an exception will be returned telling you that you need an object to associate with the reference. It is safe to assign an object to an object when you create an object reference.

Car carKey = new Car();
Copy the code

In Java, once a reference is created, you want it to be associated with a new object, often using the new operator to do this. New means, give me a new date. If you don’t want a blind date, just make yourself a new date. I wish you happiness in your next life.

Properties and methods

One of the most basic elements of a class is that it has properties and methods.

An attribute, also known as a field, is an important part of a class and can be an object of any type or a basic data type. For example, under the

class A{
  int a;
  Apple apple;
}
Copy the code

Classes should also include methods, which represent ways of doing something. Methods are just functions, but Java has a habit of calling them methods. This term also reflects the concept of object orientation.

The basic composition of a method consists of the method name, parameters, return value, and method body. Here is an example of this:

public int getResult(a){
  // ...
  return 1;
}
Copy the code

Where getResult is the method name, () represents the parameter received by the method, and return represents the value returned by the method. There is a special argument type, void, to indicate that the method returns no value. The code snippet that {} contains is called the method body.

A constructor

In Java, there is a special class of methods called constructors, also known as constructors, constructors, etc. In Java, you ensure that every object is initialized by providing this constructor. The constructor can only be called once at object creation time, ensuring that the object is initialized. A constructor has no argument type or return value. Its name must be the same as the name of the class. There can be more than one constructor.

class Apple {
  
  int sum;
  String color;
  
  public Apple(a){}
  public Apple(int sum){}
  public Apple(String color){}
  public Apple(int sum,String color){}}Copy the code

The Apple class has no argument types or return values. It has multiple methods with the same name as Apple, and the argument list varies from Apple to Apple. This is a bit polymorphic, as we’ll see later. With the constructor defined, we are ready to create the Apple object.

class createApple {

    public static void main(String[] args) {
        Apple apple1 = new Apple();
        Apple apple2 = new Apple(1);
        Apple apple3 = new Apple("red");
        Apple apple4 = new Apple(2."color"); }}Copy the code

As shown above, we defined four Apple objects and called four different Apple constructors, where the constructor without any arguments is called the default constructor, i.e

Apple apple1 = new Apple();
Copy the code

If no constructor is defined in the class, the JVM automatically generates one for you, as follows:

class Apple {    int sum;  String color;  }class createApple {    public static void main(String[] args) {        Apple apple1 = new Apple();    }}
Copy the code

The above code does not compile errors because the Apple object contains a default constructor.

The default constructor is also called a default constructor or a no-parameter constructor.

One thing to note here is that even though the JVM will add a constructor with no arguments by default, if you define any constructor manually, the JVM will no longer provide you with a default constructor. You must specify it manually or you will get a compilation error.

The error is that the Apple constructor with an int must be supplied, and the default no-argument constructor is not allowed.

Method overloading

An important concept in Java is method overloading, which is a different representation of a class name. We talked about constructors, but constructors are a type of overload. The other is method overloading

public class Apple {    int sum;    String color;    public Apple(a){}    public Apple(int sum){}        public int getApple(int num){        return 1;    }        public String getApple(String color){        return "color";    }}
Copy the code

As shown above, there are two ways to overload: the Apple constructor and the getApple method.

But this raises the question: how does Java know which method you’re calling if there are several of the same names? One thing to remember here is that each overloaded method has a unique argument list. It includes the type, order and number of parameters, etc. Meeting one factor constitutes the necessary condition of overloading.

Remember the following overload conditions

  • The method names must be the same.

  • Parameter lists must be different (number, type, order of parameter types, etc.).

  • Methods can have the same or different return types.

  • The mere fact that the return type is different is not enough to be a method overload.

  • Overloading occurs at compile time because the compiler can choose which method to use based on the type of the parameter.

Method rewriting

Method overwriting and overloading have similar names, but are completely different things. Method overrides are described between subclasses and superclasses. And an overload is in the same class. For example:

class Fruit { 	public void eat(a){    System.out.printl('eat fruit');  }}class Apple extends Fruit{    @Override  public void eat(a){    System.out.printl('eat apple');  }}
Copy the code

The code above describes the overwritten code, and as you can see, the method in the Apple subclass has the same name as the method in the Fruit parent class, so we can deduce the overwritten principle

  • The overridden method must be identical to the parent class, including the return value type, method name, and argument list.
  • Override methods can be used@OverrideAnnotate to mark
  • Overriding methods in subclasses cannot have less access than methods in their parent classes.

Initialize the

Class initialization

The Car constructor is initialized using the new keyword. The Car constructor is initialized using the new keyword. The Car constructor is initialized using the new keyword

class Car{  public Car(a){}}
Copy the code

This parameterless constructor can be hidden and added automatically by the JVM. That is, the constructor ensures class initialization.

Member initialization

Java tries to ensure that every variable is initialized before it is used, and initialization involves two types of initialization.

  • One is the initialization of fields specified by the compiler by default, the initialization of primitive data types

    One is the initialization of other object types. A String is also an object with an initial value of NULL, including a wrapper class for the primitive type.

  • One is to specify the initialization of a value, for example:

int a = 11
Copy the code

That is, specify that the initial value of a is not 0, but 11. The same is true for other primitive and object types.

Constructor initialization

You can use constructors to initialize certain methods and certain actions to determine initial values, for example

public class Counter{
  int i;
  public Counter(a){
    i = 11; }}Copy the code

Using the constructor, we can initialize the value of I to 11.

Initialization sequence

First, let’s look at the initialization sequence we need to discuss

  • Static properties: Properties defined at the beginning of static

  • Static method block: a block of code wrapped in static {}

  • Common properties: properties that are not static defined

  • Normal method block: code block wrapped around {}

  • Constructor: a method with the same class name

  • Method: Common method

public class LifeCycle {
    // Static attributes
    private static String staticField = getStaticField();
    // Static method block
    static {
        System.out.println(staticField);
        System.out.println("Static method block initialization");
    }
    // Common attributes
    private String field = getField();
    // Normal method block
    {
        System.out.println(field);
    }
    // constructor
    public LifeCycle(a) {
        System.out.println("Constructor initialization");
    }

    public static String getStaticField(a) {
        String statiFiled = "Static Field Initial";
        return statiFiled;
    }

    public static String getField(a) {
        String filed = "Field Initial";
        return filed;
    }   
    / / the main function
    public static void main(String[] argc) {
        newLifeCycle(); }}Copy the code

The execution of this code reflects the order in which it was initialized

Output: static attribute initialization, static method block initialization, common attribute initialization, common method block initialization, constructor initialization

Array initialization

An array is a sequence of objects or primitive-type data of the same type wrapped together with an identifier name. Arrays are defined using the square bracket subscript operator [].

This is how arrays are defined

int[] a1;

/ / or

int a1[];
Copy the code

The meaning of both formats is the same.

  • Int array[4] = {1,2,3,4};
  • Int array[4] = {1,2};
  • Int array[] = {1,2};

Variable argument list

One popular use of arrays in Java is mutable parameters, which are defined as follows

public int add(int. numbers){
  int sum = 0;
  for(int num : numbers){
    sum += num;
  }
  return sum;
}
Copy the code

You can then make variadic calls in the following ways

add();  // Do not pass parameters
add(1);  // Pass a parameter
add(2.1);  // Pass multiple arguments
add(new int[] {1.3.2});  // Pass the array
Copy the code

Object destruction

Although the Java language is based on C++, an important feature of it and C/C++ is that it does not need to manually manage object destruction. There is a point mentioned in the famous book Understanding the Java Virtual Machine

In Java, we no longer need to manage object destruction manually; it is managed and destroyed by the Java Virtual Machine (JVM). Although we don’t need to manage objects manually, you do need to know the concept of object scope.

Object scope

Many numerical languages have the concept of scope. A scope determines the visibility and lifetime of its internally defined variable names. In C, C++, and Java, scope is usually determined by the position of {}, which is also known as a code block. Such as:

{  int a = 11;  {    int b = 12;  }}
Copy the code

The a variable is valid in both {} scopes, while the value of the B variable is valid only in its own {}.

Although scope exists, this is not allowed

{
  int x = 11;
  {
    int x = 12; }}Copy the code

This is ok in C/C++, but not allowed in Java because the Java designers believe it can lead to clutter.

# # # this and super

This and super are both Java keywords.

This can call methods, call properties, and point to the object itself. There are three common ways to use this in Java: to refer to the current object

public class Apple {

    int i = 0;

    Apple eatApple(a){
        i++;
        return this;
    }

    public static void main(String[] args) {
        Apple apple = newApple(); apple.eatApple().eatApple(); }}Copy the code

This code is pretty neat, but what’s neat about it? I can call an eatApple() method many times, and you can continue to call it in the back, which is amazing, why? In fact, this is the problem. I added a return value of this to the eatApple method, which means that any object that calls the eatApple method returns itself.

This can also modify attributes, most commonly in constructors, as shown below

public class Apple {

    private int num;
    
    public Apple(int num){
        this.num = num;
    }

    public static void main(String[] args) {
        new Apple(10); }}Copy the code

The main method passes an int of 10, which represents the number of apples, and assigns that number to the num global variable. So the value of num is now 10.

This can also be used with constructors to act as a global keyword

public class Apple {

    private int num;
    private String color;

    public Apple(int num){
        this(num,"Red");
    }
    
    public Apple(String color){
        this(1,color);
    }

    public Apple(int num, String color) {
        this.num = num;
        this.color = color; }}Copy the code

You’ll notice that the above code doesn’t use this, but this(argument). It’s equivalent to calling some other constructor and passing in arguments. One thing to note here: this() must be on the first line of the constructor or the compiler will fail.

If you think of this as a reference to itself, then super is a reference to the parent class. The super keyword, just like this, you can use super. Object to reference a member of the parent class as follows:

public class Fruit {

    int num;
    String color;

    public void eat(a){
        System.out.println("eat Fruit"); }}public class Apple extends Fruit{

    @Override
    public void eat(a) {
        super.num = 10;
        System.out.println("eat " + num + " Apple"); }}Copy the code

You can also use super to call the constructor of the parent class, but I won’t give you an example here.

Here’s a comparison of this and super for you.

Access control permission

Access control permissions are also called encapsulation, which is one of the three main features of object orientation. I used to ignore encapsulation in the process of learning, thinking that this is not an access modifier, why is it a necessary condition of the three features? I later learned that if a trusted subordinate is hiding a bug from you, you don’t know it.

Access control permissions are, at their core, visible only to classes that need them.

There are four types of member access permissions in Java: public, protected, default, and private. Their visibility is as follows

inheritance

Inheritance is an integral part of all OOP(Object Oriented Programming) and Java languages. As soon as we create a class, we implicitly inherit from the Object parent, but we don’t specify it. If you specify a parent class, then you inherit from the parent class, and your parent class inherits from Object.

The inheritance keyword is extends, as shown in the figure above. If extends is used to specify inheritance, then we can say Father is the parent class and Son is the subclass, as shown in the code below

class Father{}class Son extends Father{}
Copy the code

The two sides of the succession have some common characteristics

class Father{    public void feature(a){    System.out.println("Traits of a father.");  }}class Son extends Father {}
Copy the code

If Son does not implement its own method, the default is to use the parent feature method. If the subclass implements its own feature method, it is equivalent to rewriting the feature method of its parent class, which is also the rewriting mentioned above.

polymorphism

Polymorphism refers to multiple different manifestations of the same behavior. Means that the same method of a class instance (object) has different representations in different situations. Encapsulation and inheritance are the basis of polymorphism, that is, polymorphism is just a manifestation.

How to implement polymorphism? There are three necessary and sufficient conditions for the realization of polymorphism

  • inheritance
  • Override the parent class method
  • A superclass reference points to a subclass object

Take this code for example

public class Fruit {

    int num;

    public void eat(a){
        System.out.println("eat Fruit"); }}public class Apple extends Fruit{

    @Override
    public void eat(a) {
        super.num = 10;
        System.out.println("eat " + num + " Apple");
    }

    public static void main(String[] args) {
        Fruit fruit = newApple(); fruit.eat(); }}Copy the code

You can see the magic in the main method, Fruit Fruit = new Apple(), where an object of type Fruit refers to a reference to an Apple object, which is essentially polymorphic -> parent refers to a subclass object, because Apple inherits from Fruit, And rewrote the eat method, so that it could represent a variety of states.

combination

Composition is easy to understand, simply placing object references in a new class. Composition is also a way to improve class reusability. If you want classes to have more extensibility, you need to remember to use composition more than inheritance.

public class SoccerPlayer {
    
    private String name;
    private Soccer soccer;
    
}

public class Soccer {
    
    private String soccerName;    
}
Copy the code

SoccerPlayer references the Soccer class to call properties and methods in Soccer.

Composition and inheritance are different, and the main differences are as follows.

The debate about inheritance and combination is fruitless, as long as they give play to their strengths and advantages. In general, combination and inheritance are also good brothers that can be used together.

The agent

In addition to inheritance and composition, another relational model worth exploring is called proxy. The general description of A proxy is that A wants to call A method of class B, but A does not call it directly. A creates A proxy of B objects in its own class, and then the proxy calls B methods. For example:

public class Destination {

    public void todo(a){
        System.out.println("control..."); }}public class Device {

    private String name;
    private Destination destination;
    private DeviceController deviceController;

    public void control(Destination destination){ destination.todo(); }}public class DeviceController {

    private Device name;
    private Destination destination;

    public void control(Destination destination){ destination.todo(); }}Copy the code

For an in-depth understanding of agents, see the article

Dynamic proxies are surprisingly simple!

In-depth understanding of agents

upcasting

Upward transformation represents the relationship between the parent class and the child class. In fact, there is not only upward transformation between the parent class and the child class, but also downward transformation, and their transformation ranges are different

  • upcasting: By converting a subclass object (small scope) to a superclass object (large scope), this conversion is automatic and not mandatory.
  • Downward transition: instantiates a child object (small) from a parent object (large range). This conversion is not automatic and must be specified forcibly.

static

Static is used to modify member variables and methods. Static is used to call methods/variables without creating objects.

  • Member variables declared static are static member variables and also class variables. Class variables have the same life cycle as classes and remain in effect throughout application execution.
static String name = "cxuan";
Copy the code
  • Methods that use the static modifier are called static methods, and static methods can use the class name directly. Method name to call. Since static methods can be accessed directly without relying on any object, there is no such keyword for static methods; instance variables always have this. Non-static member variables and non-static methods of a class cannot be accessed in a static method,
static void printMessage(a){  System.out.println("cxuan is writing the article"); }Copy the code

In addition to modifying properties and methods, static has the ability to use static code blocks for class initialization operations. To improve the performance of the program.

public class StaicBlock {    static{        System.out.println("I'm A static code block");    }}
Copy the code

Because static code blocks execute as the class is loaded, many times initialization operations that only need to be done once are placed in static code blocks.

A static keyword can still impress me. A static keyword can still impress me. It is highly recommended to read after learning the basics of Java.

final

Final means final, final, and it can modify classes, properties, and methods.

  • When final decorates a class, it indicates that the class cannot be inherited. Member variables ina final class can be set to final if necessary, but be aware that all member methods ina final class are implicitly specified as final methods.
class Parent {}
final class Person extends Parent{} // The Parent class can be inherited
class Child extends Person{} // The Person class cannot be inherited
Copy the code
  • Final decorates a method to indicate that the method cannot be overridden by any subclass, so make the method final only if you want to explicitly forbid the method to be overridden ina subclass.
class Parent {
	// Final methods cannot be overridden, but can be inherited
    public final void method1(a){}  // This method cannot be overridden
    public void method2(a){}}class Child extends Parent {
	You can override the method2 method
	public final void method2(a){}}Copy the code
  • Final modifies variables into two situations. One modifies basic data types, indicating that the value of the data type cannot be modified. One is to decorate a reference type to indicate that it can no longer point to another object after it has been initialized.
final int i = 20;
i = 30; // Final variables can only be assigned once
Copy the code

In Java, final, Finally, and Finalize become the last three brothers. As for the detailed usage of these three keywords, you can refer to the article of the author and see the final, finally and Finalize with the interviewer. Then you will have no problem

Interfaces and abstract classes

interface

An interface is an external convention and standard. Take the operating system as an example. Why is there an operating system? In order to shield the difference between software complexity and hardware simplicity, a unified standard will be provided for software.

In the Java language, interfaces are represented by the interface keyword. For example, we can define an interface as follows

public interface CxuanGoodJob {}
Copy the code

For example, if we define an interface to cxuanggood job, then you can define inside it the things that CXuan does well, such as cXuan writes good articles.

public interface CxuanGoodJob {

    void writeWell(a);
}
Copy the code

Some interface characteristics are implied here:

  • interfaceInterface is a completely abstract class, it does not provide any method implementation, only method definition.
  • There are only two types of access modifiers that can be used in an interfacepublicIt is visible to the entire project; One is thedefaultBy default, it only has package access rights.
  • An interface provides only the definition of a method. An interface is not implemented, but an interface can be implemented by other classes. That is, the class that implements the interface needs to provide implementations of methods that the implementation interface usesimplementsAn interface can have multiple implementations.
class CXuanWriteWell implements CxuanGoodJob{

    @Override
    public void writeWell(a) {
        System.out.println("Cxuan write Java is vary well"); }}Copy the code
  • The interface can’t be instantiated, so there can’t be any constructors in the interface, and if you define constructors, the compiler will fail.
  • Implementations of interfaces, such as all methods that implement the interface, must otherwise be defined asAn abstract classThat’s what we’re going to talk about

An abstract class

Abstract class is a class with weaker abstraction ability than interface. In Java, abstract class is represented by the abstract keyword. If the interface is described as a dog species, then the abstract class can be described as white and small, while the implementation class can be concrete, such as Pomerangs, teddies, etc. You can define an abstract class as follows

public interface Dog {

    void FurColor(a);

}

abstract class WhiteDog implements Dog{

    public void FurColor(a){
        System.out.println("Fur is white");
    }

    abstract void SmallBody(a);
}
Copy the code

In an abstract class, it has the following characteristics

  • If there are abstract methods in a class, the class must be abstract. That is, methods decorated with the keyword abstract must be abstract methods, and classes with abstract methods must be abstract classes. There are only method concrete implementations in implementation class methods.

  • Abstract classes do not have to have only abstract methods. Abstract classes can also have concrete methods, and you can choose whether to implement those methods or not.

  • You can define constructors, abstract methods, ordinary properties, methods, static properties, and static methods in abstract classes, where the constraints are not as strict as in interfaces

  • Abstract classes, like interfaces, cannot be instantiated; instantiation can only instantiate concrete classes.

abnormal

Exceptions are a common occurrence in programs, and the best time to detect errors is during compilation, before you try to run the program. However, not all errors are found at compile time. Some NullPointerExceptions and ClassNotFoundException are not found at compile time. These are RuntimeExceptions. These exceptions are often discovered at run time.

Java.lang.Error: java.lang.Error: java.lang.Error: java.lang.Error: java.lang.

Know the Exception

Exception, located in the java.lang package, is a top-level interface that inherits from the Throwable class. The Exception class and its subclasses are both Throwable and reasonable conditions for applications.

Before you get to Exception, it’s important to understand what Throwable is.

What is a Throwable

The Throwable class is the parent class of all errors and exceptions in the Java language. Only classes that inherit from Throwable or subclasses of Throwable can be thrown. Alternatively, classes with the @throw annotation in Java can also be thrown.

In the Java specification, non-checked and checked exceptions are defined as follows:

The unchecked exception classes are the run-time exception classes and the error classes.

The checked exception classes are all exception classes other than the unchecked exception classes. That is, the checked exception classes are Throwable and all its subclasses other than RuntimeException and its subclasses and Errorand its subclasses.

That is, all exceptions except RuntimeException and its subclasses, and Error and its subclasses are checkedException.

So, according to this logical relationship, we can classify and analyze Throwable and its subclasses

As you can see, Throwable is at the top of the list of exceptions and errors. When we look at the Throwable class, there are many methods and attributes. We’ll discuss only a few of the more common ones

// Returns the details of the exception thrown
public string getMessage(a);
public string getLocalizedMessage(a);

// Returns a brief description of when the exception occurred
public public String toString(a);// Prints exception information to the standard output stream
public void printStackTrace(a);
public void printStackTrace(PrintStream s);
public void printStackTrace(PrintWriter s)

// Record the current state of the stack frame
public synchronized Throwable fillInStackTrace(a);
Copy the code

In addition, because Throwable’s parent class is also Object, common methods include getClass() and getName() methods that inherit from its parent class.

Common Exception

Back to Exception, now that you know that Exception’s parent class is Throwable and that Exception has two types of exceptions: RuntimeException; One is CheckedException, both of which should be caught.

Below is a list of common exceptions in Java and their classification. The interviewer may also ask you to name a few common exceptions and categorize them

RuntimeException

UncheckedException

Java keywords associated with Exception

So how do these exceptions work in Java? Throws, throw, try, finally, and catch are the keywords in Java

Throws and throw

In Java, an exception is an object that can be thrown by a programmer or an application. Throw exceptions must be defined using throws and throws statements.

Throws and throws are usually paired, for example

static void cacheException(a) throws Exception{  throw newException(); }Copy the code

A throw statement is used in a method body to indicate that an exception is thrown and is handled by a statement in the method body. Throws a throws exception, which is handled by the caller of the method.

Throws throws Throws throws throws throws of this type so that its caller knows to catch the exception. A throw is the action of specifically throwing an exception, so it throws an exception instance.

Try, finally, catch

Try… try… try… The catch, try… Finally, try… catch… The finally.

try… Catch represents a catch for an exception that a piece of code might throw, as follows

static void cacheException(a) throws Exception{

  try {
    System.out.println("1");
  }catch(Exception e){ e.printStackTrace(); }}Copy the code

try… Finally means that a piece of code will be executed regardless of the situation

static void cacheException(a) throws Exception{
  for (int i = 0; i < 5; i++) {
    System.out.println("enter: i=" + i);
    try {
      System.out.println("execute: i=" + i);
      continue;
    } finally {
      System.out.println("leave: i="+ i); }}}Copy the code

try… catch… Finally is the same, indicating that after the exception is caught, the code logic in finally is passed.

What is the Error

An Error is an Error that the program cannot handle and indicates a serious problem in running the application. Most errors have nothing to do with what the code writer is doing, and instead represent problems with the JVM (Java Virtual Machine) while the code is running. These errors are not detectable because they are outside the control and processing capabilities of the application and are mostly conditions that are not allowed to occur while the program is running, such as OutOfMemoryError and StackOverflowError exceptions. The Java memory model, JDK1.7, needs to be introduced.

In the Java memory model above, only the program counter is the area where OutOfMemoryError does not occur. The program counter controls the branch, loop, jump, exception handling, and thread recovery of computer instructions. And program counters are per-thread private.

Thread private: Represents an area of memory that is stored independently of each other by threads.

If the application executes Java methods, this counter records the address of the virtual machine’s bytecode instructions; If the Native method is being executed, this counter value is null (Undefined).

In addition to program counters, other areas: Method Area, VM Stack, Native Method Stack, and Heap are all areas where OutofMemoryErrors can occur.

  • Virtual machine stack: StackOverflowError occurs if the thread requests a stack depth larger than the virtual machine stack allows. An OutOfMemoryError occurs if the virtual machine cannot allocate sufficient memory for dynamic scaling.

  • The local method stack is the same as the virtual machine stack

  • Heap: The Java heap can be physically discontinuous and logically continuous, just like our disk space, and an OutOfMemoryError will be thrown if there is no memory in the heap for instance allocation and the heap cannot be extended.

  • Method area: OutOfMemoryError is thrown when the method area cannot meet memory allocation requirements.

In Java, you can think of exceptions as a mechanism to improve the robustness of your program, so that you can write code that pays attention to these exceptions, or you can’t be a core programmer if you don’t write code that pays attention to these exceptions.

The inner class

Up to now, we only know the definition of a common class, that is, to create a class directly in IDEA.

After completion of the new, you’ll have a class file, the definition of the operation is too simple, in the long run will be boring, we young people need more and more trendy SAO gas spelled, okay, since you mentioned that you use an inner class, this is a useful and SAO gas class, the definition of the definition of the inner class is very simple: You can put the definition of one class inside another class, which is called an inner class.

Inner class is a very useful feature, defined inside the class class that holds the external class references, but for other external invisible, looks like a hidden code mechanism, and the French general, French can communicate and French general, but the enemy outside cannot attack directly to the French ontology.

Let’s talk about how to create inner classes.

How is an inner class defined

Here is the simplest way to define an inner class:

public class Parcel1 {
    public class Contents{
        private int value = 0;
    
        public int getValue(a){
            returnvalue; }}}Copy the code

So this is a very simple way to define an inner class, you can just put one class inside another class, and the way you define Contents is called an inner class.

So, as the code above shows, how does a programmer access the Contents of Contents?

public class Parcel1 {

    public class Contents{
        private int value = 0;

        public int getValue(a){
            returnvalue; }}public Contents contents(a){
        return new Contents();
    }

    public static void main(String[] args) {
        Parcel1 p1 = newParcel1(); Parcel1.Contents pc1 = p1.contents(); System.out.println(pc1.getValue()); }}Copy the code

And as you can see in the code above, you can write a method that accesses Contents, which essentially points to a reference to Contents, using an external class. The inner class is defined to create a reference to the inner class, as shown in parcel1.contents pc1 = p1.contents(), and pc1 holds access to the inner class Contents.

Now, I have a question, if the contents method in the above code becomes static, will PC1 still be able to access it?

Compilation can’t get through, so why can’t access? Take a look at the following analysis.

Links to external classes

Why would you write code this way, as if it were just to install B? Or if you feel like redefining a class is a hassle, you might as well just define an inner class instead, as if you haven’t seen the benefits of this inner class approach yet. Take a look at the following example

public class Parcel2 {

    private static int i = 11;

    public class Parcel2Inner {

        public Parcel2Inner(a){
            i++;
        }

        public int getValue(a){
            returni; }}public Parcel2Inner parcel2Inner(a){
        return new Parcel2Inner();
    }

    public static void main(String[] args) {
        Parcel2 p2 = new Parcel2();
        for(int i = 0; i <5; i++){ p2.parcel2Inner(); } System.out.println("p2.i = "+ p2.i); }}Copy the code

The output is 16

When you create an inner class object, the object has some connection to its outer objects. As shown in the code above, the inner class Parcel2Inner is the value that can access and modify the I in Parcel2.

So, how do you create an object of an inner class? Programmers can’t write a method that returns an object of an external class every time, can they? Look at the following code:

public class Parcel3 {

    public class Contents {

        public Parcel3 dotThis(a){
            return Parcel3.this;
        }

        public String toString(a){
            return "Contents"; }}public Parcel3 contents(a){
        return new Contents().dotThis();
    }

    public String toString(a){
        return "Parcel3";
    }

    public static void main(String[] args) {
        Parcel3 pc3 = new Parcel3();
        Contents c = pc3.new Contents(a); Parcel3 parcel3 = pc3.contents(); System.out.println(pc3); System.out.println(c); System.out.println(parcel3); }}Copy the code

Output: Parcel3 Contents Parcel3

As the code above shows, Parcel3 defines an inner class Contents, which defines a method called dotThis() that returns an object from the outer class, and a Contents () method that returns a reference to the outer class.

Inner classes and upward transitions

What this article has shown so far is that this class holds access to an inner class. How does an unrelated class hold access to an inner class? And what exactly does inner class have to do with upward transition?

public interface Animal {

    void eat(a);
}

public class Parcel4 {

    private class Dog implements Animal {

        @Override
        public void eat(a) {
            System.out.println("Bone gnawing"); }}public Animal getDog(a){
        return new Dog();
    }

    public static void main(String[] args) {
        Parcel4 p4 = new Parcel4();
        //Animal dog = p4.new Dog();Animal dog = p4.getDog(); dog.eat(); }}Copy the code

Output: Bone gnawing

Dog is private, so you can’t access it from any other class, so why is it accessible? If you think about it, because Parcel4 is public and Parcel4 has access to its inner class, Animal can also access Parcel4’s inner class, which is called Dog, and Dog implements the Animal interface, So the getDog() method also returns a subclass of Animal, which makes the transition up and makes the code even nicer.

Define classes inside a method and any scope

Some of the inner class definitions shown above are ordinary inner class definitions. What if I wanted to define an inner class in a method or scope?

Here are a few ways you might consider a definition:

  1. I want to define an inner class that implements an interface, and I define an inner class to return a reference to that interface
  2. I want to solve a problem, and this class doesn’t want it to be publicly available, as the name implies, wrapped up and not allowed to be used
  3. Because of lazy…

Here are a few ways to define an inner class:

  • A class defined in a method (local inner class)
  • A class defined in scope inside a method (member inner class)
  • An anonymous class that implements the interface (anonymous inner class)
  • An anonymous class that extends classes that are not default constructors
  • An anonymous class that performs field initialization operations
  • An anonymous class that implements a construct through instance initialization
  • Classes defined inside a method are also known as local inner classes
public class Parcel5 {  private Destination destination(String s){    class PDestination implements Destination{      String label;      public PDestination(String whereTo){        label = whereTo;      }      @Override      public String readLabel(a) {        returnlabel; }}return new PDestination(s);  }  public static void main(String[] args) {    Parcel5 p5 = new Parcel5();    Destination destination = p5.destination("China");    System.out.println(destination.readLabel());  }}
Copy the code

Output: China

As you can see in the code above, when you write a method, you can insert a class definition in the method, and the properties in the inner class are all classified, and I was curious when I wrote this code, how the inner class is executed, PDestination(“China”); return new PDestination(s); This is the same way we initialize its outer class, except that this method provides an entry point to the inner class.

Local inner class definitions cannot have access modifiers

  • A class defined in scope, which is inside a method
public class Parcel6 {
  // How to eat coconut
  private void eatCoconut(boolean flag){
    // If you can eat coconut
    if(flag){
      class Coconut {
        private String pipe;

        public Coconut(String pipe){
          this.pipe = pipe;
        }

        // How to drink coconut water
        String drinkCoconutJuice(a){
          System.out.println("Drink coconut water.");
          returnpipe; }}// Provide a straw for drinking coconut water
      Coconut coconut = new Coconut("Drink through a straw.");
      coconut.drinkCoconutJuice();
    }

    /** * You can only drink coconut water through a straw if you can eat coconut water ** you can't drink coconut water if you can't be told to drink coconut water */
    // Coconut = new Coconut(" Coconut ");
    // coconut.drinkCoconutJuice();
  }

  public static void main(String[] args) {
    Parcel6 p6 = new Parcel6();
    p6.eatCoconut(true); }}Copy the code

Output: Drink coconut water

As the code above shows, only the programmer tells the program, “Now I want a coconut.” When the program receives this command, it replies, “Yes,” and immediately prepares a coconut for you, along with a straw so that you can drink fresh coconut water. If the programmer doesn’t want to eat coconuts, the program won’t prepare coconuts for you, let alone make you drink coconut water.

  • A class that implements an anonymous interface

We all know that interfaces can’t be instantiated, which means you can’t return an interface object, you can only return an object that subclasses that interface, but would you be skeptical if it were defined like this?

public interface Contents {

    int getValue(a);
}

public class Parcel7 {

    private Contents contents(a){
        return new Contents() {

            private int value = 11;

            @Override
            public int getValue(a) {
                returnvalue; }}; }public static void main(String[] args) {
        Parcel7 p7 = newParcel7(); System.out.println(p7.contents().getValue()); }}Copy the code

Output: 11

Why can an interface definition be returned? And then there’s {}. What the hell is that? This is a way of writing an anonymous inner class, which is similar to the inner class and upward transition mentioned above. That is, the new Contents() returned by the anonymous inner class is actually an implementation class of Contents, but the name of the implementation class is hidden, and can be converted using the following code example:

public class Parcel7b {

    private class MyContents implements Contents {

        private int value = 11;

        @Override
        public int getValue(a) {
            return 11; }}public Contents contents(a){
        return new MyContents();
    }

    public static void main(String[] args) {
        Parcel7b parcel7b = newParcel7b(); System.out.println(parcel7b.contents().getValue()); }}Copy the code

The output result you should know ~! Do you think this code is consistent with the code described in 10.3?

  • An anonymous class that extends classes that are not default constructors

If you want to return a constructor with parameters (not the default constructor), how do you express that?

public class WithArgsConstructor {

    private int sum;

    public WithArgsConstructor(int sum){
        this.sum = sum;
    }

    public int sumAll(a){
        returnsum; }}public class Parcel8 {

    private WithArgsConstructor withArgsConstructor(int x){

        // Returns the WithArgsConstructor constructor with arguments to perform field initialization
        return new WithArgsConstructor(x){

            // Override sumAll to implement subclass execution logic
            @Override
            public int sumAll(a){
                return super.sumAll() * 2; }}; }public static void main(String[] args) {
        Parcel8 p8 = new Parcel8();
        System.out.println(p8.withArgsConstructor(10).sumAll()); }}Copy the code

The sumAll constructor method returns the value of sum. The WithArgsConstructor method returns the value of x directly. But at this point, you want to do something special with the return value. For example, you want to define a class that overrides the sumAll method to implement the business logic of the subclass. Java Programming Philosophy on page 198 says “; “in code. Not the end of an inner class, but the end of an expression that happens to contain an anonymous inner class.

  • An anonymous class that performs field initialization

The above code does initialize the field, but only through the constructor. If you don’t have a constructor with parameters, can you initialize the field? That’s ok.

public class Parcel9 {

    private Destination destination(String dest){
        return new Destination() {

            // Initialize the assignment operation
            private String label = dest;

            @Override
            public String readLabel(a) {
                returnlabel; }}; }public static void main(String[] args) {
        Parcel9 p9 = new Parcel9();
        System.out.println(p9.destination("pen").readLabel()); }}Copy the code

Java programming thought P198 says that if I initialize a field, the parameter must be final. If it is not final, the compiler will report an error. This part raises questions because I do not define it as final, and the compiler does not report an error. I have considered whether it is private or not. When I change private to public, there is no problem.

I do not know whether there is a problem in the translation of the Chinese version by the author, or this problem has been eliminated after so many Java versions have been upgraded. I have not checked how the original version was written, and I still hope someone who knows can help explain this problem.

  • An anonymous class that implements a construct through instance initialization
public abstract class Base {

    public Base(int i){
        System.out.println("Base Constructor = " + i);
    }

    abstract void f(a);
}

public class AnonymousConstructor {

    private static Base getBase(int i){

        return new Base(i){
            {
                System.out.println("Base Initialization" + i);
            }

            @Override
            public void f(a){
                System.out.println("Anonymousconstructive.f () method called"); }}; }public static void main(String[] args) {
        Base base = getBase(57); base.f(); }}Copy the code

Output: Base Constructor = 57 Base Initialization 57 anonymousconstructor.f () method is called

This code is in the same category as “an anonymous class that extends a class that is not a default constructor”, and is initialized through the constructor.

Nested classes

We’ve seen six ways to define an inner class, and now we’re going to solve the initial question of why contents() is static and compilable:

Declare an inner class static if you don’t need a previous relationship between the inner class and its enclosing class. This is often referred to as a nested class, which means that the inner class of a nested class has no prior relationship to its enclosing class, which means that the inner class is defined in the enclosing class, but does exist independently. Nested classes are also known as static inner classes.

Static inner classes mean:

  1. To create an object of a nested class, you do not need an object of its enclosing class
  2. A non-static enclosing class object cannot be accessed from an object of a nested class

Look at the following code

public class Parcel10 {

    private int value = 11;

    static int bValue = 12;

    // Static inner class
    private static class PContents implements Contents {

        Static inner class PContents does not contain a field called value
        @Override
        public int getValue(a) {
            return value;
        }

        The static inner class PContents can access the static property bValue
        public int f(a){
            returnbValue; }}// Ordinary inner class
    private class PDestination implements Destination {

        @Override
        public String readLabel(a) {
            return "label"; }}// Compile without error because static methods can access static inner classes
    public static Contents contents(a){
        return new PContents();
    }

    // Compile error because non-static methods cannot access static inner classes
    public Contents contents2(a){
        Parcel10 p10 = new Parcel10();
        return p10.new PContents(a);
    }

    Static methods can access non-static inner classes
    public static Destination destination(a){
        Parcel10 p10 = new Parcel10();
        return p10.new PDestination(a);
    }

    // Non-static methods can access non-static inner classes
    public Destination destination2(a){
        return newPDestination(); }}Copy the code

As the code above explains, the compilation error occurs because static methods cannot access non-static inner classes directly. Instead, they need to access normal inner classes by creating objects for the enclosing class.

The class inside the interface

What? You can only define methods inside an interface. Can you put a class inside an interface? You can!

Normally, you can’t put any code inside an interface, but nested classes are part of the interface, and any classes you put in the interface are public and static by default. Because classes are static, it’s not against the rules of interfaces to put nested classes in the namespace of the interface. You can even implement the interface of an external class with an inner class, but this is generally discouraged.

public interface InnerInterface {

    void f(a);

    class InnerClass implements InnerInterface {

        @Override
        public void f(a) {
            System.out.println("Methods that implement interfaces");
        }

        public static void main(String[] args) {
            newInnerClass().f(); }}You cannot use the main method in an interface. You must define it in the inner class of the interface
// public static void main(String[] args) {}
}
Copy the code

Output: Methods that implement the interface

Inner classes implement multiple inheritance

In Java, the relationship between class and class is usually one-to-one, also is the principle of single inheritance, so in the interface, the relationship between the classes and interfaces is a pair of many, that is to say, a class can implement multiple interfaces, and interface is combined with the inner class can implement multiple inheritance, is not to say that, with the extends keyword It is a mock implementation of multiple inheritance for interfaces and inner classes.

Reference articles chenssy www.cnblogs.com/chenssy/p/3… It’s already pretty good.

public class Food {

    private class InnerFruit implements Fruit{
        void meakFruit(a){
            System.out.println("Grow a fruit."); }}private class InnerMeat implements Meat{
        void makeMeat(a){
            System.out.println("Cook a piece of meat"); }}public Fruit fruit(a){
        return new InnerFruit();
    }

    public Meat meat(a){
        return new InnerMeat();
    }

    public static void main(String[] args) {
        Food food = newFood(); InnerFruit innerFruit = (InnerFruit)food.fruit(); innerFruit.meakFruit(); InnerMeat innerMeat = (InnerMeat) food.meat(); innerMeat.makeMeat(); }}Copy the code

Output: Plant a piece of fruit and cook a piece of meat

Inheritance of inner classes

Inheritance can also be implemented between inner classes, similar to, but not identical to, inheritance between ordinary classes.

public class BaseClass {

    class BaseInnerClass {

        public void f(a){
            System.out.println("BaseInnerClass.f()"); }}private void g(a){
        System.out.println("BaseClass.g()"); }}/** * We can see that InheritInner only inherits from the inner class, not the outer class. * must use similar enclosingClassReference. Super () to compile * used to illustrate the link between the internal and external class object references. * * /
public class InheritInner extends BaseClass.BaseInnerClass{

    // Error compiling
// public InheritInner(){}

    public InheritInner(BaseClass bc){
        bc.super(a); }@Override
    public void f(a) {
        System.out.println("InheritInner.f()");
    }

    /* * @override is an error, because there is no g() method in the BaseInnerClass. This is why Override must be included in the Override annotation. Otherwise, the default is the method held in the BaseInnerClass, causing the developer to think that the g() method was overridden. @Override public void g(){ System.out.println("InheritInner.g()"); } * /

    public static void main(String[] args) {
        BaseClass baseClass = new BaseClass();
        InheritInner inheritInner = newInheritInner(baseClass); inheritInner.f(); }}Copy the code

Output: InheritInner. F ()

Coverage of inner classes

Let’s look at some code for inner class coverage:

public class Man {

    private ManWithKnowledge man;

    protected class ManWithKnowledge {

        public void haveKnowledge(a){
            System.out.println("Knowledge is what we need today."); }}// We want it to output the subclass's haveKnowledge() method
    public Man(a){
        System.out.println("When we have a child, we want him to be a scientist, not an Internet celebrity.");
        newManWithKnowledge().haveKnowledge(); }}/ / web celebrity
public class InternetCelebrity extends Man {

    protected class ManWithKnowledge {

        public void haveKnowledge(a){
            System.out.println("Internet celebrities are a disease in today's society."); }}public static void main(String[] args) {
        newInternetCelebrity(); }}Copy the code

Output: When we have a child, we want him to be a scientist, not a celebrity. Knowledge is needed in today’s society

We can override inner classes by default. . So we want him to output InternetCelebrity haveKnowledge (), to achieve our conjecture, but the output ManWithKnowledge. HaveKnowledge () method.

This example shows that when you inherit from an enclosing class, the inner class does not magically change; the two inner classes are separate and in their own namespaces.

About the representation of inner classes in source code

Since each class produces a.class file, it contains all the information needed to create an object of that type.

Similarly, the inner class generates a.class file represented by OneClass$OneInnerClass

Advantages of inner classes

Here’s a summary of the advantages of inner classes:

Encapsulate some of the code so that when you create an inner class, the inner class holds a reference to the outer class by default.

2. Inner class has certain flexibility, no matter whether the outer class inherits the implementation of an interface, it does not affect the inner class;

3. Inner classes can effectively solve the problem of multiple inheritance.

A collection of

Collections are used so many times in our daily development that you are already familiar with them, but as a qualified programmer, you need to know not only the basic usage of them, but also the source code; You have to understand how it’s designed and implemented, and you have to understand how it’s derived.

In this blog post, we will take a closer look at the family architecture and members of the large Collection framework, and let you know about its design and implementation.

It’s time for this divine map

The first is the Iterator interface

The Iterable interface

Implementing this interface allows an object to become the target of a for-each loop, which enhances the for loop, a syntactic sugar in Java.

List<Object> list = new ArrayList();
for (Object obj: list){}
Copy the code

In addition to objects that implement this interface, arrays can also be iterated through with a for-each loop, as follows:

Object[] list = new Object[10];
for (Object obj: list){}
Copy the code

Other traversal methods

Before JDK 1.8, Iterator had only one method: Iterator

Iterator<T> iterator(a);
Copy the code

The approach to implementing the subinterface creates a lightweight iterator that can safely traverse, remove, and add elements. There’s a fail-fast mechanism involved.

The bottom line is that if you can create iterators to add and remove elements, use iterators to add and remove elements.

Iterators can also be used for traversal

for(Iterator it = coll.iterator(); it.hasNext(); ) { System.out.println(it.next()); }Copy the code

The top interface

Collection is a top-level interface that defines conventions for collections

The List interface is also a top-level interface that inherits the Collection interface and is the parent class of Collection elements such as ArrayList and LinkedList

The Set interface is on the same level as the List interface, and it also inherits the Collection interface. The Set interface provides additional provisions. It provides additional standards for the add, Equals, and hashCode methods.

Queue is one of the three interfaces of a Collection, along with List and Set. Queue is designed to preserve the order in which elements are accessed prior to processing. Queues provide additional insert, read, and check operations in addition to the basic operations of Collection.

The SortedSet interface directly inherits from the Set interface, using Comparable to naturally sort elements or using a Comparator to provide custom collation of elements at creation time. The iterator to set traverses the collection in ascending element order.

A Map is an object that supports key-value storage. A Map cannot contain duplicate keys and maps a maximum of one value to each key. This interface replaces the Dictionary class, which is an abstract class rather than an interface.

ArrayList

ArrayList is an expandable array (dynamic array) that implements the List interface. Its internal implementation is based on arrays. It is defined as follows:

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess.Cloneable.java.io.Serializable {... }Copy the code
  • ArrayList implements all optional list operations, allowing all elements, including null values. ArrayList also provides a way to store lists internally, which is a complete substitute for Vector, with one exception: ArrayList is not a thread-safe container.
  • An ArrayList has a concept of capacity, the capacity of the array is the capacity of the List to store its elements.
  • ArrayList is not a thread-safe container. If at least two threads out of multiple threads modify the structure of ArrayList, thread-safe List can be used as an alternative condition, and should be usedCollections.synchronizedList
List list = Collections.synchronizedList(newArrayList(...) )Copy the code
  • ArrayList has the fail-fast mechanism to detect the failure of ArrayList. Fail-fast, or throwing, can occur when the collection is structurally changed during iterationConcurrentModificationException The exception.

Vector

Vector, like ArrayList, is implemented based on arrays, except that it is a thread-safe container. It simply locks every method inside it, avoiding security problems caused by multiple threads. However, this synchronization method usually requires a high overhead. Accessing elements is much less efficient than ArrayList.

Another point is that ArrayList increases the size of arrays by 50%, while Vector doubles the size of arrays.

LinkedList class

LinkedList is a two-way LinkedList that allows storing any element (including null). Its main features are as follows:

  • All LinkedList operations can be bidirectional, indexed to LinkedList operations are traversed from beginning to end, depending on which proximity is the traversal order.
  • Note that this implementation is also not thread-safe; if multiple threads concurrently access the list and at least one of them changes the structure of the list, then the list must be externally locked. Or use
List list = Collections.synchronizedList(newLinkedList(...) )Copy the code

Stack

The stack is what we call a last in, first out container. It inherits from the Vector class, providing the usual push and pop operations, a peek method at the top of the stack, an empty method to test if the stack is empty, and a search method to find the distance from the top of the stack.

The first time the stack is created, it contains no elements. A more complete and reliable LIFO stack operation provided by the Deque interface and its implementation should be preferred

Deque<Integer> stack = new ArrayDeque<Integer>()
Copy the code

HashSet

A HashSet is an implementation class of the Set interface, supported by a hash table (in fact, a HashSet is an instance of a HashMap). It does not guarantee the iteration order of the set. This class allows null elements.

  • Note that this implementation is not thread-safe. If multiple threads concurrently access a HashSet, and at least one thread modifies the set, an external lock must be performed. Or useCollections.synchronizedSet()Method override.
  • This implementation supports the fail-fast mechanism.

TreeSet

TreeSet is a NavigableSet implementation based on TreeMap. Depending on the constructor used, these elements are sorted using either their natural sorting or the Comparator provided at creation time.

  • This implementation provides a log(n) time cost for the basic operations Add,remove, and Contains.
  • Note that this implementation is not thread-safe. If multiple threads concurrently access TreeSet and at least one thread modifies the set, an external lock must be performed. Or use
SortedSet s = Collections.synchronizedSortedSet(newTreeSet(...) )Copy the code
  • This implementation holds the fail-fast mechanism.

LinkedHashSet class

LinkedHashSet inherited from Set. Let’s take a look at the inheritance system of LinkedHashSet:

LinkedHashSet is an implementation of the Hash table and LinkedList of the Set interface. This implementation differs from HashSet in that it maintains a bidirectional linked list through all entries. This list defines the order in which elements are inserted into the collection. Note: If elements are re-inserted, the insertion order is not affected.

  • The LinkedHashSet has two parameters that affect its composition: the initial capacity and the load factor. They are defined exactly the same as a HashSet. Note, however, that for a LinkedHashSet, choosing a high initial capacity value is less expensive than a HashSet, because the number of iterations of a LinkedHashSet is not affected by capacity.
  • Note that the LinkedHashSet is also not thread-safe; if multiple threads access the LinkedHashSet at the same time, it must be locked, or accessed by using
Collections.synchronizedSet
Copy the code
  • This class also supports the Fail-fast mechanism

PriorityQueue

AbstractQueue PriorityQueue is an implementation class of AbstractQueue. The elements of a PriorityQueue are sorted either by nature or by providing a Comparator during constructor time, depending on the constructor. PriorityQueue does not allow null elements.

  • The head of a queue is, in a sense, the last element in a specified order. The queue lookup operations poll,remove,peek, and Element access the queue head element.
  • The priority queue is unlimited, but has an internal capacity that controls the size of the array used to store elements in the queue.
  • This class and iterators implement all the optional methods of the Collection and Iterator interfaces. This iterator providesiterator()Method does not guarantee traversal of the elements of the priority queue in any particular order. If you need an ordered traversal, consider using itArrays.sort(pq.toArray()).
  • Note that this implementation is not thread-safe, multithreads should not concurrently access PriorityQueue instances if a thread modiates the queue, using thread-safe classesPriorityBlockingQueue.

HashMap

A HashMap is a collection of elements that use hash table principles and allow empty key-value pairs. HashMap is non-thread-safe, which means that in a multi-threaded environment, there can be problems, whereas Hashtable is thread-safe container. HashMap also supports fail-fast. An instance of a HashMap has two parameters that affect its performance: the initial capacity and the load factor. You can use the Collections. SynchronizedMap (new HashMap (…). ) to construct a thread-safe HashMap.

TreeMap class

A NavigableMap based implementation of the red black tree. The map is stored naturally sorted by key or custom sorted by Comparator.

  • TreeMap provides log(n) time overhead for the containsKey, GET, PUT, and remove methods.

  • Note that this implementation is not thread-safe. If multiple threads concurrently access TreeMap and at least one thread changes the map, an external lock must be performed. This usually by synchronization in natural packaging collection of an object, or use a SortedMap m = Collections synchronizedSortedMap (new TreeMap (…). ).

  • This implementation holds the fail-fast mechanism.

The LinkedHashMap class

LinkedHashMap is the hash and linked list implementation of the Map interface. This implementation differs from HashMap in that it maintains a bidirectional linked list through all of its entries. This list defines the traversal order, usually the order inserted into the map.

  • It provides a special LinkedHashMap(int,float, Boolean) constructor to create a LinkedHashMap traversed in the order in which it was last accessed.

  • The removeEldestEntry(map.entry) method can be overridden to force the removal of expired mapping policies when a new mapping is added to the Map.

  • This class provides all optional map operations and allows null elements. Performance may be lower than a HashMap due to the additional overhead of maintaining a linked list, except for one: Collection-views traversing a LinkedHashMap need to be proportional to map.size, regardless of its capacity. The iteration of a HashMap looks more expensive because it also requires time proportional to its capacity.

  • The LinkedHashMap has two factors that affect its composition: the initial capacity and the load factor.

  • Note that this implementation is not thread-safe. If multiple threads concurrently access the LinkedHashMap, and at least one thread has modified the map, an external lock must be performed. It usually by synchronization in natural packaging collection of an object to achieve the Map m = Collections synchronizedMap (new LinkedHashMap (…). ).

  • This implementation holds the fail-fast mechanism.

Hashtable class

The Hashtable class implements a Hashtable that maps keys to values. Any non-empty object can be used as a key or value.

  • This implementation class supports the Fail-fast mechanism
  • Unlike the new collection implementation, Hashtable is thread-safe. If a thread-safe container is not required, HashMap is recommended, and if multiple threads are required with high concurrencyConcurrentHashMap.

IdentityHashMap class

IdentityHashMap is one of the more niche Map implementations.

  • This class is not a generic Map implementation! Although this class implements the Map interface, it deliberately violates the Map convention, which requires the equals method to be used when comparing objects, which is only applicable in rare cases where equality semantics need to be referenced.
  • Like HashMap, IdentityHashMap is unordered, and the class is not thread-safe and can be called if you want to make it thread-safeCollections.synchronizedMap(new IdentityHashMap(...) )Method to implement.
  • The FAIL-Fast mechanism is supported

WeakHashMap class

WeakHashMap class is based on Map base implementation of hash table, with weak keys. Entries in WeakHashMap are also automatically removed when they are no longer in use. More precisely, the existence of a mapping for a given key will not prevent the key from being discarded by the garbage collector.

  • Based on map interface, it is a kind of weak key connection. The key in WeakHashMap will be recovered automatically
  • Null values and null keys are supported.
  • Fast – fail mechanism
  • No repetition allowed
  • WeakHashMap is often used as a cache

The Collections classes

Collections is a separate branch of the Java framework inheritance tree. Collections is a wrapper class that provides some functionality for the Collections framework, including only static method operations or returning Collections.

Synchronous packaging

The synchronization wrapper adds automatic synchronization (thread-safety) to any collection. Each of the six core Collection interfaces (Collection, Set, List, Map, SortedSet, and SortedMap) has a static factory method.

public static  Collection synchronizedCollection(Collection c);
public static  Set synchronizedSet(Set s);
public static  List synchronizedList(List list);
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m);
public static  SortedSet synchronizedSortedSet(SortedSet s);
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m);

Copy the code

Unmodifiable packaging

Immutable wrapper by intercepting modify the collection of operation and throw UnsupportedOperationException, mainly used in the following two scenarios:

  • Build the collection and make it immutable. In this case, it is best not to fetch a reference that returns a collection, to ensure immutability
  • Allow some clients read-only access to your data structure. You keep references to the returned collection, but distribute references to the wrapper. In this way, customers can view but not modify, while maintaining full access.

These methods are:

public static  Collection unmodifiableCollection(Collection<? extends T> c);public static  Set unmodifiableSet(Set<? extends T> s);public static  List unmodifiableList(List<? extends T> list);public static <K,V> Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m);public static  SortedSet unmodifiableSortedSet(SortedSet<? extends T> s);public static <K,V> SortedMap<K, V> unmodifiableSortedMap(SortedMap<K, ? extends V> m);
Copy the code

Thread-safe Collections

Java1.5 and packaging (java.util.concurrent) provides thread-safe Collections that allow for modifications while traversing, By designing the iterator for the fail – fast and throw ConcurrentModificationException. Some implementation classes are CopyOnWriteArrayList, ConcurrentHashMap, CopyOnWriteArraySet

The Collections algorithm

This class contains methods for collection framework algorithms, such as binary search, sort, reorder, reverse, and so on.

Collection implements class feature diagrams

The following figure summarizes the characteristics of some of the main implementation classes of the collection framework, so that you can clearly see the differences between each implementation class

The generic

In Jdk1.5, a new concept was introduced: generics, so what are generics?

A generic is simply a parameterized collection that limits the types you can add to the collection. By its very nature, generics are parameterized types. Polymorphism can also be seen as a mechanism for generics. If a class inherits from a parent class, it can find its subclass through its parent class, but it cannot find the specific class through other classes. Generics are designed to be as expressive as possible for objects or methods.

Let’s look at an example of how not generics can be used

List arrayList = new ArrayList();
arrayList.add("cxuan");
arrayList.add(100);

for(int i = 0; i< arrayList.size(); i++){ String item = (String)arrayList.get(i); System.out.println("test === ", item);
}
Copy the code

This program does not work because an Integer cannot be cast directly to a String

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Copy the code

If we were to rewrite it with generics, the sample code would look like this

List<String> arrayList = newArrayList<String>(); arrayList.add(100);
Copy the code

This code will report errors at compile time, and the compiler will be able to find problems like this at compile time.

The use of generics

There are three ways to use generics: generic classes, generic interfaces, and generic methods. Let’s look at them together.

Represent classes with generics

Generics can be added to a class to represent the type of that class

// Here T can be written as any identifier. Common parameters such as T, E, K, V are used to represent generics
public class GenericDemo<T>{ 
    //value This member variable is of type T, which is externally specified
    private T value;

    public GenericDemo(T value) {
        this.value = value;
    }

    public T getValue(a){ // The generic method getKey returns a value of type T, the type of which is externally specified
        return value;
    }
 
 		public void setValue(T value){
	      this.value = value
    }
}
Copy the code

Represent interfaces with generics

Generic interfaces are defined and used in much the same way as generic classes.

// Define a generic interface
public interface Generator<T> {
    public T next(a);
}
Copy the code

Generic interfaces are often used in generators, which are equivalent to object factories, a class that is specifically used to create objects.

Generic method

You can use generics to represent methods

public class GenericMethods {
  public <T> void f(T x){ System.out.println(x.getClass().getName()); }}Copy the code

Generic wildcard

Unrestricted wildcard <? >

Lists are generic classes. To represent the parent classes of various generic lists, you can use type wildcards, which use question marks (?). Represents that its element type can match any type. For example,

public static void main(String[] args) {
    List<String> name = new ArrayList<String>();
    List<Integer> age = new ArrayList<Integer>();
    List<Number> number = new ArrayList<Number>();
    name.add("cxuan");
    age.add(18);
    number.add(314);
    generic(name);
    generic(age);
    generic(number);   
}

public static void generic(List
        data) {
    System.out.println("Test cxuan :" + data.get(0));
}
Copy the code

Upper bound wildcard

Using extends in a type parameter means that the parameter in the generic must be E or a subclass of E. This has two benefits:

  • If the type passed is not E or a subclass of E, editing fails
  • The E method can be used in generics, otherwise you have to cast to E to use it

Here’s an example:

private <K extends ChildBookBean, E extends BookBean> E test2(K arg1, E arg2){
    E result = arg2;
    arg2.compareTo(arg1);
    / /...
    return result;
}
Copy the code

Lower bound wildcard

Using super in type parameters indicates that the parameters in the generic must be E or a parent of E.

private <E> void add(List<? super E> dst, List<E> src){
    for(E e : src) { dst.add(e); }}Copy the code

As you can see above, DST is “greater than or equal to” SRC, where “greater than or equal to” means that DST represents a larger range than SRC, so a container that can hold DST can also hold SRC.

Wildcard comparison

We can see from the above example that the unrestricted wildcard <? Similar to Object, > is used for scenarios of unlimited or indeterminate scope.

Two restricted wildmatch forms <? Super E> and <? Extends E> is also a bit confusing.

They are all aimed at making method interfaces more flexible and able to accept a wider range of types.

<? Super E> is used to flexibly write or compare, so that objects can be written to the container of the parent type, so that the comparison method of the parent type can be applied to subclass objects. <? Extends E> is used for flexible reading, allowing methods to read container objects of any type E or E.

Type erasure for generics

There is one big difference between generics in Java and templates in C++ :

The instantiation of templates in C++ produces a different set of code for each type, known as code bloat. This problem does not occur in Java. There are no generic type objects in the virtual machine; all objects are ordinary classes. (from: blog.csdn.net/fw0124/arti…

In Java, generics are the concept of the Java compiler. Java programs written with generics are basically the same as normal Java programs, with more parameterized types and fewer type conversions.

In fact, Generic programs are first converted to Generic, non-generic Java programs and then processed. The compiler automatically translates from Generic Java to Generic Java, and the Java virtual machine runs with almost no knowledge of generics.

When a compiler compiles Java code with generics, it performs type checking and type inference, and then generates plain bytecodes without generics that can be received and executed by ordinary Java virtual machines. This is called type erasure.

In fact, regardless of whether you use generics or not, the data type of objects stored in the collection framework is Object, which can be seen not only from the source code, but also through reflection.

List<String> strings = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
System.out.println(strings.getClass() == integers.getClass());//true
Copy the code

The code above does not output false as expected, but true. The reason is the erasure of generics.

reflection

Reflection is a very important and advanced feature in Java, and basically Spring and other frameworks are written with reflection in mind. Let’s first look at what the reflex is.

Java reflection mechanism is in the process of running a program, for any class, can know all its properties and methods; For any object, any attribute and method can be known to call it. The function of dynamically obtaining information and dynamically calling object methods is called reflection mechanism of Java language.

To dissect a class, you must first retrieve the bytecode file object for that class. The methods used in the Class Class are dissected, so the object of Class type corresponding to each bytecode file must be obtained first.

The reflection is actually getting the bytecode file of the class, the.class file, so we can get it from the class object.

The Java reflection mechanism provides the following functions

  • Determine the class to which any object belongs at run time
  • Constructs an object of any class at run time
  • Determine all member variables and methods of any class at run time
  • Call a method of any object at run time

In this way, reflection is like a global player. No matter how your program is running, I know what properties and methods your class has, and who is calling your object.

In Java, the reflection mechanism is implemented using the java.lang.Reflect package. The classes java.lang.Reflect designs are as follows

Here is a simple reflection class

public class Person {
    public String name;/ / name
    public int age;/ / age
 
    public Person(a) {
        super(a); }public Person(String name, int age) {
        super(a);this.name = name;
        this.age = age;
    }
 
    public String showInfo(a) {
        return "name=" + name + ", age="+ age; }}public class Student extends Person implements Study {
    public String className;/ / class
    private String address;/ / address
 
    public Student(a) {
        super(a); }public Student(String name, int age, String className, String address) {
        super(name, age);
        this.className = className;
        this.address = address;
    }
 
    public Student(String className) {
        this.className = className;
    }
 
    public String toString(a) {
        return "Name:" + name + ", age: + age + Class: + className + Address:"
                + address;
    }
 
    public String getAddress(a) {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address; }}public class TestRelect {
 
    public static void main(String[] args) {
        Class student = null;
        try {
            student = Class.forName("com.cxuan.reflection.Student");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
 
        // Get all the public attributes of the object.
        Field[] fields = student.getFields();
        for (Field f : fields) {
            System.out.println(f);
        }
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
        // Get all attributes of the object except inherited ones.
        Field[] declaredFields = student.getDeclaredFields();
        for (Field df : declaredFields) {
            System.out.println(df);
        }
      
      	// Get all the public methods of the object
        Method[] methods = student.getMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
        // Get all methods of the object, but not inherited ones
        Method[] declaredMethods = student.getDeclaredMethods();
        for (Method dm : declaredMethods) {
            System.out.println(dm);
        }
				
      	// Get all the public constructors of the object
        Constructor[] constructors = student.getConstructors();
        for (Constructor c : constructors) {
            System.out.println(c);
        }
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
        // Get all the constructors of the object
        Constructor[] declaredConstructors = student.getDeclaredConstructors();
        for (Constructor dc : declaredConstructors) {
            System.out.println(dc);
        }
      
      	Class c = Class.forName("com.cxuan.reflection.Student");
      	Student stu1 = (Student) c.newInstance();
      	// The first method instantiates the default constructor and calls set assignment
        stu1.setAddress("Shijiazhuang, Hebei");
        System.out.println(stu1);

        // The second method gets all constructors using constructor assignments
        Constructor<Student> constructor = c.getConstructor(String.class, 
                                                            int.class, String.class, String.class);
        Student student2 = (Student) constructor.newInstance("cxuan".24."Six"."Shijiazhuang");
        System.out.println(student2);

        /** * get method and execute method */
        Method show = c.getMethod("showInfo");// Get showInfo()
        Object object = show.invoke(stu2);// Call showInfo()}}Copy the code

Some of them are more commonly used, some of them I haven’t seen yet, and here’s a category.

The main classes related to Java reflection are

Class Class

In Java, you generate a class object for every Java Class entity you define. That is, when we write a class and compile it, the generated.class file produces a class object that represents the type information of the class. There is no common constructor in a Class, which means that Class objects cannot be instantiated. Let’s take a quick look at what methods the Class Class includes

toString()

public String toString(a) {
  return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
    + getName();
}
Copy the code

The toString() method converts an object to a string. ToString () determines whether a Class type is an interface type. That is, ordinary classes and interfaces can be represented by Class objects. There’s also void.

All types are as follows

  • Java.lang. Boolean: A wrapper class that represents a Boolean data type
  • Java.lang.Character: Wrapper class that represents the char data type
  • Java.lang. Byte: Wrapper class that represents the Byte data type
  • Java.lang. Short: Wrapper class that represents the Short data type
  • Java.lang. Integer: Wrapper class representing the int data type
  • Java.lang. Long: Wrapper class that represents the Long data type
  • Java.lang. Float: A wrapper class that represents the Float data type
  • Java.lang.Double: Wrapper class that represents the Double data type
  • Java.lang.Void: Wrapper class that represents the Void data type

Then there is the getName() method, which returns the fully qualified name of the class.

  • If it is a reference type, such as string.class.getName () ->java.lang.String
  • For basic data types, byte.class.getName() ->byte
  • New Object[3]).getClass().getName() ->[Ljava.lang.Object

toGenericString()

This method returns the fully qualified name of the class and includes the class’s modifiers and type parameter information.

forName()

Gets a reference to a Class object based on the Class name. This method initializes the Class object.

For example, Class t = class.forname (” java.lang.thread “) initializes a Thread object

There are three ways to get an instance of a class in Java

  • Class.forName(java.lang.Thread)
  • Thread.class
  • thread.getClass()

newInstance()

Creates an instance of a class that represents objects of that class. The forName() method above initializes the class and the newInstance method instantiates the class.

getClassLoader()

Gets the classloader object.

getTypeParameters()

Gets the object’s parameter type information in the declared order.

getPackage()

Returns the package of the class

getInterfaces()

Get the current Class implementation of the Class or interface, may be multiple, so return the Class array.

Cast

Converts an object to an object that represents a class or interface

asSubclass(Class clazz)

Converts the object of the passed class to an object representing its subclasses

getClasses()

Returns an array containing objects for all public and interface classes in that class

getDeclaredClasses()

Returns an array containing objects for all classes and interface classes in that class

getSimpleName()

Gets the name of the class

getFields()

Get all public property objects

getField(String name)

Gets a public property object

getDeclaredField(String name)

Get a property object

getDeclaredFields()

Get all property objects

getAnnotation(Class annotationClass)

Returns the public annotation object in this class that matches the parameter type

getAnnotations()

Returns all public annotation objects for the class

getDeclaredAnnotation(Class annotationClass)

Returns all annotation objects in the class that match the parameter type

getDeclaredAnnotations()

Returns all the annotation objects for the class

getConstructor(Class… <? > parameterTypes)

Gets the public constructor of the class that matches the parameter type

getConstructors()

Gets all public constructors for the class

getDeclaredConstructor(Class… <? > parameterTypes)

Gets the constructor of the class that matches the parameter type

getDeclaredConstructors()

Gets all constructors for the class

getMethod(String name, Class… <? > parameterTypes)

Gets a public method of that class

getMethods()

Gets all public methods of the class

getDeclaredMethod(String name, Class… <? > parameterTypes)

Gets a method of that class

getDeclaredMethods()

Get all methods of the class

The Field class

The Field class provides information about individual fields in a class or interface, as well as dynamic access to individual fields.

The specific method is not introduced here, readers interested can refer to the official API

Here are just a few common ones

equals(Object obj)

Property equal to obj returns true

get(Object obj)

Get the corresponding attribute value in obj

set(Object obj, Object value)

Set the corresponding property value in obj

Method the class

invoke(Object obj, Object… args)

Pass an object and its parameters to call the corresponding method of the object

This class

Another very important class in reflection is the ClassLoader class, which is used to load classes into the JVM. Classloaders use the parent delegate model to search for loaded classes, which is also known as the parent delegate model. The class inheritance diagram for ClassLoader is shown below

After learning to reflect, I was hired! (dry)

The enumeration

Enumerations are probably the feature we use less often. In Java, enumerations are represented by the enum keyword. Enumerations are actually a very useful feature, and you can think of them as classes with specific properties. Enum is not only in Java, but also in C and C++. Here is an example of an enumeration.

public enum Family {

    FATHER,
    MOTHER,
    SON,
    Daughter;

}
Copy the code

Above we created a Family enumeration class with four values, all in uppercase letters because the enumeration types are constants. So how do you refer to enum?

public class EnumUse {

    public static void main(String[] args) { Family s = Family.FATHER; }}Copy the code

Enumeration features

When you create an enum, the compiler automatically adds the toString() method to your enum. It allows you to display the name of the enum instance. In addition to the toString() method, the compiler adds the ordinal() method, which represents the order in which enum constants are declared, and the values() method displays the order of values.

public static void main(String[] args) {

  for(Family family : Family.values()){
    System.out.println(family + ", ordinal"+ family.ordinal()); }}Copy the code

Enum The package can be statically imported without entering the enumeration class name. Constants, you can just use constants, isn’t that amazing? You can statically import packages using the ennum and static keywords

The above code imports all constants in Family, or you can specify constants separately.

Enumerations are the same as normal classes

Enumerations are just like ordinary classes. Except for the convenience of defining constants in enumerations, we can use enumerations to define public static final XXX. You can define properties and methods in enumerations, too. Don’t think of it as an outlier, it’s one of a million classes.

public enum OrdinalEnum {

    WEST("live in west"),
    EAST("live in east"),
    SOUTH("live in south"),
    NORTH("live in north");

    String description;

    OrdinalEnum(String description){
        this.description = description;
    }

    public String getDescription(a) {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public static void main(String[] args) {
        for(OrdinalEnum ordinalEnum : OrdinalEnum.values()){ System.out.println(ordinalEnum.getDescription()); }}}Copy the code

Generally, switch can be used with enum to construct a small state transition machine.

enum Signal {
  GREEN, YELLOW, RED
}

public class TrafficLight {
    Signal color = Signal.RED;

    public void change(a) {
        switch (color) {
        case RED:
            color = Signal.GREEN;
            break;
        case YELLOW:
            color = Signal.RED;
            break;
        case GREEN:
            color = Signal.YELLOW;
            break; }}}Copy the code

Does the code suddenly feel a little cleaner and more elegant?

Enumerate the mysteries

In Java, everything is an object. Enum is a keyword, but it implicitly inherits from the enum class. Let’s take a look at the Enum class, which is in the java.lang package and can be referenced automatically.

This class has fewer properties and methods. You’ll notice that our values method is missing from this class. As mentioned earlier, values() is the static method that the compiler adds when you use enumerations. You can verify this using reflection.

In addition, enum has an intersection with the Class Class, where there are three methods on enum

The first two methods are used to get enum constants, and isEnum is used to determine if an enum is used.

Enumeration class

In addition to enums, there are two utility classes you need to know about enumerations: EnumSet and EnumMap

Enumsets and EnumMap

Introduced in JDK1.5, EnumSet is designed with speed in mind and can be used as an efficient alternative to Enum.

EnumMap is a special Map that requires the key value to come from an enum. Because EnumMap is also fast, we can use EnumMap for quick key lookups.

In general, enumerations aren’t that complicated to use, and they’re a small piece of Java functionality, but sometimes you can make your code elegant and clean with just one little trick.

I/O

Creating a good I/O program is very complex. JDK developers write a lot of classes just to be able to create a good toolkit, and writing an I/O toolkit must be a lot of work.

The IO class is designed to solve IO related operations. The most common I/O read and write operations are networks and disks. In Java, operating on a file is a typical I/O operation. Let’s make a classification of I/O.

I/ OS can also be distinguished by operation objects

In addition, there are other classes that are important in I/O

The File type

The File class is a class that operates on files and folders in the File system. You can manipulate files and folders with object-oriented thinking. Isn’t it amazing?

File creation involves creating, deleting, and obtaining file descriptors

class FileDemo{
   public static void main(String[] args) {
       File file = new File("D:\\file.txt");
       try{
         f.createNewFile(); // Create a file
         
         // Two constants of the File class
         // Path delimiter (system specific) < Windows is; In Linux: >
        System.out.println(File.pathSeparator);  / /;
        // System-specific path name delimiter < Windows yes/Linux yes / >
        System.out.println(File.separator);      / / /
         
         // Delete files
         /* File file = new File(fileName); if(f.exists()){ f.delete(); }else{system.out.println (" file does not exist "); } * /

         
       }catch(Exception e) { e.printStackTrace(); }}}Copy the code

You can also operate on folders

class FileDemo{
  public static void main(String[] args) {
    String fileName = "D:"+ File.separator + "filepackage";
    File file = new File(fileName);
    f.mkdir();
    
		// List all files
    /* String[] str = file.list(); for (int i = 0; i < str.length; i++) { System.out.println(str[i]); } * /
    
    / / using the file. ListFiles (); Lists all files, including hidden files
    
    // Use file.isdirectory () to determine whether the specified path is a directory}}Copy the code

The above are just two simple examples. In fact, there are some other operations on files that are not used. Creating a file, for example, can be done in one of three ways

File(String directoryPath);
File(String directoryPath, String filename);
File(File dirObj, String filename);
Copy the code

DirectoryPath is the path name of the File, filename is the File name, and dirObj is a File object. For example,

File file = new File("D:\\java\\file1.txt");  // double \\ is an escape
System.out.println(file);
File file2 = new File("D:\\java"."file2.txt");// Parent path, child path - can be applied to multiple files!
System.out.println(file2);
File parent = new File("D:\\java");
File file3 = new File(parent,"file3.txt");//File Class parent path, child path
System.out.println(file3);
Copy the code

Now summarize the File class

Basic IO classes and related methods

There are many. IO classes, but the most basic are four abstract classes: InputStream, OutputStream, Reader, and Writer. The most basic methods are the read() and write() methods, from which all other streams are subclasses and from which methods are derived. And most of the IO source code is native logo, that is, the source code is written in C/C++. Let’s take a look at these stream classes and their methods

InputStream

InputStream is an abstract class that defines Java stream byte input patterns. All methods of this class raise an IOException exception in the event of an error condition. Its main methods are defined as follows

OutputStream

OutputStream is an abstract class that defines the stream byte output pattern. All methods of this class return a void value and raise an IOException in case of an error. Its main methods are defined as follows

Reader class

Reader is an abstract class for the Java-defined streaming character input pattern. Methods in a class raise IOException when an error occurs.

Writer class

Writer is an abstract class that defines streaming character output. All methods of this class return a void value and raise IOException in case of an error

InputStream and its subclasses

FileInputStream: The FileInputStream class creates an InputStream class that reads bytes from a file

ByteArrayInputStream ByteArrayInputStream: a buffer in memory is used as an InputStream

PipedInputStream Pipe input stream: Implements the concept of a PIPE pipe and is primarily used in threads

SequenceInputStream Sequential input streams: Combine multiple InputStreams into one InputStream

FilterOutputStream Filter input stream: wrapper for other input streams.

ObjectInputStream Deserializes input stream: Restores the original data previously serialized with ObjectOutputStream to an object and reads the object as a stream

DataInputStream: a DataInputStream allows an application to read basic Java data types from the underlying input stream in a machine-independent manner.

PushbackInputStream: A novel use of buffering is to implement pushback. Pushback is used to input the stream to allow bytes to be read and then returned to the stream.

OutputStream and its subclasses

FileOutputStream: This class implements an output stream whose data is written to a file.

ByteArrayOutputStream: This class implements an output stream whose data is written to a buffer of byte arrays that grows automatically as data is written.

PipedOutputStream: The output stream of a pipe, which is the sender of the pipe.

ObjectOutputStream Primitive type output stream: this class serializes an object that has been serialized and writes to the specified location.

FilterOutputStream FilterOutputStream: wrapper for other output streams.

PrintStream Allows you to print text to a file or network.

DataOutputStream: a DataOutputStream allows an application to write basic Java data types to the underlying output stream in a machine-independent manner.

Reader and its subclasses

FileReader file character input stream: Converts a file to a character stream read in

CharArrayReader: is an implementation of an input stream that takes an array of characters as its source

BufferedReader Buffer input stream: The BufferedReader class reads text from the character input stream and buffers characters to efficiently read characters, arrays, and lines

PushbackReader: The PushbackReader class allows one or more characters to be sent back to the input stream.

PipedReader input stream: The main purpose of PipedReader is also to communicate between threads, but this can be used to transfer characters

Writer and its subclasses

FileWriter: FileWriter creates a Writer class that can write to files.

CharArrayWriter Character array output stream: CharArrayWriter implements an output stream that targets arrays.

BufferedWriter Buffer output stream: BufferedWriter is a Writer with the flush() method added. The flush() method can be used to ensure that the data buffer is actually written to the actual output stream.

**PrintWriter ** : PrintWriter is essentially a character version of PrintStream.

PipedWriter pipe output stream: The main purpose of PipedWriter is also to communicate between threads, but this can be used to transfer characters

Java’s streaming interface for input and output provides a neat abstraction for complex and onerous tasks. The combination of filter stream classes allows you to dynamically create client-side streaming interfaces to match data transfer requirements. Java programs that inherit from the advanced InputStream, InputStreamReader, Reader, and Writer classes can be used reasonably in the future, even when new and improved concrete classes are created.

For an in-depth understanding of Java IO, you can read this article by The author for an in-depth understanding of Java IO

annotations

Java annotations, also known as metadata, provide a formal way to add information to your code. Introduced in JDK1.5, Java defines a set of seven annotations, three in java.lang and four in java.lang.annotation.

There are three annotations that apply to the code

  • @Override: override flag, used when a subclass inherits its parent class and marks the method of the overridden subclass. If the method is not found in the parent class or in the referenced interface, a compilation error is reported.
  • @Deprecated: The code annotated with this annotation is outdated and no longer recommended
  • @SuppressWarningsThis annotation ignores the compiler’s warning

There are four meta-annotations, which are the annotations used to mark the annotations. They are

  • @Retention: Identifies how it is stored, whether it is stored only in code, marshaled in a class file, or accessible by reflection at run time.

Retentionpolicy. SOURCE: Annotations are retained only in the SOURCE file. When Java files are compiled into class files, annotations are discarded.

Retentionpolicy. CLASS: Annotations are kept in the CLASS file, but are discarded when the JVM loads the CLASS file, which is the default lifecycle;

Retentionpolicy. RUNTIME: Annotations are not only saved to the class file, but still exist after the JVM loads the class file.

  • @Documented: marks whether these annotations are included in JavaDoc.
  • @Target: Mark this Annotation describes the range of objects that the Annotation is modifying, Annotations can be used for packages, types (classes, interfaces, enumerations, Annotation types), type members (methods, constructors, member variables, enumerated values), method parameters, and local variables (such as loop variables, catch parameters). The following values
public enum ElementType {
    TYPE, 						// Classes, interfaces, annotations, enumerations
    FIELD,						/ / field
    METHOD,						/ / method
    PARAMETER,				/ / parameters
    CONSTRUCTOR,			// constructor
    LOCAL_VARIABLE,		// Local variables
    ANNOTATION_TYPE,	/ / comment
    PACKAGE,					/ / package
    TYPE_PARAMETER,		// Type parameter
    TYPE_USE					// Type use
Copy the code
  • @Inherited: marks the annotation class from which the annotation is inherited.

Since JDK1.7, three additional annotations have been added, which are

  • SafeVarargs: The Java compiler will emit an unchecked warning when declaring variadic constructors or methods. You can ignore these warnings with @safevarargs

  • @functionalinterface: indicates that this method is a FunctionalInterface

  • Repeatable: Indicates that an annotation can be used multiple times on the same statement.

Note: Annotations do not support inheritance.

The life cycle of annotations

Annotations also have a corresponding declaration cycle and are encapsulated in an enumerated class: RetentionPolicy:

  • SOURCE: During the SOURCE code, it is removed at compile time, so it is all for the compiler to use.
  • CLASS: is retained in the CLASS file, but not required by the JVM at runtime, the default life cycle.
  • RUNTIME: is saved until the JVM runs and can be retrieved by reflection.

The statement period is used in conjunction with @retention as follows:

@Retention(RetentionPolicy.RUNTIME)
Copy the code

Generally speaking, the lifecycle of annotations used to write frameworks is RUNTIME.

Several ways to handle null

Null Pointers have always been an annoying problem for Java programmers, and nullPointerExceptions often plague our development efforts. Java’s inventors also acknowledged that this was a huge design mistake.

Here are a few things you should know about NULL to effectively understand it and avoid many null-induced errors.

Case sensitivity

First, NULL is a Java keyword, such as **public, static, and final. ** It is case sensitive, you cannot write NULL as NULL or null, the editor will not recognize them and report an error.

This problem is almost nonexistent because the Eclipse and Idea compilers already give compiler hints, so you don’t have to worry about it.

Null is the initial value for any reference type

Null is the default value for all reference types. Any reference variable in Java uses NULL as the default value. That is, all reference types under Object are null by default. This is true for all reference variables. Just like the default values for primitive types, for example, int defaults to 0 and Boolean defaults to false.

Here are the initial values for the basic data types

Null is just a special kind of value

Null is neither an object nor a type. It is just a special value that you can assign to any type. You can convert NULL to any type

public static void main(String[] args) {
  String str = null;
  Integer itr = null;
  Double dou = null;

  Integer integer = (Integer) null;
  String string = (String)null;

  System.out.println("integer = " + integer);
  System.out.println("string = " + string);
}
Copy the code

As you can see, it is possible to convert NULL to any reference type at compile time and run time without throwing a null-pointer exception.

Null can only be assigned to reference variables, not primitives.

A wrapper class that holds NULL cannot be converted when unboxing itself, throws a null pointer exception, and null cannot be compared to a primitive data type

public static void main(String[] args) {
  int i = 0;
  Integer itr = null;
  System.out.println(itr == i);
}
Copy the code

A reference type variable with a null value is used,instanceofThe action returns false

public static void main(String[] args) {
  Integer isNull = null;
  // instanceof = isInstance
  if(isNull instanceof Integer){
    System.out.println("isNull is instanceof Integer");
  }else{
    System.out.println("isNull is not instanceof Integer"); }}Copy the code

This is an important feature of the Instanceof operator, which makes casting checks useful

Calling a static method with a static variable null does not throw a NullPointerException. Because static methods use static binding.

Use the null-safe method

You should use null-safe methods. There are many utility classes in the Java class library that provide static methods, such as wrapper classes for primitive data types, Integer, Double, and so on. For example,

public class NullSafeMethod {

    private static String number;

    public static void main(String[] args) {
        String s = String.valueOf(number);
        String string = number.toString();
        System.out.println("s = " + s);
        System.out.println("string = "+ string); }}Copy the code

The String. Value (number) static method does not raise a null-pointer exception, but toString() does. So use static methods of objects whenever possible.

Null judgments

You can use == or! The = operation compares null values, but no other algorithm or logical operation, such as less than or greater than, can be used. Unlike SQL, null == null in Java returns true, as shown below:

public class CompareNull {

    private static String str1;
    private static String str2;

    public static void main(String[] args) {
        System.out.println("str1 == str2 ? " + str1 == str2);
        System.out.println(null= =null); }}Copy the code

The last

If the article is helpful to you, I hope you give me a thumbs-up!!