polymorphism

  • That is, the same method can behave differently depending on the object being sent

  • The actual type of an object is determined, but there can be many references to the object

  • Conditions for the existence of polymorphism

    • Have a hereditary relationship
    • A subclass overrides a parent class method
    • A superclass reference points to a subclass object

    Note:

    1. A polymorphism is a polymorphism of methods, without attributes
    2. Parent and subclass, associated type conversion exception: ClassCastException
    3. Conditions: inheritance relationships, methods need to be overridden, and parent class references point to subclass objects!

Instanceof and type conversion

  • Instanceof reference type comparison to determine what type an object is
Object object = new Student();        System.out.println(object instanceof Student);        System.out.println(object instanceof Person);        System.out.println(object instanceof Object);        System.out.println(object instanceof Teacher);        System.out.println(object instanceof String);        System.out.println("= = = = = = = = = = = = = = = = = = = = = =");        Person person = new Student();        System.out.println(person instanceof Student);        System.out.println(person instanceof Person);        System.out.println(person instanceof Object);        System.out.println(person instanceof Teacher);// System.out.println(person instanceof String); System.out.println("======================="); Student student = new Student(); System.out.println(student instanceof Student); System.out.println(student instanceof Person); System.out.println(student instanceof Object); // System.out.println(student instanceof Teacher); // System.out.println(student instanceof String);

Copy the code
  • Type conversion
    • A parent class refers to an object that points to a child class
    • By converting a subclass to a parent class, going up, you lose some of your original methods
    • The parent class is converted to a subclass, cast down, and then the subclass method is called
    • Convenient method call (transformation), reduce repeated code, concise

Polymorphism:

  • Understanding polymorphism: Can be understood as many forms of the same thing

  • What is polymorphism:

    • Object polymorphism: references from a parent class to an object of a child class (or references from an object of a child class to a parent class)

  • Use of polymorphism:

    • With the use of polymorphism, we can only call methods declared by the parent class at the compiler, but at run time, we actually perform subclass override methods of the parent class

  • Analysis of s. move ();

    • Java programs are divided into compile phase and run phase

      1. First, analyze the compilation phase:

        • The compiler only knows that the type of s is Animal, so when the compiler checks the syntax, it looks for the move() method in the animal. class bytecode file. If it finds the move() method, it will bind it. (The compilation phase is static binding phase)

      2. Continue to analyze the operation stage:

    • In the run phase, the Java object created in the heap is a Cat object, so when move() is implemented, a Cat is actually involved in move(), so the run phase dynamically executes the move() method of the Cat object.
    • But when it is run, it is related to the actual object in the underlying heap, and when it is executed, it calls the related methods of the real object.
  • Summary: Compile, look at the left. Execute (run), look to the right.

  • Object polymorphism: applies only to methods, not attributes.

  • The preconditions of polymorphism are: ① inheritance relation of class ② rewriting of method

  • Use of the instanceof keyword:

    • A instanceof a: checks whether object a is an instanceof class a. if so, return true; if not, return false
    • Usage scenario: To avoid ClassCastException during the downward transition, we perform instanceof judgment before the downward transition. Once true is returned, the downward transition is immediately performed, and if false is returned, the downward transition is stopped.
    • If an instanceof a returns true, a instanaceof B will also return true.

Practice notes:

  1. If a subclass overrides a method of the parent class, it means that the method defined by the subclass completely overrides a method of the parent class with the same name and parameter, and the system will not be able to transfer a method from the parent class to the subclass
  2. This is not the case with instance variables. Even if a subclass defines an instance variable identical to the parent class, that instance variable cannot override the instance variable defined in the parent class: compile to the left, run to the right.

With the polymorphism of the object, memory actually loads subclass-specific properties and methods. But since the variable is declared as a parent type

As a result, only properties and methods declared in the parent class can be called at compile time. Subclass-specific properties and methods cannot be called.

How can I call properties and methods in subclasses? *

Downcast: Use forced type conversions. Disadvantages: Loss of accuracy


Super qualified

If you need to call an instance method whose parent class is overridden in a subclass method. You can use the super qualification to call instance methods whose parent class is overridden. Add a method to the above Ostrich class that calls the fly method overridden in the Bird class.

public void callOverrideMethod(a)
{
    // Explicitly call the instance method overridden by the parent class in a subclass method via super
    super.fly();
}
Copy the code

Super is a keyword provided by Java to restrict the object to calling instance variables or methods that it inherits from its parent class. Just as this cannot appear in static modified methods, super cannot appear in static modified methods. Static modified methods belong to classes. The caller to this method may be a class rather than an object, so the super qualification is meaningless.

If you use super in a constructor, super qualifies the constructor to initialize instance variables that the object inherits from its parent class, not instance variables defined by the class itself.

If a subclass defines an instance variable with the same name as the parent class. The subclass instance variable hides the parent class instance variable. Under normal circumstances, methods defined in a subclass that access instance variables directly access instance variables defined in a subclass by default.

Cannot access a hidden instance variable in the parent class. Instance variables hidden in the parent class can be accessed by super in instance methods defined by subclasses.

The following code looks like this:

class BaseClass
{
    public int a = 5;
}
public class SubClass extends BaseClass
{
    public int a = 7;
    public void accessOwner(a)
    {
        System.out.println(a);
    }
    public void accessBase(a)
    {
        // Restrict access to instance variables of A inherited from the parent class by using super
        System.out.println(super.a);
    }
    public static void main(String[] args)
    {
        SubClass sc = new SubClass();
        sc.accessOwner(); / / output 7
        sc.accessBase(); / / output 5}}Copy the code

Both BaseClass and SubClass of the above program define instance variables named A. The a instance variable of SubClass will hide the A instance variable of BaseClass. When the system creates a SubClass object, it actually allocates two pieces of memory for the SubClass object.


If the subclass does not contain a member variable with the same name as the parent class. When accessing the member variable in a subclass instance method, there is no need to explicitly use super or the superclass name as the caller. If a member variable named A is accessed in a method, but the caller is not explicitly specified, the system looks for a in the following order:

  • Find if the method has a local variable named A.
  • Find the current; Whether the class contains a member variable named A.
  • Find if a’s immediate parent contains a member variable named A, tracing all of a’s parents up. Until the java.lang.Object class.
  • If the member variable named A cannot eventually be found, a compilation error occurs.

If the overridden class variable is a class variable, the method of the subclass can access the overridden class variable through the parent class name as the caller.

Bump: when the program creates a subclass object. The system allocates memory not only for instance variables defined in this class. It also allocates memory for all instance variables it inherits from its parent class. Even if a subclass defines an instance variable with the same name as the parent class. That is, when the system creates a Java object. If the Java class has two parents (one direct parent A and one indirect parent B) assume that two instance variables are defined in class A and three instance variables are defined in class B. If there are two instance variables defined in the current class, this Java object will hold 2 + 3 + 2 instance variables.


Because an instance variable defined in a subclass with the same name as the parent does not completely override the instance variable defined in the parent class, it simply hides the instance variable defined in the parent class, the following special cases occur:

class Parent
{
    public String tag = "Sun Wukong";
}
class Derived extends Parent
{
    // Define a private tag instance variable to hide the parent class's tag instance variable
    private String tag = "Pig Eight Quit";
}
public class HideTest
{
    public static void main(String[] args)
    {
        Derived d = new Derived();
        // The program cannot access d's private variable tag, so the following statement will cause a compilation error
        //System.out.println(d.tag);
        // We can access the tag instance variable by explicitly upcasting the d variable to Parent
        // The program will output Sun WukongSystem.out.println(((Parent)d).tag); }}Copy the code

The Parent class defines a tag instance variable. Its subclass, Derived, defines a private tag instance variable. The instance variable defined in the subclass will hide the tag instance variable defined in the parent class.

The entry to the program, the Main () method, creates a Derived object first. The Derived object will hold two tag instance variables. One is the tag instance variable defined in Parent. One is the tag instance variable defined in the Derived class. So we have a d variable in our program.

It refers to a Derived object, stored in memory as follows:

Next, the program assigns the Derived object to the D variable. Next, the program attempts to access the tag instance variable through D and is prompted that access is not allowed. Next, the d variable is forced up to the Parent type. It is allowed to access tag instance variables again.

Invoke the parent class constructor

Subclasses do not get the parent class’s constructor.

But the subclass constructor can call the initialization code of the parent constructor.

A constructor similar to the one described earlier can call another overloaded constructor.

A constructor that calls another overloaded constructor in one constructor completes the call using this.

Calling the superclass constructor in the subclass constructor is done using a super call.

The Sub class is a subclass of the Base class. The program uses super in the constructor of the Sub class to call the constructor initialization code of the Base class.

class Base
{
    public double size;
    public String name;
    public Base(double size, String name)
    {
        this.size = size;
        this.name = name; }}public class Sub extends Base
{
    public String color;
    public Sub(double size, String name, String color)
    {
        // Call the initialization of the parent constructor with a super call
        super(size, name);
        this.color = color;
    }
    public static void main(String[] args)
    {
        Sub s = new Sub(5.6."Pikachu"."Yellow");
        // Outputs three instance variables of the Sub object
        System.out.println(s.size + "--" + s.name + "--"+ s.color); }}Copy the code

As you can see from the above program, using a super call is also very similar to using this. The difference is that super calls the constructor of its parent class, while this calls the overloaded constructor of the same class. Therefore, calling the superclass constructor with super must also appear on the first line of the subclass constructor’s body. So the this call and the super call don’t happen together.

Whether or not a super call is used to execute the initialization code for the parent constructor. The subclass constructor always calls the superclass constructor once.

The subclass constructor calls the parent constructor in the following ways:

  • The first line of the subclass constructor body explicitly calls the superclass constructor using super. The constructor for the parent class will be called based on the argument list passed in the super call.
  • The first line of the subclass constructor body explicitly calls the overloaded constructor of the class using this. The system will call another constructor of the class based on the list of arguments passed in the this call. The parent constructor is called when another constructor in the class is executed.
  • There is no super or this call in the subclass constructor body, and the system implicitly calls the constructor with no arguments in its parent class before executing the subclass constructor.

In either case, when the subclass constructor is called to initialize the subclass object. The superclass constructor is always executed before the subclass constructor: not only that, when the superclass constructor is executed, the system executes the parent constructor up again… The java.lang.Object constructor is always executed first when creating any Java Object.

For the inheritance tree shown below.

If you create a ClassB Object, the constructor of the java.lang.Object class is executed first. Then execute the ClassA constructor. The ClassB constructor is then executed. This implementation is still the most basic case. If ClassB explicitly calls ClassA’s constructor, and that constructor calls an overloaded constructor in the ClassA class, you’ll see that both ClassA constructors execute one after the other.

The following program defines three classes with strict inheritance relationships between them. This inheritance gives you a look at the call relationships between constructors.

class Creature
{
    public Creature(a)
    {
        System.out.println("Creature no-parameter constructor"); }}class Animal extends Creature
{
    public Animal(String name)
    {
        System.out.println("Animal with one parameter constructor," + "The animal's name is :" + name);
    }
    public Animal(String name, int age)
    {
        // Call the same overloaded constructor with this
        this(name);
        System.out.println("Animal two-parameter constructor," + "The age is :"+ age); }}public class Wolf extends Animal
{
    public Wolf(a)
    {
        // Explicitly calls a constructor whose parent class has two arguments
        super(The Big Bad Wolf.3);
        System.out.println("Wolf no-argument constructor");
    }
    public static void main(String[] args)
    {
        newWolf(); }}Copy the code

The main method of the above program creates only one Wolf object. But the system performs complex operations at the bottom. Run the above program and see the following results:

The Creature with one parameter is Creature with two parameters and its age is3Wolf no-argument constructorCopy the code

From the above running process. The creation of any object always starts with the constructor of the class at the top of the inheritance tree of that class. And then you go down. The constructor for this class is executed last. If a parent class calls an overloaded constructor of its class through this. Multiple constructors of the parent class are executed in turn


super&this

Super:

  1. Super calls the constructor of the parent class, which must be the first constructor

  2. Super must only appear in methods or constructors of subclasses

  3. Super and this cannot notify the call constructor

  4. We can do it in a subclass method or constructor. By using “super. property” or “super. method”, the display invokes properties and methods in the parent class, but in general, the “super” keyword is usually omitted.

  5. In a special case, if we want to call a property declared by the parent class, we must display “super” when a property of the same name is defined in a subclass or a parent class. Property, indicating that the property declared in the parent class is called

  6. In a special case, we must explicitly use “super” when we want to call a method in a subclass that overrides a method in its parent class. Method, indicating that the method in the parent class is called.

VS this:

  • Different objects are represented

    • This: calls the object itself

    • Super: can be tried only under inheritance conditions

  • A constructor

    • This () : Construction of this class

    • Super () : Construction of the parent class

    • We can call the specified constructor declared in the parent class in a manner applicable to “super.” (row argument list) as shown in the constructor of the subclass

    • The use of “super.” must be declared on the first line of the subclass constructor!

    • We can only choose between “this.” (row argument list) or “super.” (row argument list) in the constructor of the class.

    • Without a declaration “this.” or “super.” displayed on the first line of the constructor, the constructor for empty arguments in the parent class is called by default.

    • Super is not a reference,super does not hold memory addresses, and super does not point to any objects

    • Super simply represents the characteristics of the piece of parent class inside the current object.

  • The difference between super and this: super represents a reference to a parent object and can only be used under inheritance conditions. This can also be used without inheritance relationship

    super(a);// Hide the code, the default call to the parent class without arguments construction, to write only the first line
    
    Copy the code


Summary: Method overloading and overwriting

  • From a compile and run perspective:
    • Overloading allows multiple methods with the same name that take different arguments. The compiler modifies the name of a method based on its argument list. To the compiler, these methods with the same name become different methods. Their call addresses are bound at compile time. Java overloading can include superclasses and subclasses, that is, subclasses can override methods with the same name and different arguments as the parent class.
    • So in the case of overloading, the method to be called is determined before the method is called, which is called “early binding” or “static binding.”
    • With polymorphism, the compiler does not determine which method is called until the moment the method is called. This is called “late binding” or “dynamic binding”
    • “Don’t be silly, just make sure he’s not late bound and he’s not polymorphic!”

Process knowledge

JavaBean

  • A JavaBean is a Java class that conforms to the following:

  • Classes are public

  • There is a constructor with no arguments

  • It has properties, and it has corresponding set and get methods.

  • Users can use Javabeans to package functionality, processing, database access, and any other objects that can be created in Java code, and other developers can use these objects through internal JSP pages, servlets, and other Javabeans programs or applications. Users can think of Javabeans as providing a copy-and-paste capability anytime, anywhere, regardless of any changes.


    Other details of the object-oriented phase

    When is a variable declared instance and when is a variable declared static?

    If all objects of this type have the same attribute value, it is not recommended to define them as instance variables, which wastes memory space. You are advised to define static variables as class-level features and keep only one copy in the method area to save memory.

    A copy of an object is an instance variable

    A copy of all objects is a static variable


8. Java Advanced

The final use

The final variable

Final variables can be member variables or local variables (local variables within a method). In class members, final is often used with static as a class constant. Where class constants must be initialized at declaration time, final member constants can be initialized in the constructor.

public class Main {
    public static final int i; Because the constant exists in the constant pool, no class initialization is required, so it must be initialized at declaration time
    public static final int j;
    Main() {
        i = 2;
        j = 3; }}Copy the code

As mentioned above, for class constants, the JVM caches them in the constant pool and does not load the class when the variable is read.


public class Main {
    public static final int i = 2;
    Main() {
        System.out.println("Call constructor"); // This method will not be called
    }
    public static void main(String[] args) { System.out.println(Main.i); }}Copy the code

Final decorates base datatype variables and references

@Test
public void finalModify primitive type variables and references () {final int a = 1;
    final int[] b = {1};
    final int[] c = {1};
// b = c; An error
    b[0] = 1;
    final String aa = "a";
    final Fi f = new Fi();
    //aa = "b"; An error
    // f = null; / / an error
    f.a = 1;
}
Copy the code

A final method means that the method cannot be overridden by a subclass’s method. Declaring the method final is already statically bound at compile time and does not need to be dynamically bound at run time. The final method is called with the Invokespecial directive.

class PersonalLoan{
    public final String getName(a){
        return"Personal loan"; } } class CheapPersonalLoan extends PersonalLoan{ @Override public final String getName(){ return"cheap personal loan"; } public String test() {return getName(); // can be called because it is a public method}}Copy the code

Final class

Final classes cannot be inherited, and methods in final classes are final by default. The String and Integer classes in Java are final.

class Si{
    // In general final variables must be initialized.
    // The variable must be initialized in the constructor, except in the following case.
    // And no empty argument constructor.
    // This allows each instance to have a different variable that is initialized only once per instance
    // Then this variable is constant in a single instance.
    final int s ;
    Si(int s) {
        this.s = s; }}class Bi {
    final int a = 1;
    final void go(a) {
        // Final decorators cannot be inherited}}class Ci extends Bi {
    final int a = 1;
// void go() {
The // //final decorator cannot be inherited
/ /}
}
final char[]a = {'a'};
final int[]b = {1};
Copy the code
final class PersonalLoan{}

class CheapPersonalLoan extends PersonalLoan {  // Compile error, cannot be inherited
}
Copy the code
@Test
public void finalModifier class () {// References are mutable because they are not final.
    // Final only modifies the Fi type, that is, the memory address of the Fi instantiated object in the heap is immutable.
    // Although the memory address is immutable, the internal data can be changed.
    Fi f = new Fi();
    f.a = 1;
    System.out.println(f);
    f.a = 2;
    System.out.println(f);
    // Changing the value in the instance does not change the memory address.

    Fi ff = f;
    // make the reference point to the new Fi object. The old f object is held by the new reference ff.
    // Changing the reference does not change the address of the original object
    f = new Fi();
    System.out.println(f);
    System.out.println(ff);
}
Copy the code

Final keyword knowledge points

  1. Final member variables must be initialized at declaration time or in the constructor, otherwise a compilation error will be reported. Final variables cannot be assigned once they have been initialized.

  2. Local variables must be assigned at declaration time. Because there’s no initialization

  3. All variables in an anonymous class must be final.

  4. Final methods cannot be overridden, and final classes cannot be inherited

  5. All variables declared in an interface are themselves final. Similar to anonymous classes

  6. The keywords final and abstract are inversely related, and a final class cannot be abstract.

  7. Final methods are bound at compile time and are called static binding.

  8. Declaring classes, methods, and variables final improves performance so that the JVM has a chance to estimate and then optimize.

Benefits of the final method:

  1. For improved performance, the JVM caches final variables in the constant pool

  2. Final variables are concurrency safe in multiple threads without additional synchronization overhead

  3. Final methods are statically compiled to speed up calls

  4. Final classes create objects that are readable only and can be safely shared across multiple threads

Best practices for the final keyword

The use of the final

1. Final for constants means that the value cannot change, for example final int I =100. This I is always going to be 100. For variables, however, the reference cannot be changed, such as final File f=new File(“c:\test.txt”);

So f must not be changed, if f itself has a way to modify its member variables, such as readable, is allowed to change. There is an image metaphor: a woman defines a final husband, whose occupation and income are allowed to change, but this woman will not change her husband.

About blank Final

Final modifies three types of variables: static variables, instance variables, and local variables, representing three types of constants. In addition, when a final variable is defined, it can be declared first without giving an initial value. This variable is also called final whitespace. In any case, the compiler ensures that blank final is initialized before it can be used. However, final whitespace provides greater flexibility in the use of the final keyword final, so that final data members ina class can be implemented to vary from object to object, yet have the property of remaining constant.

public class FinalTest { 
final int p; 
final int q=3; 
FinalTest(){ 
p=1; 
} 
FinalTest(int i){ 
p=i;// Can be assigned, equivalent to defining p directly
q=i;// A final variable cannot be assigned}}Copy the code

Final memory allocation

I just mentioned the embedding mechanism, but now I’ll expand on it. Remember that calling a function requires additional time to find the function in addition to the execution time of the function itself (there is a mapping table of function signatures and function addresses inside the class). So reducing the number of function calls equals reducing the performance cost.

Final modified functions are optimized by the compiler, which results in fewer function calls. Here’s an example of how this works:

public class Test{ 
final void func(a){System.out.println("g"); };public void main(String[] args){ 
for(int j=0; j<1000; j++) func(); }} After compiler optimization, this class is equivalent to writing:public class Test{ 
final void func(a){System.out.println("g"); };public void main(String[] args){ 
for(int j=0; j<1000; j++) {System.out.println("g");} 
}} 
Copy the code

See the difference? The compiler inserts the func function body directly into the place where the function is called. The result is 1000 function calls saved. Of course, the compiler processes the function as bytecode, but we can imagine it like this.

However, when the function body is too long, using final can backfire because the code length increases dramatically after the compiler is embedded, increasing the time it takes for the JVM to interpret the bytecode.

When using final modification methods, the compiler will insert the method modified by final into the caller’s code to improve the running speed and efficiency. However, the body of the method modified by final should not be too large. The compiler may abandon inlining, but I have not done tests to calculate how many methods will be abandoned.

The following is continued through two questions

Will using final decorators improve speed and efficiency

See the following test code, which I will execute five times:

public class Test   
{   
    public static void getJava(a)   
    {   
        String str1 = "Java ";   
        String str2 = "final ";   
        for (int i = 0; i < 10000; i++) { str1 += str2; }}public static final void getJava_Final(a)   
    {   
        String str1 = "Java ";   
        String str2 = "final ";   
        for (int i = 0; i < 10000; i++) { str1 += str2; }}public static void main(String[] args)   
    {   
        long start = System.currentTimeMillis();   
        getJava();   
        System.out.println("The execution time for calling a method without final decoration is :" + (System.currentTimeMillis() - start) + Millisecond time);   
        start = System.currentTimeMillis();   
        String str1 = "Java ";   
        String str2 = "final ";   
        for (int i = 0; i < 10000; i++)   
        {   
            str1 += str2;   
        }   
        System.out.println("Normal execution time is :" + (System.currentTimeMillis() - start) + Millisecond time);   
        start = System.currentTimeMillis();   
        getJava_Final();   
        System.out.println("The execution time of the method calling the final modifier is :" + (System.currentTimeMillis() - start) + Millisecond time); }} The result is: First: no callfinalThe execution time of the modified method is:1732Milliseconds The normal execution time is as follows:1498Millisecond callfinalThe execution time of the modified method is:1593Second time in ms: No callfinalThe execution time of the modified method is:1217Milliseconds The normal execution time is as follows:1031Millisecond callfinalThe execution time of the modified method is:1124Third time in ms: No callfinalThe execution time of the modified method is:1154Milliseconds The normal execution time is as follows:1140Millisecond callfinalThe execution time of the modified method is:1202Fourth time in ms: No callfinalThe execution time of the modified method is:1139Milliseconds The normal execution time is as follows:999Millisecond callfinalThe execution time of the modified method is:1092Fifth time in ms: No callfinalThe execution time of the modified method is:1186Milliseconds The normal execution time is as follows:1030Millisecond callfinalThe execution time of the modified method is:1109It is not hard to see from the above running results that the fastest execution is "normal execution" i.e. code written directly while usingfinalEmbellished methods, unlike some books or articles that say speed and efficiency are no different from "normal execution," are secondary, and worst of all, not invokedfinalThe method of modification.Copy the code

Opinion: It’s better than nothing.

Does modifying a variable with final make it impossible to change its value?

See the code:

public class Final   
{   
    public static void main(String[] args)   
    {   
        Color.color[3] = "white";   
        for (String color : Color.color)   
            System.out.print(color+""); }}class Color   
{   
    public static final String[] color = { "red"."blue"."yellow"."black"}; } Result: red blue yellow white Look! Black turned white.Copy the code

Public static String[] color = {“red”, “blue”, “yellow”, “black”}; This line of code is not safe, but with the final modifier, it is still not safe, because final does not guarantee that the value of the variable will not be modified! The reason: the final keyword only guarantees that the variable itself cannot be assigned a new value, not that its internal structure cannot be modified. Color = new String[]{“”}; I’ll get an error.

How do I keep the inside of an array from being modified

Adding the final keyword does not guarantee that the array will not be modified externally, so how can you do that? The answer is to lower the access level and make the array private. This solves the problem of the array being modified externally, but it also creates the problem of the array being used externally.Copy the code

To solve this problem, see the code:

import java.util.AbstractList;   
import java.util.List;   

public class Final   
{   
    public static void main(String[] args)   
    {   
        for (String color : Color.color)   
            System.out.print(color + "");   
        Color.color.set(3."white"); }}class Color   
{   
    private static String[] _color = { "red"."blue"."yellow"."black" };   
    public static List<String> color = new AbstractList<String>()   
    {   
        @Override  
        public String get(int index)   
        {   
            return _color[index];   
        }   
        @Override  
        public String set(int index, String value)   
        {   
            throw new RuntimeException("For code security, you cannot modify arrays.");   
        }   
        @Override  
        public int size(a)   
        {   
            return_color.length; }}; }Copy the code

This is OK, keeping the code safe and allowing the elements in the array to be accessed.

Three rules for final methods

Rule 1: Final methods cannot be overridden.

Rule 2: Final methods simply cannot be overridden, but they can be overridden.

Rule 3: When a parent class has a private final method, a subclass can redefine it.

Code sample

The rules1codepublic class FinalMethodTest
{
	public final void test(a){}}class Sub extends FinalMethodTest
{
	// The following method definition will get a compilation error and final methods cannot be overridden
	public void test(a){}} rules2codepublic class Finaloverload {
	// Final methods cannot be overridden
	public final void test(a){}
	public final void test(String arg){}} rules3codepublic class PrivateFinalMethodTest
{
	private final void test(a){}}class Sub extends PrivateFinalMethodTest
{
	// There will be no problem with the following method definitions
	public void test(a){}}Copy the code

Abstract classes and interfaces

Abstract class and interface and the difference between abstract class and interface.

2.1 abstract Class first: How to define abstract class? Just add the abstract keyword before class. Second: Abstract classes cannot be instantiated and cannot create objects, so they are used to be inherited by subclasses. Third, final and abstract cannot be used together. The two keywords are opposite. Fourth: A subclass of an abstract class can be an abstract class. It can also be non-abstract. Fifth: Abstract classes cannot be instantiated, but they have constructors that are used by subclasses. Sixth: the abstract class does not have abstract methods, abstract methods must appear in the abstract class. Seventh: how to define abstract methods? public abstract void doSome(); A non-abstract class that inherits an abstract class must override/override/implement the abstract methods in the abstract class. So far, we have only learned the basic syntax of abstract classes. Whether a class is declared abstract or non-abstract, all methods in the Java language that have no method body are abstract methods. No, wrong. There are many methods in the Object class that have no method body. They all start with "; ". Public native int hashCode(); public native int hashCode(); This method calls the dynamic link library program written by C++. There is no: abstract in the previous list of modifiers. There is a native. Represents a call to a JVM native program. 2.2 Basic interface syntax. 1. An interface is a reference data type. 2. Interfaces are completely abstract. [modifiers] interface name {} 4, interface support multiple inheritance. 5. Only constants + abstract methods in the interface. 6, All elements in the interface are public. 8, The interface constant public static final can be omitted. 9. An interface method cannot have a method body.Copy the code

An abstract class

Basic concepts of abstract classes

A normal class is a fully functional class that generates instantiated objects directly and can contain constructors, normal methods, static methods, constants, and variables. An abstract class means adding the components of an abstract method to the structure of an ordinary class.

So what are abstract methods? All normal methods have a “{}” above them, which represents the body of the method. Methods with a body must be used directly by objects. Abstract methods, on the other hand, refer to methods that have no method body and must be decorated with the keyword abstract.

Classes that have abstract methods are abstract classes, which are declared using the abstract keyword.

Let me write an example of an abstract class:

abstract class A{// Define an abstract class
	
	public void fun(a){// Common method
		System.out.println("A method that exists a method body.");
	}
	
	public abstract void print(a);
    // An abstract method has no method body and is modified with the abstract keyword
	
}

Copy the code

The use of abstract classes

Let’s take a look at this example:

abstract class A{// Define an abstract class
	
	public void fun(a){// Common method
		System.out.println("A method that exists a method body.");
	}
	
	public abstract void print(a);
    // An abstract method has no method body and is modified with the abstract keyword
	
}

public class TestDemo {

	public static void main(String[] args) {
		A a = newA(); }}Copy the code

Running results:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	Cannot instantiate the type A

	at com.wz.abstractdemo.TestDemo.main(TestDemo.java:15)


Copy the code

It can be seen from the above that A is abstract and cannot be instantiated directly. Why can’t you instantiate it directly? When a class is instantiated, it means that the object can call properties of the class or let go, but there are abstract methods in abstract classes, and abstract methods don’t have a method body, and they can’t be called without a method body. How can you generate an instantiated object if you can’t make a method call? So an abstract class cannot instantiate an object.


  1. The abstract method must be either public or protected (because if it is private, it cannot be inherited by subclasses, which cannot implement the method), and public by default;
  2. Abstract classes can not be instantiated directly, so they need to be processed by up-transformation of subclasses.
  3. Abstract classes must have subclasses. Using extends inheritance, a subclass can inherit only one abstract class.
  4. A subclass (if not an abstract class) must override all the abstract methods in the abstract class. (If the subclass does not implement the parent’s abstract methods, the subclass must also be defined as an abstract class.) Otherwise the compilation fails;


abstract class A{// Define an abstract class
	
	public void fun(a){// Common method
		System.out.println("A method that exists a method body.");
	}
	
	public abstract void print(a);
    // An abstract method has no method body and is modified with the abstract keyword
	
}
/ / single inheritance
class B extends A{
    // Class B is a subclass of an abstract class

	@Override
	public void print(a) {// Force override (also called "implement")
		System.out.println("Hello World !"); }}public class TestDemo {

	public static void main(String[] args) {
        	/ / polymorphism
		A a = new B();// Upward transition
		
		a.print();// The method overridden by the subclass}}Copy the code

Running results:

Hello World !
Copy the code

It is now clear that:

  1. Abstract classes inherit subclasses with explicit method overrides, whereas ordinary classes can be selective about whether they need overrides.
  2. Abstract classes actually have a few more abstract methods than ordinary classes, but the rest of the components are exactly the same as ordinary classes;
  3. Ordinary class objects can be instantiated directly, but objects of abstract classes must be transformed upward to be available.

Although a subclass of a class can inherit any ordinary class, but from the practical requirements of development, ordinary classes try not to inherit another ordinary class, but to inherit abstract classes.


3. Restrictions on the use of abstract classes

  1. Is there a constructor in an abstract class? Since there are properties in an abstract class, there must be constructors in an abstract class for the purpose of initializing the properties. In addition, the instantiation of a subclass object still satisfies the order of superclass construction first and then subclass construction.

    Here’s an example:

    package com.wz.abstractdemo;
    
    abstract class A{// Define an abstract class
    	
    	public A(a){
    		System.out.println("***** class A constructor *****");
    	}
    
    	public abstract void print(a);// An abstract method has no method body and is modified with the abstract keyword
    	
    }
    / / single inheritance
    class B extends A{// Class B is a subclass of an abstract class
    
    	public B(a){
    		System.out.println("***** class B constructor *****");
    	}
    	
    	@Override
    	public void print(a) {// Override mandatory
    		System.out.println("Hello World !"); }}public class TestDemo {
    
    	public static void main(String[] args) {
    		A a = new B();// Upward transition}}Copy the code

    Execution Result:

    ***** class A constructor ***** ***** class B constructor *****Copy the code

  2. Can abstract classes be declared with final? No, because abstract classes must have subclasses, and final classes cannot have subclasses; (The final keyword does not allow inheritance, so final and abstract are in conflict.)


  3. Can abstract classes be declared static? Here’s an example:

    static abstract class A{// Define an abstract class
    	
    	public abstract void print(a);
    	
    }
    
    class B extends A{
    	
    	public void print(a){
    		System.out.println("* * * * * * * * * *"); }}public class TestDemo {
    
    	public static void main(String[] args) {
    		A a = new B();// Upward transitiona.print(); }}Copy the code

    Execution Result:

    Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    	Illegal modifier for the class A; only public.abstract & final are permitted
    
    	at com.manman.abstractdemo.A.<init>(TestDemo.java:3)
    	at com.manman.abstractdemo.B.<init>(TestDemo.java:9)
    	at com.manman.abstractdemo.TestDemo.main(TestDemo.java:18)
    
    
    Copy the code

    Here’s another example of an inner abstract class:

    abstract class A{// Define an abstract class
    	
    	static abstract class B{// Static defines an inner class as an outer class
    		public abstract void print(a); }}class C extends A.B{
    	
    	public void print(a){
    		System.out.println("* * * * * * * * * *"); }}public class TestDemo {
    
    	public static void main(String[] args) {
    		A.B ab = new C();// Upward transitionab.print(); }}Copy the code

    Execution Result:

    * * * * * * * * * *Copy the code

    As you can see, the external abstract class does not allow static declarations, while the inner abstract class runs with static declarations. An internal abstract class declared static is equivalent to an external abstract class. The form “inner class” represents the class name.

  4. Can I directly call methods declared static in abstract classes? Any time you want to execute a static method on a class, you can call it without an object, even for an abstract class.

    Here’s an example:

    abstract class A{// Define an abstract class
    	
    	public static void print(a){
    		System.out.println("Hello World !"); }}public class TestDemo {
    
    	public static void main(String[] args) { A.print(); }}Copy the code

    Running results:

    Hello World !
    Copy the code

interface

1. Basic Concepts

An Interface, in the JAVA programming language, is an abstract type that is a collection of abstract methods. Interfaces are usually declared as interfaces. A class inherits the abstract methods of an interface by inheriting an interface.

If a class consists only of abstract methods and global constants, it will not be defined as an abstract class in this case. Is defined as an interface, so the interface strictly belongs to a special class that contains only abstract methods and global constants, not even constructors.

Here’s an example:

interface A{// Define an interface

    public static final String MSG = "hello";// Global constants
    public abstract void print(a);// Abstract methods
}

Copy the code

Second, the use of interfaces

1. Interface objects cannot be instantiated directly with the keyword new because of abstract methods in the interface. The principles for using interfaces are as follows:

  1. Interfaces must have subclasses, but a subclass can implement multiple interfaces using the implements keyword.
  2. Subclasses of interfaces (if not abstract classes) must override all abstract methods in the interface.
  3. An object of an interface can be instantiated using an upcast of a subclass object.

Here’s an example:

package com.gzm.interfacedemo;

interface A{// Define an interface A

    public static final String MSG = "hello";// Global constants

    public abstract void print(a);// Abstract methods
}

interface B{// Define an interface B

    public abstract void get(a);
}

class X implements A.B{// Class X implements both A and B interfaces

    @Override
    public void print(a) {
        System.out.println("Abstract method print() on interface A");
    }

    @Override
    public void get(a) {
        System.out.println("Abstract method get() for interface B"); }}public class TestDemo {

    public static void main(String[] args){

        X x = new X();// instantiate the subclass object
        A a = x;// Upward transition
        B b = x;// Upward transitiona.print(); b.get(); }}Copy the code

Running results:

Print () print() get()Copy the code

The above code instantiates an object of class X. Since class X is A subclass of A and B, an object of class X can become either an INTERFACE A or an interface B object. Let’s change the test main class code:

public class TestDemo {

    public static void main(String[] args){

        A a = newX(); B b = (B) a; b.get(); }}Copy the code

Running results:

Abstract method get() for interface BCopy the code

Let’s take another quiz:

public class TestDemo {

    public static void main(String[] args){

        A a = new X();

        B b = (B) a;
        b.get();

        System.out.println(a instanceof A);
        System.out.println(a instanceof B);

    }
Copy the code

Running results:

Abstract method get() for interface Btrue
true
Copy the code

We found that, by definition, interfaces A and B have no direct connection, but the two interfaces share the same subclass. Let’s not get confused by the type and name, because we are instantiating an X subclass, and this class object belongs to class B, so the above code works, but not very well in terms of the code specification.

In addition to implementing interfaces, subclasses can also inherit abstract classes. To inherit an abstract class and implement an interface, use the following syntax:

classSubclasses [extendsThe parent class] [implemetnsInterface 1, interface 2... ]{}
Copy the code

Let me use examples to illustrate:

interface A{// Define an interface A

    public static final String MSG = "hello";// Global constants

    public abstract void print(a);// Abstract methods
}

interface B{// Define an interface B

    public abstract void get(a);
}

abstract class C{// Define an abstract class C
    public abstract void change(a);
}

class X extends C implements A.B{// Class X inherits class C and implements both A and B interfaces

    @Override
    public void print(a) {
        System.out.println("Abstract method print() on interface A");
    }

    @Override
    public void get(a) {
        System.out.println("Abstract method get() for interface B");
    }

    @Override
    public void change(a) {
        System.out.println("Abstract method change() of abstract class C"); }}Copy the code

In the case of interfaces, there are only abstract methods and global constants, so in many cases you don’t need to write public abstract or public static final for the sake of simplicity. In addition, there is only one access permission in the interface: public, that is, even if public is not written when defining interface methods and global constants, the final access permission is public, which is not default. The following two forms are completely equivalent:

interface A{
    public static final String MSG = "hello";
    public abstract void print(a);
}
Copy the code

Is equivalent to:

interface A{
    String MSG = "hello";
    void print(a);
}
Copy the code

But is there a problem with that? If the override method in the subclass is not public, let’s see:

package com.gzm.interfacedemo;

interface A{

    String MSG = "hello";

    void print(a);
}

class X implements A{
	// Notice that the subclass is default instead of public
    void print(a) {
        System.out.println("Abstract method print() on interface A"); }}public class TestDemo {
    public static void main(String[] args){

        A a = newX(); a.print(); }}Copy the code

Here’s the result:

Exception in thread "main" java.lang.IllegalAccessError: com.wz.interfacedemo.X.print()V
    at com.gzm.interfacedemo.TestDemo.main(TestDemo.java:22)
Copy the code

This is because the interface defaults to the public modifier, and if a subclass does not use the public modifier, then access is restricted and subclasses are assigned lower access. Therefore, it is strongly recommended to define interfaces with public before abstract methods and subclasses with:

interface A{

    String MSG = "hello";

    public void print(a);
}

class X implements A{

    public void print(a) {
        System.out.println("Abstract method print() on interface A"); }}Copy the code

3. In Java, an abstract class can only inherit from one abstract class, but an interface can inherit from multiple interfaces using the extends keyword (but an interface cannot inherit from an abstract class).

Here’s an example:

interface A{
    public void funA(a);
}

interface B{
    public void funB(a);
}

// Interface C inherits both interface A and interface B
interface C extends A.B{// extends is used
    public void funC(a);
}

class X implements C{

    @Override
    public void funA(a) {}@Override
    public void funB(a) {}@Override
    public void funC(a) {}}Copy the code

Interfaces are less restrictive than abstract classes in terms of inheritance:

  1. An abstract class can only inherit from one abstract superclass, whereas an interface can inherit from multiple interfaces.
  2. A subclass can inherit only one abstract class, but can implement multiple interfaces (in Java, the main function of interfaces is to solve the single inheritance limitation).

4. Conceptually speaking, an interface can only be composed of abstract methods and global constants, but the internal structure is not limited by the concept. Just as abstract inner classes can be defined in abstract classes, ordinary inner classes, abstract inner classes, and internal interfaces can be defined in interfaces. It is rare for users to define their own internal abstract classes or interfaces.)

Let’s look at an example of defining an abstract inner class in an interface:

interface A{
    public void funA(a);

    abstract class B{// Define an abstract inner class
        public abstract void funB(a); }}Copy the code

If static is used to define an internal interface, it represents an external interface:

interface A{
    public void funA(a);

    static interface B{// Static is an external interface
        public void funB(a); }}class X implements A.B{

    @Override
    public void funB(a) {}}Copy the code

Iii. Practical application of interfaces (Standard definition)

In daily life, the term interface is often heard, such as: USB interface, printing interface, charging interface and so on.

If development is to proceed, USB interface standards must be developed before device manufacturers can design USB devices.

Now assume that each USB device has only two functions: installing drivers and working. Define a USB standard:

interface USB {   // Operating standard
    public void install(a) ;
    public void work(a) ;
}
Copy the code

To apply this interface on a computer:

class Computer {
   public void plugin(USB usb) { usb.install() ; usb.work() ; }}Copy the code

Defining USB devices — Mobile phones:

class Phone implements USB {
     public void install(a) {
           System.out.println("Install the phone driver."); }public void work(a) {
           System.out.println("The phone works with the computer."); }}Copy the code

4. The function of interfaces

normative

Interfaces are normative in abstract methods. Because subclasses implement interfaces, they must completely override all of the abstract methods in the interface, and the method declarations are identical. This is mandatory and normative.

expanding

Interface in life there are many, USB interface, socket hole, the charging hole, etc. As long as it is in accordance with the rules of the interface to create, can and interface docking, all in accordance with the interface specification can create docking, all the implementation class as long as all of the interfaces to rewrite the abstract method [rule], you can use, which is the development of the interface.


5. Member characteristics of the interface

All variables in an interface are final, which means that they can only be assigned once. So there’s no such thing as a variable in an interface, it’s just a constant.

  • The default constant in the interface that uses the final modifier can only be assigned once.

  • The default constants in the interface are static by default, which means that the class name can be used. The call.

  • Interfaces are all public by default, they’re all public.

    All methods in the interface are abstract methods, so the public abstract modifier is used by default

A constructor

Because an interface can’t create an object, there are no constructors in the interface, no building blocks, no static blocks.

  • There are no constructors in the interface
  • No code blocks are constructed in the interface
  • There are no static code blocks in the interface

What is the difference between an abstract class and an interface

  1. Abstract classes are semi-abstract and interfaces are completely abstract.
  2. Abstract classes have constructors; interfaces have no constructors.
  3. Interfaces support multiple inheritance, and classes support single inheritance.
  4. A class can implement multiple interfaces at the same time, and an abstract class can inherit only one class.
  5. Only constants and abstract methods are allowed in an interface.

Note: With JDK 1.8, static methods and method bodies are now available in interfaces.

After JDK 1.8, interfaces are allowed to include implementation-specific methods called “default methods,” which are decorated with the default keyword.

Since JDK 1.9, methods have been allowed to be defined private so that some reusable code does not expose them.

7. Mind mapping


Object class

A brief introduction to Object class

The Object class is the core class of the Javajava.lang package. The Object class is the parent of all classes. Any class that does not explicitly inherit a parent class is a subclass of Object.

The net effect of the following two definitions is exactly the same:

class Person{
}
class Person extends Object{

}
Copy the code

Receive all objects using the Object type

The Object class belongs to the java.lang package. All classes in this package do not need to be manually imported during program compilation

Structure diagram of the Object class (Object provides 11 methods)

Let’s take a look at each of these methods and see how they work:

  1. clone()

Protection method, the realization of a shallow copy of object, only implements the Cloneable interface to invoke the method, otherwise throw CloneNotSupportedException anomalies.

  1. getClass()

Final method, which returns an object of type Class and reflects to get the object.

  1. toString()

This method is used more often, generally subclasses have overridden, to get information about the object.

  1. finalize()

This method is used to release resources. This method is rarely used because it is impossible to determine when it will be called.

  1. equals()

Compare whether the contents of objects are equal

  1. hashCode()

This method is used for hash lookup, overrides equals and generally overrides hashCode. This method is used in some collections that have hash capabilities.

  1. wait()

The wait method causes the current thread to wait for the lock on the object. The current thread must be the owner of the object, that is, the lock on the object. The wait() method waits until the lock is acquired or interrupted. Wait (long timeout) Sets a timeout interval and returns if the lock has not been acquired within the specified time.

This method is called and the current thread goes to sleep until the following event occurs.

Other threads called notify on this object. Other threads call the notifyAll method on this object. Other threads call interrupt to interrupt the thread. The time interval is up. The thread can then be scheduled, throwing an InterruptedException if it is interrupted.

  1. notify()

This method wakes up a thread waiting on the object.

  1. notifyAll()

This method wakes up all threads waiting on the object.


2. Object class common methods

Method names type describe
toString( ) ordinary Get object information
equals() ordinary Compare whether objects are equal
  1. The toString method

ToString () : Retrieves object information and returns a string representation of the object

Here’s an example:

public class ObjectTest01 {
    public static void main(String[] args) {
            Person person = new Person(20."manamn"); System.out.println(person); }}class Person{
    private int age;
    private String name;

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

    public int getAge(a) {
        return age;
    }

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

    public String getName(a) {
        return name;
    }

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

Running results:

com.manman.javase.object.Person@4554617c
Copy the code

When using object direct output, the default output is the address value of an object in the heap memory. To print the contents of the object, override the toString() method

Overrides the toString() method in Person

@Override
    public String toString(a){
        return "Age as" + this.age + "Name as" + this.name; 
    }
Copy the code

The execution result is as follows:

Age:20Name: manamnCopy the code

The core purpose of toString() is to retrieve object information

String is an important data type for information output. In Java, all data types execute + whenever they meet String, and all require it to be connected after it becomes a String. And all objects want to become a String by default, toString() method is used

Such as:

System.out.println("hello" + 123); >>> Output: hello123Copy the code

Why can hello and 123 (a string and an int) be concatenated together?

Because string is father, in this era of spelling father, he has a versatile father Object

In other words, Object is the parent of all classes, and any class inherits from Object. Object defines the toString() method, so any class contains a toString() method that can be called after the Object is instantiated.

So the output of any object to a string is done by overwriting toString()…

Every class contains toString(), but not every class overrides toString()


  1. Quals method

    Equals () : Object comparison

    The equals() method of the String class is actually an override of the equals() method of the Object class

    • Use “==” to compare basic data types (e.g., a == 3, b == 4, a == b)
    • Reference data type comparison: Call equals () to compare.

    Equals () is used to compare whether two objects have the same content:

    package com.manman.javase.object;
    
    / * * *@authorFull * createDate 2022/2/23 15:34 */
    public class ObjectTest02 {
        public static void main(String[] args) {
            People people1 = new People(30."zhangsan");
            People people2 = new People(30."zhangsan"); System.out.println(people1.equals(people2)); }}class People{
        private int age;
        private String name;
    
        public People(a) {}public People(int age, String name) {
            this.age = age;
            this.name = name; }}Copy the code

    Execution Result:

    false
    Copy the code

    People1 = people2; people1 = people2 How can it be false?

    This is because calling equals() directly compares the addresses of the two objects by default.

    In source code, the passed Object compares the address value with the current Object and returns a Boolean value.

However, new immediately creates a new space on the heap, and the two objects will not have the same address, so false.

But when checking whether two objects are equal, such as two objects of a Person class with the same name, override equals().

Override equals() as in the previous example:

  /** * this overrides the equals method * of the parent Object@param obj
     * @return* /
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        // If the memory address is the same, they are the same reference
        if (this == obj){
            return true;
        }
        if ( !(obj instanceof People)){
            return false;
        }
// At this point in the program it is not empty and is a People object
// At this point, a downward transformation is performed to forcibly convert Object to Perple
           People p = (People)obj;
            return p.name.equals(this.name)&& p.age == this.age;
    }
Copy the code

Execution Result:

true
Copy the code

Therefore, reference type data should be overridden before comparisonequals()Method, otherwise the heap memory address of the two objects will not be equal.


The String class

Commonly used class

1. Wrapper classes corresponding to the eight basic data types.

1.1. What is automatic packing and automatic unpacking? How to write the code? Integer x = 100; // x does not store 100, it stores the memory address of the object 100. Integer y = 100; System.out.println(x == y); // true

	Integer x = 128;
	Integer y = 128;
	System.out.println(x == y); // false

1.2Integer class common methods. Integer.valueOf() Integer.parseInt("123")
	Integer.parseInt("Chinese") : NumberFormatException

1.3, an Integer StringintThe three types convert to each other.Copy the code

D = new Date(); Date –> String YYYY-MM-DD HH: MM: SS SSS SimpleDateFormat SDF = new SimpleDate(” YYYY-MM-DD HH: MM: SS SSS”); String s = sdf.format(new Date()); 3, String –> Date SimpleDateFormat SDF = new simpleDatedate (” YYYY-MM-DD HH: MM :ss”); Date d = sdf.parse(“2008-08-08 08:08:08”); Long begin = system.currentTimemillis (); Date d = new Date(begin – 1000 * 60 * 60 * 24);

### indicates the addition of the thousandth place and the retention of two decimals. ### #.0000 means to add the thousandth place and keep 4 decimal places, which is not enough to fill the 0

4. Random number

4.1 how to generate int type random number Random r = new Random(); int i = r.nextInt(); 4.2, how to generate a certain range of int type random number. Random r = new Random(); int i = r.nextInt(101); // Generate a random number [0-100].

5, the enumeration

5.1 enumeration is a reference data type. 5.2. Enumerations are also class files after compilation. 5.3. How to define enumeration types? Enum Enumeration type name {enumeration value, enumeration value 2, enumeration value 3} 5.4. When more than two types of results of a method can be enumerated one by one, it is recommended that the return type be enumerated.

abnormal

Exception handling mechanism

  • Exceptions in Java are used to enhance program robustness.

  • Exceptions in Java come in the form of classes and objects.

    1. Java exception handling mechanism

1.1Exceptions exist in Java in the form of classes and objects. So what is the inheritance structure of exceptions? We can use UML diagrams to describe the inheritance structure. There are many tools for drawing UML diagrams, such as Rational Rose (paid), starUML, etc.... There are two branches of Throwable: Error (untraceable, directly exits the JVM) and Exception (traceable) Exception has two branches: direct subclasses of Exception: Compile-time exceptions (programmers must handle these exceptions in advance when writing programs. If they are not handled, the compiler reports an error, hence the name compile-time exceptions.) . RuntimeException: RuntimeException. (The programmer can either pre-process or leave it at the programming stage.)1.2, compile-time exceptions, and runtime exceptions, all occur at run time. Compile-time exceptions do not occur. Why do compile-time exceptions get their name? The name comes from the fact that compile-time exceptions must be handled in advance during the compile (write) phase, and the compiler reports an error if not handled. All exceptions occur at run time. Because it only works when the program is runningnewObject. Because the occurrence of an exception isnewException object.1.3What are the differences between compile-time exceptions and runtime exceptions? Compile-time exceptions generally occur at a high rate. For example: You see it's raining outside, it's pouring. You know before you leave: if I don't use an umbrella, I might get sick (illness is an anomaly). And there's a high probability of this happening, so take an umbrella before you go out. "Taking an umbrella" is one way to deal with the "abnormal illness" before it happens. Some exceptions with high probability need to be preprocessed before running. Run-time exceptions generally occur at a low rate. For example, Xiao Ming may be hit by a plane wheel in the sky when he is walking on the street. Getting hit by a plane wheel is an anomaly. However, the occurrence of such anomalies is relatively rare. You don't need to pre-process this low-probability anomaly before you head out the door. If you preprocess this abnormality, you will live very tired. If you take care of anything that might happen before you leave the house, you'll be safer, but you'll be tired. What if Java had no division of exceptions into compile-time exceptions and run-time exceptions, and all exceptions had to be preprocessed at programming time? First of all, if so, the program must be absolutely safe. But programmers are too tired to write programs, and the code is littered with code that handles exceptions.1.4Compile-time exceptions have other names: Checked exceptions: CheckedException Checked exceptions1.5Run-time exceptions have other names: Unchecked exceptions: UnCheckedException Uncontrolled exceptions1.6, again: All exceptions occur at run time.1.7In the Java language, there are two ways to handle exceptions: The first way: in the position of the method declaration, use thethrowsKeyword, thrown to the next level. I'll throw it to whoever calls me. To the next level. Second way: usetry.catchStatement to catch exceptions. It happened without anyone knowing because I was caught. For example: I am a salesman of a group, because of my mistake, the company lost1000Yuan, "loss1000This can be seen as an exception happening. I have two ways to deal with it. The first way is that I tell my boss about it. The second way is that I pay for it out of my own pocket. CEO thought: after the exception occurs, if I choose to throw up, throw to my caller, caller needs to continue to deal with this exception, then caller also has two ways to deal with this exception.1.8Note: If an exception occurs in Java and is thrown up and eventually thrown to main, the main method continues to be thrown up and thrown to the calling JVM. The JVM knows about the exception and has only one result. Terminates the execution of the Java program.Copy the code

Anomalous system diagram

As you can see from the above figure, Throwable is the superclass for all errors and exceptions in the Java language. It has two subclasses: Error and Exception.

The Java standard library has some generic exceptions built into it, and these classes have Throwable as their top-level parent.

Throwable also derives the Error and Exception classes.

Error: The Error class, and instances of its subclasses, represent errors in the JVM itself. Errors cannot be handled by programmers in code, and errors are rare. Therefore, programmers should focus on the various Exception classes that branch off of Exception as a parent.

Exception: Exception and its subclasses, which represent unexpected events sent by a program while it is running. Can be used by the Java exception handling mechanism, is the core of exception handling.

In general, we divide exception classes into two classes based on Javac’s requirements for exception handling.

Unckecked Exception: Error and RuntimeException and their subclasses. Javac does not raise or find such exceptions at compile time and does not require the program to handle them. So we can write code to handle (using try… The catch… Finally) can also be left unhandled.

For these exceptions, we should fix the code rather than handle them through an exception handler. Such exceptions are most likely due to poorly written code. Such as zero error ArithmeticException, casts error ClassCastException error, array index ArrayIndexOutOfBoundsException seams, NullPointerException and so on.

Checked Exceptions: Exceptions other than Error and RuntimeException. Javac forces the programmer to do preparatory work for such exceptions (using try… The catch… Finally or throws). The compilation fails if it is either caught and processed in a try-catch statement or thrown with a throws clause declaration in a method.

Such exceptions are usually caused by the environment in which the program is running. Because programs can be run in all kinds of unknown environments, and the programmer has no way of interfering with how the user uses the program, the programmer should always be prepared for such exceptions. Such as SQLException, IOException, ClassNotFoundException, etc.

To be clear: Checking and non-checking are for Javac, so it’s easy to understand and distinguish.


Abnormal person

Exceptions are raised when a function is executed, and functions are called hierarchically, forming the call stack. As long as an exception occurs in a function, all its callers will be affected by the exception. When these affected functions are output with exception information, an exception tracing stack is formed.

The point where an exception first occurs is called the exception throw point.

public classabnormal{
    public static void main (String [] args )
    {
        System . out. println( "---- Welcome to command line division calculator ----"); CMDCalculate (); }public static void CMDCalculate (a)
    {
        Scanner scan = new Scanner ( System. in );
        int num1 = scan .nextInt () ;
        int num2 = scan .nextInt () ;
        int result = devide (num1 , num2 ) ;
        System . out. println( "result:" + result) ;
        scan .close () ;
    }
    public static int devide (int num1, int num2 ){
        return num1 / num2 ;
    }

// ---- Welcome to the command-line division calculator ----
/ / 1
/ / 0
// Exception in thread "main" java.lang.ArithmeticException: / by zero
// at com.javase. Exception. Devide (exception.java :24)
// at com.javase. Exception. CMDCalculate(exception.java :19)
// at com.javase. Exception. Exception.main (exception.java :12)

Copy the code

As you can see from the above example, devide throws a ArithmeticException when it encounters a division of 0 exception, so calling its CMDCalculate function cannot complete properly, so it also sends an exception, CMDCalculate’s caller — main — also gets an exception because CMDCalculate throws an exception, which goes all the way back to the bottom of the call stack.

This behavior is called exception bubbling. Exception bubbling is to find the most recent exception handler in the function or caller of that function. Since no exception handling mechanism is used in this example, the exception is ultimately thrown to the JRE by the main function, causing the program to terminate.

The code above compiles without exception handling because both exceptions are unchecked. The following example, however, requires exception handling because exceptions are checked for exceptions.

I choose to use throws to declare exceptions in the code, leaving the caller of the function to handle any exceptions that might occur. But why throw only IOException? Because FileNotFoundException is a subclass of IOException, it is within the scope of processing.


Exceptions and errors

Let’s look at an example

// Errors are generally errors that cannot be handled by the JVM
// Exceptions are tools defined by Java to simplify error handling and locate errors.
public classMistakes and errors{
    Error error = new Error();

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

    // The following four exceptions or errors can be handled differently
    public void error1 (a){
        // Compile-time requirements must be handled, because this exception is the top-level exception, including the check exception, and must be handled
        try {
            throw new Throwable();
        } catch(Throwable throwable) { throwable.printStackTrace(); }}//Exception must also be handled. Otherwise, an error is reported, because check exceptions inherit from Exception, so you need to catch them by default.
    public void error2 (a){
        try {
            throw new Exception();
        } catch(Exception e) { e.printStackTrace(); }}// The virtual machine can't handle it, so you don't need to do anything
    public void error3 (a){
        throw new Error();
    }

    // runtimeException is known to compile without errors
    public void error4 (a){
        throw new RuntimeException();
    }
// Exception in thread "main" java.lang.Error
// at com.javase. Exception. Error. Main (error. Java :11)

}

Copy the code

How to handle exceptions

When writing code to handle exceptions, there are two different ways to handle checking for exceptions:

Using a try… The catch… The finally statement block handles it.

Alternatively, use the throws declaration in the function signature and leave it to the function caller to resolve.

Let’s look at some specific examples, including Error, Exception, and throwable

The example above is a runtime exception and does not need to show the catch. The following example is a checkable exception required to show either a catch or a throw

@Test
public void testException(a) throws IOException
{
    //FileInputStream's constructor throws a FileNotFoundException
    FileInputStream fileIn = new FileInputStream("E:\\a.txt");

    int word;
    The read method throws an IOException
    while((word = fileIn.read())! = -1)
    {
        System.out.print((char)word);
    }
    // The close method throws IOException
    fileIn.close();
}

Copy the code

In general, try catch finally is used

public classException Handling Mode{

@Test
public void main(a) {
    try{
        // Put the code in the try block where the exception might occur.
        InputStream inputStream = new FileInputStream("a.txt");

        // If the try is complete and no exception occurs, then the finally block and the code after finally (if any) are executed.
        int i = 1/0;
        // If an exception occurs, try to match the catch block.
        throw new SQLException();
        Using the 1.8 JDK to catch multiple exceptions at the same time, runtimeExceptions can also be caught. However, even after the capture, the VM cannot process it. Therefore, it is not recommended to capture it.
    }catch(SQLException | IOException | ArrayIndexOutOfBoundsException exception){
        System.out.println(exception.getMessage());
        // Each catch block is used to catch and handle a particular exception, or a subclass of that exception type. In Java7, you can declare multiple exceptions in a catch.

        // The parentheses after catch define the exception type and the exception parameters. If the exception matches and is matched first, the virtual machine will use the catch block to handle the exception.

        // In a catch block, you can use the exception parameters of the block to get information about the exception. Exception parameters are local variables in the catch block and cannot be accessed by other blocks.

        // If an exception occurs in the current try block and is not caught in any subsequent catch, then finally is executed, and the external caller of the function matches the exception handler.

        If no exception occurs in the try, all catch blocks are ignored.

    }catch(Exception exception){
        System.out.println(exception.getMessage());
        / /...
    }finally{
        The //finally block is usually optional.
        // Finally executes regardless of whether an exception occurs and if an exception match is handled.

        // Finally does some cleanup work, such as stream closure, database connection closure, etc.
    }

Copy the code

A try must be followed by at least one catch or finally

    try {
        int i = 1;
    }finally {
        // A try must have at least one catch block, otherwise, at least one finally block. But finally is not used to handle exceptions, and finally does not catch exceptions.}}Copy the code

When an exception occurs, the code following the method is no longer executed, even if the exception has been caught. For a different example, you can still try a try catch finally after a catch block

@Test
public void test(a) {
    try {
        throwE();
        System.out.println(I threw an exception earlier.);
        System.out.println("I'm not going to do it.");
    } catch (StringIndexOutOfBoundsException e) {
        System.out.println(e.getCause());
    }catch (Exception ex) {
    // Try catch finally can still be used ina catch block
        try {
            throw new Exception();
        }catch (Exception ee) {
            
        }finally {
            System.out.println("My catch block didn't execute, and I'm not going to execute."); }}}// An exception thrown in a method declaration must be handled by the calling method or further thrown,
// Abort program cannot be handled when jre is thrown
public void throwE (a){
// Socket Socket = new Socket("127.0.0.1", 80);

        // When an exception is thrown manually, no error is reported, but the method calling the method needs to handle the exception otherwise it will fail.
// java.lang.StringIndexOutOfBoundsException
// at com.javase. Exception. ThrowE (exception handling. Java :75)
// at com.javase. Exception. Exception handler. Test (exception handler. Java :62)
        throw new StringIndexOutOfBoundsException();
    }

Copy the code

Throws “irresponsible”

Throws is another way of handling exceptions, which is different from try… The catch… Finally and throws only declare the exceptions that may occur ina function to the caller, but do not handle them themselves.

The reason for this exception handling may be that the method itself does not know how to handle such an exception, or that it is better handled by the caller, who is responsible for any exceptions that may occur.

public void foo(a) throws ExceptionType1 , ExceptionType2 ,ExceptionTypeN
{ 
     // Foo can internally throw ExceptionType1, ExceptionType2,ExceptionTypeN exceptions, or exception objects from their subclasses.
}

Copy the code

Tangled finally

The finally block does not care if an exception occurs; if the corresponding try executes, it must also execute. There is only one way for a finally block not to execute: ** system.exit (). ** So finally blocks are often used to do resource release operations: close files, close database connections, and so on.

Good programming practice is to open resources ina try block and clean up and release them ina finally block.

Points to note:

1. The finally block has no ability to handle exceptions. Exceptions can only be handled by catch blocks.

2, In the same try… The catch… In a finally block, if an exception is thrown ina try and there is a matching catch block, the catch block is executed first and then the finally block is executed. If there is no catch block match, then finally is executed and the caller outside is searched for an appropriate catch block.

3, In the same try… The catch… In a finally block, if an exception occurs ina try and an exception is thrown in the matching catch block, then the finally block is executed: first, the finally block is executed, and then the enclosing caller looks for the appropriate catch block.

public class finallyuse{
    public static void main(String[] args) {
        try {
            throw new IllegalAccessException();
        }catch (IllegalAccessException e) {
            // throw new Throwable();
            // Finally cannot be executed if an exception is thrown.
            //finally executes whenever
            // Unless I display the call. Finally is not executed at this point
            System.exit(0);

        }finally {
            System.out.println("You are so cruel."); }}}Copy the code

Throw: Keyword also used by JRE

throw exceptionObject

A programmer can also explicitly throw an exception manually by using a throw statement. The throw statement must be followed by an exception object.

The throw statement must be written in the function, and the place where the throw statement is executed is an exception throw point, which is no different from the exception throw point automatically formed by the JRE. = =

public void save(User user)
{
      if(user  == null) 
          throw new IllegalArgumentException("User object is empty");
      / /...
 
}

Copy the code

Custom exception

If you want to customize an Exception class, you simply extend the Exception class, so that custom exceptions are checked exceptions. If you want to customize non-check exceptions, extend from RuntimeException.

By international convention, a custom exception should always contain the following constructor:

A no-argument constructor a constructor that takes a String argument and passes it to the constructor of the parent class. A constructor that takes a String argument and a Throwable argument is passed to the parent constructor. Here is the IOException class complete source code, can be used for reference.

public class IOException extends Exception
{
    static final long serialVersionUID = 7818375828146090155L;
 
    public IOException(a)
    {
        super(a); }public IOException(String message)
    {
        super(message);
    }
 
    public IOException(String message, Throwable cause)
    {
        super(message, cause);
    }
 
    public IOException(Throwable cause)
    {
        super(cause); }}Copy the code

Precautions for exceptions

Precautions for exceptions

When a subclass overrides a parent class function with a throws declaration, its throws declared exception must be within the scope of the parent class exception — the exception handler used to handle the parent class’s throws method must also apply to the subclass’s throws method. This is to support polymorphism.

For example, if a superclass method throws two exceptions, a subclass cannot throw three or more exceptions. The parent class throws IOException, and the subclass must throw IOException or a subclass of IOException.

And why? I think, perhaps, the following example will illustrate.

class Father
{
    public void start(a) throws IOException
    {
        throw newIOException(); }}class Son extends Father
{
    public void start(a) throws Exception
    {
        throw newSQLException(); }}Copy the code

/ * * * * * * * * * * * * * * assume the above code is allowed (essence is wrong) * * * * * * * * * * * * * * * * * * * /

class Test
{
    public static void main(String[] args)
    {
        Father[] objs = new Father[2];
        objs[0] = new Father();
        objs[1] = new Son();
 
        for(Father obj:objs)
        {
        // Because the Son class throws a SQLException, IOException cannot handle it.
        // Then try. Catch cannot handle exceptions in Son.
        // The polymorphism cannot be implemented.
            try {
                 obj.start();
            }catch(IOException)
            {
                 / / processing IOException}}}}Copy the code

JAVA exceptions often meet questions

Here is my personal summary of exceptions and errors that Java and J2EE developers are often asked about in interviews. In sharing my answers, I’ve also made quick revisions to these questions and provided the source code for further understanding. I have summarized the various difficulty problems, suitable for beginners and advanced Java code farmers. If you have a problem that isn’t on my list, and it’s a very good one, please share it in the comments below. You can also share your interview mistakes in the comments.

1) What is Exception in Java?

This question is often asked for the first time when asking about exceptions or when interviewing newbies. I’ve never met a senior engineer or senior engineer who asks this question, but it’s a great question for beginners.

Simply put, exceptions are Java’s way of communicating errors to your system and program. In Java, exceptions are implemented by implementing classes such as Throwable, Exception, RuntimeException, and other exceptions. Then there are some keywords to handle exceptions, such as throw, throws, try, catch, finally, and so on. All exceptions are derived from Throwable. Throwable Error is further divided into Java. Lang. Exception and Java lang. Error. The Java. Lang. Error handling system errors, such as Java, lang. StackOverFlowError and so on. Exceptions are then used to handle program errors, requested resources unavailable, and so on.

2) What is the difference between checking and non-checking exceptions in Java?

This is another very popular Java exception interview question that comes up in Java interviews at all levels.

The main difference between checking and non-checking exceptions is how they are handled. Check exceptions need to be handled at compile time using the try, catch, and finally keywords, otherwise the compiler will report an error. This is not necessary for non-checking exceptions. All exceptions in Java that inherit from the java.lang.Exception class are checking exceptions, and all exceptions that inherit from RuntimeException are called non-checking exceptions.

3) what is the same between NullPointerException of Java and ArrayIndexOutOfBoundException?

This is not a popular question to ask in Java exception interviews, but is used in beginner interviews at various levels to test a candidate’s familiarity with the concepts of checkable and non-checkable exceptions. And the answer to that question, by the way,

Both exceptions are non-checking exceptions and inherit from RuntimeExceptions. This problem may lead to another problem, that is what’s the difference between an array of Java and C, because there is no limit to the size of the array, C would never sell ArrayIndexOutOfBoundException.

4) What are some of the best practices you follow in Java exception handling?

This is a very common question when interviewing technical managers. Because exception handling is critical in project design, it is essential to be proficient in exception handling. There are many best practices for exception handling, and here are a few that improve the robustness and flexibility of your code:

  1. Instead of returning null, a NullPointerException is returned when a method is called. Because null Pointers are the most disgusting of Java exceptions
  2. Don’t write code in a catch block. An empty catch block is an error event in exception handling because it simply catches the exception without any handling or prompting. Usually you should at least print out the exception message, but it is best to handle the exception message as required.

3) If you can throw checked exceptions, try not to throw unchecked exceptions. You can improve the readability of your code by removing duplicate exception handling code.

  1. Never let your database-related exceptions show up on the client. Since the vast majority of database and SQLException exceptions are managed exceptions, in Java, you should handle the exception information at the DAO layer and then return the handled exception information that the user can understand and correct according to the exception prompt.
  2. In Java, be sure to call the close() method ina finally block after a database connection, database query, and stream processing.

5) Why do you think there are checking exceptions in Java when we can handle errors with RuntimeExceptions?

This is a controversial question and you should be careful in answering it. While they will certainly want to hear your point of view, they are most interested in a compelling argument. One reason I think is that the existence of checking exceptions is a design decision influenced by the design experience of programming languages that predate Java, such as C++. The vast majority of checking exceptions are in the java.io package, which makes sense, because a robust program must be able to handle this gracefully when you request a non-existent system resource. By declaring IOException as a checking exception, Java ensures that you can handle exceptions gracefully. Another possible reason is to use catch or finally to ensure that a limited number of system resources, such as file descriptors, are released early after you use them. Effective Java by Joshua Bloch covers this topic extensively and is worth reading.

6) What is the difference between the throw and throws keywords in Java?

A Java beginner’s interview question. Throws and throws look very similar at first glance, especially if you are a Java beginner. Although they look similar, they are both used when handling exceptions. But how you use it and where you use it in your code are different. Throws throws. You can also declare unchecked exceptions, but this is not mandatory by the compiler. If a method throws an exception it needs to be handled when the method is called. Throwable (i.e. Throwable or any derived class of Throwable) is used to throw any exception. A Throwable (i.e. Throwable or any derived class of Throwable) can interrupt a program and therefore be used instead of a return. The most common example is to use a throw in an empty method where a return is needed

UnSupportedOperationException code is as follows:

123 private``static ````void show() {thrownew ``````UnsupportedOperationException(“Notyet implemented”`); ` `} ` ` `

Check out this article to see more of the differences between these two keywords in Java.

7) What is an “exception chain”?

“Exception chain” is a very popular exception handling concept in Java. It refers to an exception chain that is created when one exception is thrown while another exception is being handled. This technique is mostly used to encapsulate “checked exceptions” as “unchecked exceptions” or runtimeexceptions. By the way, if you decide to throw a new exception because of an exception, you must include the original exception so that the handler can access the final root of the exception through the getCause() and initCause() methods.

8) Have you ever custom implemented an exception? How do you write that?

Obviously, most of us have written about custom or business exceptions like AccountNotFoundException. The main reason to ask this Java exception question during an interview is to discover how you use this feature. This allows for more accurate and refined handling of exceptions, depending on whether you choose Checked or unchecked Exception. By creating a specific exception for each specific case, you give the caller better options for handling the exception. I prefer more precise exceptions to general exceptions. Creating a large number of custom exceptions increases the number of project classes, so maintaining a balance between custom and generic exceptions is key to success.

9) What changes were made to exception handling in JDK7?

This is a recent interview question for Java exception handling. Error and Exception handling are two new features in JDK7. First, multiple exceptions can be raised in a single catch block, just like the original catch block. The other is automated resource management (ARM), also known as try-with-Resource blocks. Both of these features reduce the amount of code while improving readability when handling exceptions. Knowing these features not only helps developers write better exception handling code, but also makes you stand out in interviews. I recommend reading the Java 7 walkthrough for a deeper understanding of these two very useful features.

10) Have you encountered outofMemoryErrors? How did you pull it off?

This question is used when interviewing senior programmers who want to know how you handle this dangerous OutOfMemoryError. Admittedly, no matter what project you’re working on, you’re going to have this problem. So if you say you haven’t, the interviewer won’t buy it. If you are not familiar with the problem, or even have not encountered it, and you have 3 or 4 years of Java experience, be prepared to tackle it. While answering this question, you can also show off your skills in handling memory leaks, tuning, and debugging. I find that people who master these skills can make a deep impression on the interviewer.

11) If the method returns a result before executing a finally block, or if the JVM exits, does the code in the finally block still execute?

The question can also be asked differently: “What would happen if system.exit () was called ina try or finally block?” Understanding how finally blocks execute, even when a return is already used ina try, is valuable for understanding Java exception handling. The code in the finally block will not execute unless there is system.exit (0) inside the try to exit the JVM.

12) Differences between final, Finalize,finally keywords in Java

This is a classic Java interview question. A friend of mine asked this question when he was recruiting a core Java developer in telecommunications for Morgan Stanley. Final and finally are Java keywords, and Finalize is a method. The final keyword is useful when creating immutable classes that simply declare the class to be final. The Finalize () method is called by the garbage collector before an object is collected, but there is no guarantee in the Java specification that this method will be called. The finally keyword is the only one related to exception handling discussed in this article. In your production code, you must use the finally block when closing connections and resource files.


A collection of

First, set outline

Set the Connection:

Map collections:

1. The difference between collections and arrays

2. #### Connection collection:

  1. Classification of common sets:

    A Collection of interface objects for the Collection interface (single-column Collection)

    – > > > List interface: >>> ArrayList interface implementation class, array, random access, no synchronization, Thread-unsafe — >>> Vector implements arrays, synchronization, thread-safe — >>> Stack implements Vector — >>> Set: ├ HashSet = >> LinkedHashSet = > LinkedHashSet = > LinkedHashSet = > LinkedHashSet = > LinkedHashSet = > LinkedHashSet = > LinkedHashSet = > LinkedHashSet = > LinkedHashSet

    Set of Map interface key-value pairs (two-column set)

    — >>> Thread safe — >>> Thread safe — >>> Thread safe Thread-unsafe — >>> LinkedHashMap bidirectional linked list and hash table implementation — >>> WeakHashMap — >>> TreeMap red-black tree sorts all keys — >>> IdentifyHashMap


List and Set

1. The difference between a list and a set:

2. The List:

  1. ArrayList: The underlying data structure is an array, fast query, slow add and delete, thread unsafe, high efficiency, can store duplicate elements
  2. The underlying data structure of LinkedList is a LinkedList, which is slow to query, fast to add and delete, unsafe threads, high efficiency, and can store repeated elements
  3. Vector: The underlying data structure is an array. It is fast to query, slow to add and delete, thread-safe, inefficient, and can store duplicate elements

3. Set:

  1. Hash table is used to implement the underlying data structure of HashSet. The elements are unordered and unique, which is not thread safe and efficient. Null elements can be stored. Specific comparison process to achieve uniqueness: Storing elements first uses the hash() algorithm function to generate a hashCode hash value of type int, and then compares the hashCode values of the stored elements. If hashCode is not equal, then the two stored objects must not be equal. In this case, store the element object at the current new hashCode value. If hashCode is equal, the objects storing the elements are not necessarily equal. In this case, equals() is called to determine whether the contents of the two objects are equal. If the contents of the comparison are not equal, then it is different objects, and it is stored. In this case, the hash algorithm for resolving address conflicts is adopted. The current hashCode value is like a new linked list, and the different objects are stored after the same hashCode value, so as to ensure the uniqueness of elements. A HashSet uses an algorithm to ensure that the elements in a HashSet are not duplicated. A HashSet uses a hash algorithm, and an array is used to store data at the bottom. The default initialization capacity is 16 and the loading factor is 0.75. The method of hashCode() in Object, which all subclasses inherit, returns a Hash code value using the Hash algorithm. A HashSet modulo the Hash value with the length of the array. Modules (which are the positions of objects in the array) determine if the elements in the array and the object to be added are the same, and if they are different, they are added.

The Hash algorithm is a Hash algorithm. Set hs=new HashSet();

hs.add(o); | o.hashCode(); | o % of the current total capacity (0-15) | | don’t conflict Whether — — — conflict direct deposit | | | false conflict (not equal) o1. Equals (o2) — — — – find a space to add | | is (equal to)

Not adding a rule to override the hashCode() method:

Make sure that objects that we think are the same return the same hashCode value

2. Try to make objects that we think are different return different hashCode values; otherwise, it increases the probability of collisions.

The implementation of HashSet is relatively simple. The operations related to HashSet are basically completed by directly calling the related methods of the underlying HashMap. We should override hashCode() and equals() for objects stored in a HashSet, because when adding an object to a HashSet, we call the hashCode method to calculate the hash value of the object, and then call the hash method in the HashMap based on that hash value. The value & (length-1) gets the index of the object stored in the transient Entry[] table of the hashMap, and then calls equals to check whether the two objects are equal. If they are equal, do not add them. So custom classes to be stored in the collection object of a HashSet must override hashCode() and equals() to ensure that elements in the collection are not duplicated. When overwriting equals() and hashCode(), make the hashCode() method of the same object return the same value, override equals() and determine its contents. To ensure efficiency, overwrite the hashCode() method so that different objects return different Hash values.

If the elements in the array and the hashCode() of the object to be added return the same Hash value (same object), equals() is used to determine whether the contents of the two objects are identical.

  1. The underlying data structure of LinkedHashSet is realized by linked list and hash table. The linked list ensures that the order of elements is consistent with the order of storage, while the hash table ensures the uniqueness of elements. Threads are unsafe and efficient.

  2. The underlying data structure of TreeSet is implemented by binary tree, with unique and sorted elements. Uniqueness also requires overriding the hashCode and equals() methods, and the binary tree structure guarantees ordering of elements. CompareTo (); compareTo(); compareTo(); compareTo(); The Comparator row needs to pass in a Comparator object that implements the Comparator interface when TreeSet is initialized, or use an anonymous inner class to create a Comparator object that overwrites the compare() method.

  3. Summary: Set has exactly the same interface as Collection, so it doesn’t have any extra functionality, unlike the two different lists above. In fact, a Set is a Collection, but the behavior is different. (This is a typical application of the idea of inheritance versus polymorphism: showing different behaviors.) Set does not hold duplicate elements. Each element that a Set puts into a Set must be unique, because a Set does not hold duplicate elements. Elements added to a Set must define equals() to ensure uniqueness of the object. Set and Collection have exactly the same interface. The Set interface does not guarantee maintaining the order of elements.

4.List and Set

  1. List and Set inherit from Collection interface, Map does not

  2. A List of elements can be placed in an order that is repeatable. A Set of elements cannot be placed in an order that is not repeatable. The position of an element in a set is determined by its HashCode. Objects added to a set must define equals(). In addition, the list supports a for loop. But set can only be used iteratively, because it is unordered and cannot use subscripts to get the desired value.

  3. .set and List:

    Set:

    Retrieval of elements is inefficient, while deletion and insertion are efficient, and insertion and deletion do not change the position of elements.

    The List:

    Like an array, a List can grow dynamically, making it efficient to find elements, but inefficient to insert and delete elements because it causes other elements to change positions.

  4. ArrayList and LinkedList differences and applicable scenarios ArrayList:

    Advantages: ArrayList implements a data structure based on a dynamic array. Because the addresses are contiguous, the query operation is efficient once the data is stored (it is contiguous in memory).

    Disadvantages: Because addresses are contiguous, ArrayList moves data around, so insert and delete operations are inefficient.

LinkedList:

Advantages: LinkedList is based on the data structure of LinkedList, and the address is arbitrary, so there is no need to wait for a continuous address when creating memory space. For add and remove operations, LinedList has the advantage. LinkedList is suitable for scenarios where you want to start and end operations or insert a specific location

Disadvantages:

Because LinkedList moves Pointers, query performance is low.


Application scenario analysis: ArrayList is used when data needs to be accessed; LinkedList is used when data needs to be added or deleted for multiple times.

Differences between ArrayList and Vector and applicable scenarios

ArrayList has three constructors:

public ArrayList(int initialCapacity)// Construct an empty list with the specified initial capacity.
public ArrayList(a)      By default, an empty list with an initial capacity of 10 is constructed.
public ArrayList(Collection<? extends E> c)// Constructs a list of elements for the specified collection
Copy the code

A Vector has four constructors:

public Vector(a)Construct an empty vector with the specified initial capacity and a capacity increment equal to 0.
public Vector(int initialCapacity)// Construct an empty vector with the size of its internal data array, whose standard capacity increment is zero.
public Vector(Collection<? extends E> c)// Construct a vector containing elements from the specified collection
public Vector(int initialCapacity,int capacityIncrement)Construct an empty vector with the specified initial capacity and capacity increment
Copy the code

ArrayList and Vector are both implemented using arrays, with three main differences:

  1. Vector is multithread safe, which means that multiple threads accessing the same code can produce no uncertain results. ArrayList does not. As can be seen from the source code, many of the methods in the Vector class are modified by synchronized, so that Vector cannot compare with ArrayList in efficiency.

  2. Both use linear contiguous space to store elements, but when space runs out, the two classes grow differently.

  3. Vector can set growth factors, whereas ArrayList cannot.

  4. Vector is an old dynamic array that is thread-synchronized, inefficient and generally frowned on.

Application scenario analysis:

  1. Vector is thread-synchronous, so it is thread-safe, whereas ArrayList is thread-asynchronous and unsafe. Without regard to thread safety, ArrayList is generally more efficient.

  2. If the number of elements in the collection is greater than the current array length, using a Vector has some advantages when using a large amount of data in the collection.

  3. TreeSet is implemented by binary tree (the tree data structure of red-black tree). Data in TreeSet is automatically sorted and null values are not allowed.

  4. A HashSet is an implementation of a hash table. The data in a HashSet is unordered, and null can be placed in a HashSet, but only one NULL can be placed in a HashSet. The values in both cannot be repeated, just like a unique constraint in a database

  5. A HashSet requires that all objects put into it implement the HashCode() method. Objects put into it are identified by a HashCode, whereas String objects with the same content have the same HashCode, so the contents cannot be repeated. But objects of the same class can fit into different instances

Application scenario analysis:

A HashSet is implemented based on a Hash algorithm and generally performs better than TreeSet. For sets designed for quick lookups, we should usually use hashSets, and TreeSet is used only when we need sorting capabilities.

5. When to use it?

Please look at the diagram below for specific analysis


3. Map

A Map is used to store mapped data. A Map holds two sets of data: keys and values, which can be used for any reference type of data, but keys cannot be duplicated. Therefore, the corresponding value can be retrieved by the specified key.

1. Precautions:

Map does not inherit Collection interface. Map provides key-to-value mapping. You can find values by keys. A Map cannot contain the same key, and each key can Map only one value. Map interface3The contents of a Map can be thought of as a set of keys, a set of values, or a set of key-value mappings.Copy the code

2. The Map:

3. Comparison of HashMap and HashTable:

4. A TreeMap:

5. Other classes of Map:

The difference between IdentityHashMap and HashMap is that IdentityHashMap uses == to determine whether two keys are equal, whereas HashMap uses the equals method to compare keys. What’s the difference?

For ==, if applied to a variable of the base data type, the stored “values” are directly compared for equality; If applied to a variable of a reference type, it compares the address of the object to which it points. For equals, note that the equals method does not apply to variables of base datatype. If you do not override the equals method, you compare the address of the object to which the variables referring to the type refer. Classes such as String, Date, etc. override equals to compare the contents of the objects to which they refer.

6. Summary:

HashMap Non-thread-safe HashMap: Implemented based on hash tables. The key classes required to be added using HashMap explicitly define hashCode() and equals()[you can override hashCode() and equals()], and you can tune the initial capacity and load factor to optimize the use of HashMap space.

TreeMap: Non-thread-safe implementation based on red-black trees. TreeMap has no tuning options because the tree is always in equilibrium.

Application scenario analysis:Copy the code

HashMap and HashTable:HashMap removes the contains methods of HashTable, but adds containsValue() and containsKey() methods. HashTable is synchronous, whereas HashMap is asynchronous and is more efficient than HashTable. A HashMap allows empty key values, whereas a HashTable does not.

HashMap: Used to insert, delete, and locate elements in a Map. Treemap: Applies to traversing keys in natural or custom order.

7. Other summaries:

Thread-safe and non-thread-safe collection classes

LinkedList, ArrayList, and HashSet are thread-safe; Vector is thread-safe; HashMap is thread-safe, HashTable is thread-safe; StringBuilder is not thread-safe, StringBuffer is thread-safe.

The data structure

ArrayXxx: the underlying data structure is an array, fast query, add and slow LinkedXxx: the underlying data structure is a linked list, slow query, add and fast HashXxx: the underlying data structure is a hash table. Rely on two methods: hashCode() and equals() TreeXxx: The underlying data structure is a binary tree. There are two ways to sort: natural sort and comparator sort


JavaIO flow

Initial IO flow

IO, also known as in and out, refers to data transfer between applications and external devices. Common external devices include files, pipes, and network connections.

Java handles IO through streams, so what is a stream?

A Stream, “Stream,” is an abstract concept. It refers to a Stream of data (characters or bytes) that is sent in a first-in, first-out manner.

When the program needs to read data, it opens a stream to a data source, be it a file, memory, or network connection. Similarly, when a program needs to write data, it starts a stream to its destination. You can imagine the data sort of flowing through it.

In general, the following are the characteristics of streams:

  1. Fifo: Data written to the output stream is read by the input stream first.

  2. Sequential access: A string of bytes can be written to the stream one by one, and a string of bytes will be read in write order when read, with no random access to intermediate data. (except RandomAccessFile)

  3. Read-only or write-only: A stream can be either an input stream or an output stream. The input stream can only be read and the output stream can only be written. In a data transfer channel, if data is to be written and read, two streams are provided.

IO flow classification

I/O streams are classified into the following three types:

  1. According to the direction of data flow: input flow, output flow

  2. Data by processing unit: byte stream, character stream

  3. By function: node flow, processing flow

1. Input and output streams

Input and output are relative to the program, such as reading and writing files, reading files is the input stream; It’s easy to forget that writing a file is the output stream!

2. Byte stream and character stream

Byte streams and character streams are used in much the same way, unlike the data units that byte streams and character streams operate on, which are 8-bit bytes, whereas character streams operate on 16-bit characters

Why do we have character streams?

Java characters are Unicode standard, Unicode encoding, an English letter or a Chinese character is two bytes.

In UTF-8, a Chinese character is three bytes. For example, in the following figure, the five Chinese characters for “Unknown cloud depth” correspond to 15 bytes: -28-70-111-26-73-79-28-72-115-25-97-91-27-92-124

The problem is that if you use a byte stream to process Chinese, if you read and write the number of bytes corresponding to one character at a time, there will be no problem. Once you split the number of bytes corresponding to one character, there will be garbled characters. To make it easier to handle Chinese characters, Java introduced character streams.

Other differences between byte stream and character stream:

  1. Byte stream is generally used to process images, video, audio, PPT, Word and other types of files. Character streams are generally used to process plain text files, such as TXT files, but cannot process non-text files, such as images and videos. In a word: byte streams can handle all files, while character streams can only handle plain text files.

  2. The byte stream itself has no buffer, so the efficiency of buffering byte stream is very high compared to byte stream. The buffered character stream is not so efficient as the buffered character stream. See efficiency comparison at the end of this article.

In the case of writing a file, we looked at the source code for a character stream and found that it was really useful to use buffers:

3. Node flow and processing flow

Node stream: A stream class that directly operates on data reads and writes, such as FileInputStream

Processing stream (also called wrapper stream) : Linking and encapsulating an existing stream that processes data to provide powerful, flexible read and write capabilities for programs, such as BufferedInputStream.

The process flow and node flow apply Java’s decorator design pattern.

The node flow and the processing flow are vividly depicted in the figure below. The processing flow is the encapsulation of the node flow, and the final data processing is done by the node flow.

One of the most important processing flows is the buffering flow.Copy the code

We know that program – disk interaction is slow for memory operations and can easily become a performance bottleneck for programs. Reducing the interaction between programs and disks is an effective way to improve program efficiency. Buffered streams apply this idea: normal streams read and write one byte at a time, while buffered streams set up a cache in memory that stores enough data to be operated on before interacting with memory or disk. In this way, the number of interactions is reduced by increasing the amount of data for each interaction while the total amount of data remains unchanged.

Think of the example in life. When we move bricks, it must be inefficient to put them on the car one by one. We can use a cart, put the bricks on the cart, then push the cart in front of the car, put the bricks on the car. In this example, the trolley can be regarded as a buffer, the presence of the trolley, we reduce the number of loading, thus improving efficiency.

What needs to be noted is, is buffering flow efficient? Not necessarily. In some cases, buffer flow efficiency may be lower. For details, see IO Flow Efficiency Comparison.

The COMPLETE I/O classification diagram is as follows:


A case in field

Next, let’s look at how to use Java IO.

The text reading and writing example, which is what the article says at the beginning, will be “Matsushita asked the boy, the teacher to pick medicine. Only in this mountain, where the clouds are deep.” Write local text, then read from the file and output to the console.

1, FileInputStream, FileOutputStream

Byte stream is not recommended because it is inefficient

public class IOTest {
	public static void main(String[] args) throws IOException {
		File file = new File("D:/test.txt");

		write(file);
		System.out.println(read(file));
	}

	public static void write(File file) throws IOException {
		OutputStream os = new FileOutputStream(file, true);

		// The string to write to
		String string = Matsushita asked the boy, the teacher to pick medicine. Only in this mountain, where the clouds are deep.";
		// Write to the file
		os.write(string.getBytes());
		/ / close the flow
		os.close();
	}

	public static String read(File file) throws IOException {
		InputStream in = new FileInputStream(file);

		// How many bytes are taken at a time
		byte[] bytes = new byte[1024];
		// An array of bytes used to receive reads
		StringBuilder sb = new StringBuilder();
		// The length of the byte array read is -1, indicating no data
		int length = 0;
		// loop to fetch data
		while((length = in.read(bytes)) ! = -1) {
			// Convert what is read to a string
			sb.append(new String(bytes, 0, length));
		}
		/ / close the flow
		in.close();

		returnsb.toString(); }}Copy the code
BufferedInputStream BufferedOutputStream

Buffering byte streams are designed for high efficiency, and the real read and write operations are FileOutputStream and FileInputStream, so it’s not surprising that the constructor takes objects from these two classes.

public class IOTest {

	public static void write(File file) throws IOException {
		// Buffer byte stream, improve efficiency
		BufferedOutputStream bis = new BufferedOutputStream(new FileOutputStream(file, true));

		// The string to write to
		String string = Matsushita asked the boy, the teacher to pick medicine. Only in this mountain, where the clouds are deep.";
		// Write to the file
		bis.write(string.getBytes());
		/ / close the flow
		bis.close();
	}

	public static String read(File file) throws IOException {
		BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file));

		// How many bytes are taken at a time
		byte[] bytes = new byte[1024];
		// An array of bytes used to receive reads
		StringBuilder sb = new StringBuilder();
		// The length of the byte array read is -1, indicating no data
		int length = 0;
		// loop to fetch data
		while((length = fis.read(bytes)) ! = -1) {
			// Convert what is read to a string
			sb.append(new String(bytes, 0, length));
		}
		/ / close the flow
		fis.close();

		returnsb.toString(); }}Copy the code
3, InputStreamReader, OutputStreamWriter

Character streams are suitable for reading and writing text files. The OutputStreamWriter class is also implemented by the FileOutputStream class, so its constructor is the Object of the FileOutputStream

public class IOTest {
	
	public static void write(File file) throws IOException {
		// OutputStreamWriter can display the specified character set, otherwise use the default character set
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file, true), "UTF-8");

		// The string to write to
		String string = Matsushita asked the boy, the teacher to pick medicine. Only in this mountain, where the clouds are deep.";
		osw.write(string);
		osw.close();
	}

	public static String read(File file) throws IOException {
		InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF-8");
		// String array: How many characters are read at a time
		char[] chars = new char[1024];
		// Append the character array to StringBuilder each time it is read
		StringBuilder sb = new StringBuilder();
		// The length of the character array read is -1, indicating no data
		int length;
		// loop to fetch data
		while((length = isr.read(chars)) ! = -1) {
			// Convert what is read to a string
			sb.append(chars, 0, length);
		}
		/ / close the flow
		isr.close();

		return sb.toString()
	}
}
Copy the code
4, character stream convenience class

Java provides FileWriter and FileReader to simplify reading and writing character streams. New FileWriter is equivalent to new OutputStreamWriter(new FileOutputStream(file, true)).

public class IOTest {
	
	public static void write(File file) throws IOException {
		FileWriter fw = new FileWriter(file, true);

		// The string to write to
		String string = Matsushita asked the boy, the teacher to pick medicine. Only in this mountain, where the clouds are deep.";
		fw.write(string);
		fw.close();
	}

	public static String read(File file) throws IOException {
		FileReader fr = new FileReader(file);
		// How many bytes are taken at a time
		char[] chars = new char[1024];
		// An array of bytes used to receive reads
		StringBuilder sb = new StringBuilder();
		// The length of the byte array read is -1, indicating no data
		int length;
		// loop to fetch data
		while((length = fr.read(chars)) ! = -1) {
			// Convert what is read to a string
			sb.append(chars, 0, length);
		}
		/ / close the flow
		fr.close();

		returnsb.toString(); }}Copy the code
5, BufferedReader, BufferedWriter
public class IOTest {
	
	public static void write(File file) throws IOException {
		// BufferedWriter fw = new BufferedWriter(new OutputStreamWriter(new
		// FileOutputStream(file, true), "UTF-8"));
		// FileWriter can greatly simplify code
		BufferedWriter bw = new BufferedWriter(new FileWriter(file, true));

		// The string to write to
		String string = Matsushita asked the boy, the teacher to pick medicine. Only in this mountain, where the clouds are deep.";
		bw.write(string);
		bw.close();
	}

	public static String read(File file) throws IOException {
		BufferedReader br = new BufferedReader(new FileReader(file));
		// An array of bytes used to receive reads
		StringBuilder sb = new StringBuilder();

		// Read data in rows
		String line;
		// loop to fetch data
		while((line = br.readLine()) ! =null) {
			// Convert what is read to a string
			sb.append(line);
		}
		/ / close the flow
		br.close();

		returnsb.toString(); }}Copy the code

IO stream object

In the first section, we have a general understanding of IO, and completed a few cases, but there is still a lack of more detailed understanding of IO, so next we will decompose Java IO, comb out the complete knowledge system.

The Java class provides more than 40 classes, and we only need to take a closer look at the most important ones for everyday use.

The File type

The File class is used to manipulate files, but it cannot manipulate data in files.

public class File extends Object implements Serializable.Comparable<File>
Copy the code

The File class implements Serializable and Comparable

, indicating that it supports serialization and sorting.

Constructor of the File class

The method name instructions
File(File parent, String child) Creates a new File instance based on the parent abstract pathname and child pathname strings.
File(String pathname) Creates a new File instance by converting the given pathname string to an abstract pathname.
File(String parent, String child) Creates a new File instance based on the parent pathname string and child pathname string.
File(URI uri) Create a new instance of File by converting the given file: URI to an abstract pathname.

A common method of the File class

methods instructions
createNewFile() A new empty file is created inseparably if and only if no file with the name specified by this abstract pathname exists.
delete() Deletes the file or directory represented by this abstract pathname.
exists() Tests whether the file or directory represented by this abstract pathname exists.
getAbsoluteFile() Returns the absolute pathname form of this abstract pathname.
getAbsolutePath() Returns an absolute pathname string for this abstract pathname.
length() Returns the length of the file represented by this abstract pathname.
mkdir() Creates the directory specified by this abstract pathname.

Example of the File class

public class FileTest {
	public static void main(String[] args) throws IOException {
		File file = new File("C:/Mu/fileTest.txt");

		// Check whether the file exists
		if(! file.exists()) {// Create one if it does not exist
			file.createNewFile();
		}
		System.out.println("Absolute path to file:" + file.getAbsolutePath());
		System.out.println("File size:" + file.length());

		// Delete filesfile.delete(); }}Copy the code

Byte stream

InputStream and OutputStream are two abstract classes that are the base classes of byte streams. All concrete byte stream implementation classes inherit from these two classes.

InputStream, for example, inherits Object and implements Closeable

public abstract class InputStream
extends Object
implements Closeable
Copy the code

The InputStream class has many subclasses. Here are some of the more common ones:

To elaborate on the class shown above:

  1. InputStream: InputStream is an abstract base class for all byte input streams. As mentioned earlier, the abstract class cannot be instantiated. It actually exists as a template, defining methods for all implementation classes to handle input streams.

  2. FileInputSream: File input stream, a very important byte input stream used to read files.

  3. PipedInputStream: pipe byte input stream that enables pipe communication between multiple threads

  4. ByteArrayInputStream: An input stream that reads bytes from a byte array (byte[]), that is, the resource files are stored in bytes into the byte array of the class.

  5. FilterInputStream: Decorator class, from which the decorator inherits. These classes are processing classes that encapsulate node classes and implement special functions.

  6. DataInputStream: DataInputStream that decorates other input streams to “allow applications to read basic Java data types from the underlying input stream in a machine-independent manner.”

  7. BufferedInputStream: A buffered stream, decorated with a node stream that has an internal cache for bytes, and it’s more efficient to fill the cache each time and send it instead of one or two bytes.

  8. ObjectInputStream: ObjectInputStream used to provide persistent storage of basic data or objects. In layman’s terms, the ability to transfer objects directly is often used in deserialization. It is also a processing stream, and the constructor takes an instance object of InputStream as an input.

    OutputStream class inheritance diagram:

OutputStreamClass inheritance relationship andInputStreamSimilarly, notice thatPrintStream.

Characters of the flow

Like byte streams, character streams have two abstract base classes, Reader and Writer. All other character stream implementation classes inherit from these two classes.

In the case of Reader, the main implementation subclasses are shown below:

A detailed description of each class:

  1. InputStreamReader: bridge from byte stream to character stream (InputStreamReader constructor input is an instance object of FileInputStream) that reads bytes and decodes them into characters using the specified character set. The character set it uses can be specified by name, given explicitly, or it can accept the platform’s default character set.

  2. BufferedReader: Reads text from the character input stream, setting a buffer to improve efficiency. BufferedReader is a wrapper around InputStreamReader, the input of the former constructor is an instance object of the latter.

  3. FileReader: New FileReader(File File) = new InputStreamReader(new FileInputStream(File, true),”UTF-8″) But FileReader cannot specify a character encoding or a default byte buffer size.

  4. PipedReader: Pipe character input stream. Realize the pipeline communication between multiple threads.

  5. CharArrayReader: A media stream that reads data from a Char array.

  6. StringReader: A medium stream that reads data from a String.

    Writer and Reader are similar in structure and in opposite direction. The only difference is that Writer subclass PrintWriter.

serialization

To be continued


IO flow method

Byte stream method

InputStream main methods:

  1. Read () : Reads a byte of data from this input stream.

  2. Read (byte[] b) : Reads up to B. length of bytes from this input stream into a byte array.

  3. Read (byte[] b, int off, int len) : To read up to len bytes of data from this input stream into a byte array.

  4. Close () : Closes this input stream and releases all system resources associated with it.

Byte OutputStream OutputStream main methods:

  1. Write (byte[] b) : writes B. length bytes from the specified byte array to the file output stream.

  2. Write (byte[] b, int off, int len) : Writes len bytes from the specified byte array starting with offset off to the file output stream.

  3. Write (int b) : Writes the specified byte to this file output stream.

  4. Close () : Closes this input stream and releases all system resources associated with it.

Character stream method

Main methods for Reader:

  1. Read () : Reads a single character.

  2. Read (char[] cbuf) : Reads characters into an array.

  3. Read (char[] cbuf, int off, int len) : Reads characters into a part of an array.

  4. Read (CharBuffer target) : Attempts to read characters into the specified character buffer.

  5. Flush () : Flushes the buffer for this stream.

  6. Close () : Close this stream, but refresh it first.

Writer main methods:

  1. Write (char[] cbuf) : Writes to the character array.

  2. Write (char[] cbuf, int off, int len) : Writes a part of the character array.

  3. Write (int C) : writes a single character.

  4. Write (String STR) : writes a character String.

  5. Write (String STR, int off, int len) : Writes a part of a String.

  6. Flush () : Flushes the buffer for this stream.

  7. Close () : Close this stream, but refresh it first.

In addition, there are two unique methods for character buffering streams:

  • BufferedWriterclassnewLine()Writes a line separator. This method automatically ADAPTS to the line separator on your system.
  • BufferedReaderclassreadLine(): Reads a line of text.

Additional content

Bits, bytes, characters

Byte is a unit of measurement, indicating the amount of data. It is a unit of measurement used in computer information technology to measure storage capacity. Usually, one Byte is equal to eight bits.

Character The letters, numbers, words, and symbols used in computers, such as’ A ‘, ‘B’, ‘$’,’ &’, etc.

Generally, a letter or character occupies one byte in the English state, and a Chinese character is represented by two bytes.

Bytes and characters:

  • In THE ASCII code, one English letter (case insensitive) is one byte, and one Chinese character is two bytes.

  • In UTF-8 encoding, an English word is one byte and a Chinese word is three bytes.

  • In Unicode, an English byte is one byte and a Chinese byte is two bytes.

  • Symbols: English punctuation is one byte, Chinese punctuation is two bytes. For example: English full stop. The size of 1 byte, Chinese full stop. It is 2 bytes in size.

  • Utf-16 encodings require two bytes for each alphanumeric character or Chinese character storage (some Chinese characters in the Unicode extension require four bytes).

  • In UTF-32 encoding, it takes four bytes to store any character in the world.

    I/O flow efficiency

    public class MyTest {
    	public static void main(String[] args) throws IOException {
    		File file = new File("C:/Mu/test.txt");
    		StringBuilder sb = new StringBuilder();
    
    		for (int i = 0; i < 3000000; i++) {
    			sb.append("abcdefghigklmnopqrstuvwsyz");
    		}
    		byte[] bytes = sb.toString().getBytes();
    
    		long start = System.currentTimeMillis();
    		write(file, bytes);
    		long end = System.currentTimeMillis();
    
    		long start2 = System.currentTimeMillis();
    		bufferedWrite(file, bytes);
    		long end2 = System.currentTimeMillis();
    
    		System.out.println("Ordinary byte stream time:" + (end - start) + " ms");
    		System.out.println("Buffer byte stream time:" + (end2 - start2) + " ms");
    
    	}
    
    	// Plain byte stream
    	public static void write(File file, byte[] bytes) throws IOException {
    		OutputStream os = new FileOutputStream(file);
    		os.write(bytes);
    		os.close();
    	}
    
    	// Buffer byte stream
    	public static void bufferedWrite(File file, byte[] bytes) throws IOException {
    		BufferedOutputStream bo = new BufferedOutputStream(newFileOutputStream(file)); bo.write(bytes); bo.close(); }}Copy the code

    Running results:

    Ordinary byte stream time:250Ms buffer byte stream time:268 ms
    Copy the code

    The result surprised me. The buffer flow was supposed to be efficient. To know why, can only go to the source code to find the answer. Look at the write method for byte buffered streams:

    public synchronized void write(byte b[], int off, int len) throws IOException {
        if (len >= buf.length) {
            /* If the request length exceeds the size of the output buffer, flush the output buffer and then write the data directly. In this way buffered streams will cascade harmlessly. */
            flushBuffer();
            out.write(b, off, len);
            return;
        }
        if (len > buf.length - count) {
            flushBuffer();
        }
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }
    Copy the code

    The comments make it clear: if the request exceeds the size of the output buffer, flush the output buffer and write the data directly. In this way, buffer flows cascade harmlessly.

    But, as to why so design, I did not want to understand, which understand big guy can leave a message to give directions.

    Based on the above situation, to compare the efficiency difference between ordinary byte stream and buffer byte stream, it is necessary to avoid reading and writing long strings directly. Therefore, the following comparison case is designed: copy files with byte stream and buffer byte stream separately.

public class MyTest {
	public static void main(String[] args) throws IOException {
		File data = new File("C:/Mu/data.zip");
		File a = new File("C:/Mu/a.zip");
		File b = new File("C:/Mu/b.zip");

		StringBuilder sb = new StringBuilder();

		long start = System.currentTimeMillis();
		copy(data, a);
		long end = System.currentTimeMillis();

		long start2 = System.currentTimeMillis();
		bufferedCopy(data, b);
		long end2 = System.currentTimeMillis();

		System.out.println("Ordinary byte stream time:" + (end - start) + " ms");
		System.out.println("Buffer byte stream time:" + (end2 - start2) + " ms");
	}

	// Plain byte stream
	public static void copy(File in, File out) throws IOException {
		// Encapsulate the data source
		InputStream is = new FileInputStream(in);
		// Encapsulate the destination
		OutputStream os = new FileOutputStream(out);
		
		int by = 0;
		while((by = is.read()) ! = -1) {
			os.write(by);
		}
		is.close();
		os.close();
	}

	// Buffer byte stream
	public static void bufferedCopy(File in, File out) throws IOException {
		// Encapsulate the data source
		BufferedInputStream bi = new BufferedInputStream(new FileInputStream(in));
		// Encapsulate the destination
		BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(out));
		
		int by = 0;
		while((by = bi.read()) ! = -1) { bo.write(by); } bo.close(); bi.close(); }}Copy the code

Running results:

Ordinary byte stream time:184867Ms buffer byte stream time:752 ms
Copy the code

This time, the efficiency difference between the normal byte stream and the buffer byte stream is obvious, up to 245 times.

Let’s look at the efficiency of the character stream versus the buffered character stream:

public class IOTest {
	public static void main(String[] args) throws IOException {
		// Data preparation
		dataReady();

		File data = new File("C:/Mu/data.txt");
		File a = new File("C:/Mu/a.txt");
		File b = new File("C:/Mu/b.txt");
		File c = new File("C:/Mu/c.txt");

		long start = System.currentTimeMillis();
		copy(data, a);
		long end = System.currentTimeMillis();

		long start2 = System.currentTimeMillis();
		copyChars(data, b);
		long end2 = System.currentTimeMillis();

		long start3 = System.currentTimeMillis();
		bufferedCopy(data, c);
		long end3 = System.currentTimeMillis();

		System.out.println("Ordinary byte stream 1 time:" + (end - start) + "Ms, file size:" + a.length() / 1024 + " kb");
		System.out.println("Ordinary byte stream 2 time:" + (end2 - start2) + "Ms, file size:" + b.length() / 1024 + " kb");
		System.out.println("Buffer byte stream time:" + (end3 - start3) + "Ms, file size:" + c.length() / 1024 + " kb");
	}

	// Normal character streams do not use arrays
	public static void copy(File in, File out) throws IOException {
		Reader reader = new FileReader(in);
		Writer writer = new FileWriter(out);

		int ch = 0;
		while((ch = reader.read()) ! = -1) {
			writer.write((char) ch);
		}
		reader.close();
		writer.close();
	}

	// Normal character stream uses character stream
	public static void copyChars(File in, File out) throws IOException {
		Reader reader = new FileReader(in);
		Writer writer = new FileWriter(out);

		char[] chs = new char[1024];
		while((reader.read(chs)) ! = -1) {
			writer.write(chs);
		}
		reader.close();
		writer.close();
	}

	// Buffer character stream
	public static void bufferedCopy(File in, File out) throws IOException {
		BufferedReader br = new BufferedReader(new FileReader(in));
		BufferedWriter bw = new BufferedWriter(new FileWriter(out));

		String line = null;
		while((line = br.readLine()) ! =null) {
			bw.write(line);
			bw.newLine();
			bw.flush();
		}

		// Release resources
		bw.close();
		br.close();
	}

	// Data preparation
	public static void dataReady(a) throws IOException {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < 600000; i++) {
			sb.append("abcdefghijklmnopqrstuvwxyz");
		}
		OutputStream os = new FileOutputStream(new File("C:/Mu/data.txt"));
		os.write(sb.toString().getBytes());

		os.close();
		System.out.println("Finished"); }}Copy the code

Running results:

Ordinary character stream1Time:1337Ms, file size:15234KB Ordinary character stream2Time:82Ms, file size:15235KB Buffer character stream time:205Ms, file size:15234 kb
Copy the code

We tested it several times, and the results were similar. There was no significant improvement in the efficiency of the visible character buffer stream. We used its readLine() and newLine() methods more.