Learning notes of Liao Xuefeng's java tutorial -- object oriented Foundation

Posted by kykin on Tue, 08 Feb 2022 11:08:04 +0100

From C + + to a little Scala, I learned a little Python, and then back to Java.

In the Internet age, the foundation of Java still needs to be strengthened. From java web to big data, it is indispensable.

Learn Liao Xuefeng's course and brush it quickly. Update a note every day.

Run java program and execute java classname

Like hello Class, execute java Hello; If you execute java Hello Class will report an error.

Length, length(), size() in Java

length :
Arrays (int[], double[], String[]) — obtain Array Length of

length():
String related Object (String, StringBuilder, etc) — Get string length

size():
Collection Object (ArrayList, Set, etc) — Gets the size of the collection object

Variable parameter

class Group {
    private String[] names;

    public void setNames(String... names) { //Use type Definition, equivalent to array type:
        this.names = names;
    }
}

See: https://www.liaoxuefeng.com/wiki/1252599548343744/1260452774408320

this can be omitted if there is no conflict between variables

class Person {
    private String name;

    public String getName() {
        return name; // If there is no naming conflict, you can omit this. Equivalent to this name
    }
}

class modifier, the difference between adding public and not adding public

Add public to represent the global class, which can be import ed into any class.

Without public, it is reserved by default and can only be referenced by other classes in the same package.

inherit

Use the extends keyword:

class Student extends Person {
    // Do not repeat the name and age fields / methods,
    // You only need to define the new score field / method:
    private int score;

    public int getScore() { ... }
    public void setScore(int score) { ... }
}

The subclass automatically obtains all fields of the parent class. It is strictly prohibited to define fields with the same name as the parent class!

Java only allows one class to inherit from one class (you only have one father!), A parent class can have multiple subclasses. It inherits from the object class by default. Only object has no parent class.

       ┌───────────┐
       │  Object   │
       └───────────┘
             ▲
             │
       ┌───────────┐
       │  Person   │
       └───────────┘
          ▲     ▲
          │     │
          │     │
┌───────────┐ ┌───────────┐
│  Student  │ │  Teacher  │
└───────────┘ └───────────┘

protected keyword, which allows subclasses to access the fields of the parent class.

class Person {
    protected String name;
    protected int age;
}

class Student extends Person {
    public String hello() {
        return "Hello, " + name; // OK!
    }
}

super()

If the parent class does not have a default constructor, the child class must explicitly call super() and give parameters so that the compiler can locate an appropriate constructor of the parent class.

This also leads to another problem: that is, the subclass will not inherit the constructor of any parent class. The default construction method of subclasses is automatically generated by the compiler, not inherited.

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        super(name, age); // Call the constructor Person(String, int) of the parent class
        this.score = score;
    }
}

upcasting

The subclass becomes the parent class, which is completely ok, because the subclass must have all the functions of the parent class:

Person p = new Student(); // Yes, the parent class declaration can point to a subclass instance

downcasting

Parent class to child class, failed; If the subclass is turned up to be the parent of the subclass and then back to the subclass, then OK! (repeated horizontal jumps, the result is very good)

Person p1 = new Student(); // upcasting, ok
Person p2 = new Person();
Student s1 = (Student) p1; // ok, p1 is a subclass, but it turns up to be a parent class
Student s2 = (Student) p2; // runtime error! ClassCastException!

During the downward transformation, the transformation from p1 to Student will succeed, because p1 does point to the Student instance, and the transformation from p2 to Student will fail, because the actual type of p2 is Person, and the parent class cannot be changed into a child class, because the child class has more functions than the parent class, and more functions cannot be changed out of thin air.

To avoid downward transition errors, you can use the instanceof operator:

Object obj = "hello";
if (obj instanceof String) {
    String s = (String) obj;
    System.out.println(s.toUpperCase());
}

Polymorphic polymorphic

The characteristic of polymorphism is that the runtime can dynamically determine the subclass methods to be called. When a method is called on a type, the actual method executed may be the override method of a subclass.

public class Main {
    public static void main(String[] args) {
        // Tax is calculated for a small partner with ordinary income, wage income and special allowance of the State Council:
        Income[] incomes = new Income[] {
            new Income(3000),
            new Salary(7500),
            new StateCouncilSpecialAllowance(15000)
        };
        System.out.println(totalTax(incomes));
    }

    public static double totalTax(Income... incomes) {
        double total = 0;
        for (Income income: incomes) {
            total = total + income.getTax();
        }
        return total;
    }
}

Using polymorphism, the totalTax() method only needs to deal with Income. It can correctly calculate the total tax without knowing the existence of Salary and StateCouncil special allowance.

Polymorphism has a very powerful function, which is to allow adding more types of subclasses to realize function expansion without modifying the code based on the parent class.

final

Before it can be used in a class or method, it means that inheritance is prohibited! That is, it cannot be overridden.

It can also be used in front of the field, indicating that modification is prohibited.

abstract class

If the method of the parent class itself does not need to implement any function, but only to define the method signature, so that the child class can override it, then the method of the parent class can be declared as an abstract method, and then the Person class itself must be declared as abstract before it can be compiled correctly:

abstract class Person {
    public abstract void run();
}

It can only be used to implement Abstract subclasses, otherwise it can only be used to implement Abstract subclasses. Therefore, the abstract method is actually equivalent to defining the "specification".

The essence of abstract oriented programming is:

  1. The upper layer code only defines specifications (for example: abstract class Person);

  2. The business subclass can be implemented normally (if the business logic does not need to be compiled);

  3. The specific business logic is implemented by different subclasses, and the caller does not care.

Always call methods with abstract classes.

Interface

If an abstract class has no fields, all methods are abstract methods:

abstract class Person {
    public abstract void run();
    public abstract String getName();
}

You can rewrite the abstract class as interface:

interface Person {
    void run();
    String getName();
}

The two modifiers of public abstract do not need to be written out (the effect is the same whether they are written or not).

When a specific class implements an interface, you need to use the implements keyword. for instance:

class Student implements Person {
    private String name;

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

    @Override
    public void run() {
        System.out.println(this.name + " run");
    }

    @Override
    public String getName() {
        return this.name;
    }
}

In Java, a class can only inherit from another class, not from multiple classes. However, a class can implement multiple interface s, for example:

class Student implements Person, Hello { // Two interface s are implemented
    ...
}

Comparison between abstract classes and interfaces:

Interface can inherit another interface. Use extensions:

interface Hello {
    void hello();
}

interface Person extends Hello { //Person has the hello() abstract method by default
    void run();
    String getName();
}

The interface can have a default method:

interface Person {
    String getName();
    default void run() { //Subclasses can choose not to implement the method
        System.out.println(getName() + " run");
    }
}

The default method is different from the ordinary method of the abstract class. Because the interface has no field, the default method cannot access the field, while the ordinary method of the abstract class can access the instance field.

Static fields and static methods

Static field

The field modified with static is called static field.

They do not belong to an instance, but belong to this class!

The instance field has its own independent "space" in each instance, but the static field has only one shared "space", which will be shared by all instances:


class Person {
    public String name;
    public int age;
    // Define static field number:
    public static int number;
}

Instance variables are not recommended Static fields to access static fields, because in Java programs, instance objects do not have static fields. In code, instance objects can access static fields only because the compiler can automatically convert them to class names according to the instance type Static fields to access static objects.

It is recommended to use the class name to access static fields. Static fields can be understood as fields describing the class itself (non instance fields). For the above code, the better way to write it is:

Person.number = 99;
System.out.println(Person.number);

Static method

Similarly, you can directly call with the class name without instantiation.

public class Main {
    public static void main(String[] args) {
        Person.setNumber(99);
        System.out.println(Person.number);
    }
}

class Person {
    public static int number;

    public static void setNumber(int value) {
        number = value;
    }
}

Inside the static method, the this variable and the instance field cannot be accessed. It can only access the static field. Because the static method belongs to class and not instance.

Static properties and methods are loaded into memory when the program starts, regardless of whether these methods and properties are used in the future.

Static methods are often used in tool classes. For example:

Arrays.sort()

Math.random()

Static methods are also often used as auxiliary methods. Notice that the Java program entry main() is also a static method.

practice

Add a static field count and static method getCount to the Person class to count the number of instances created.

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        System.out.println(p.getCount());
        p = new Person();
        System.out.println(p.getCount());
    }
}

class Person {
    public static int count = 0;
    public Person(){
        count++;
    }
    int getCount(){
        return count;
    }
}

Print:

1
2

Interface static field

Although the interface cannot have instance fields, it can have static fields, and the static fields must be of final type:

public interface Person {
    public static final int MALE = 1;
    public static final int FEMALE = 2;
}

You can remove public static final, and the compiler adds it by default:

public interface Person {
    // The compiler will automatically add public statc final:
    int MALE = 1;
    int FEMALE = 2;
}

Interface static fields must be given default values.

package

When the Java virtual machine executes, the JVM only looks at the complete class name. Therefore, as long as the package name is different, the class will be different.

Special note: packages have no parent-child relationship. java.util and Java util. Zip is a different package, and there is no inheritance relationship between them.

Compiled class files also need to be stored according to the package structure:

Classes in the same package can access the fields and methods of the package scope. Fields and methods that do not need public, protected and private modifications are package scopes.

How to import packages:

  1. Full name: mr.jun.Arrays arrays = new mr.jun.Arrays();
  2. Use import: import mr.jun.Arrays; Then write arrays;
  3. You can import *, but it is not recommended, because after importing too many packages, you can't tell which class belongs to;
  4. Import static: import static fields and methods of a class, import static Java lang.System.*;, That is, all static fields and static methods of the system class are imported;

The Java compiler checks the order of classes

The Java compiler finally compiled it The class file only uses the full class name. Therefore, in the code, when the compiler encounters a class name:

If it is a complete class name, you can directly find the class according to the complete class name;

If it is a simple class name, find it in the following order:

  • Find out whether this class exists in the current package;

  • Find out whether the import ed package contains this class;

  • Find Java Whether the Lang package contains this class.

If the class name cannot be determined according to the above rules, the compilation will report an error.

The compiler defaults to two import s

  1. By default, other class es of the current package are automatically import ed;
  2. The default is to automatically import Java lang.*.

Best practices

  1. The recommended practice is to use inverted domain names to ensure uniqueness, such as com liaoxuefeng. sample
  2. Be careful not to interact with Java The class names of Lang package are the same, that is, do not use these names for your own class:
    String
    System
    Runtime
    ...
    Do not duplicate the name of the JDK common class:
    java.util.List
    java.text.Format
    java.math.BigInteger
    ...

Scope

The built-in access permissions of Java include public, protected, private and package permissions;

Package scope

Package scope refers to a class that allows access to the same package without public and private modifications, as well as fields and methods without public, protected and private modifications.

final

  1. final class to prevent the class from being inherited;
  2. protected final void hi(), to prevent the method from being overwritten;
  3. private final int n = 0 to prevent the field from being re assigned;
  4. final int t parameter to prevent the local variable t from being re assigned;

Nested class

Classes defined within a class are called nested class es, which have access to private.

public class Main {
    public static void main(String[] args) {
        Inner i = new Inner();
        i.hi();
    }

    // private method:
    private static void hello() {
        System.out.println("private hello!");
    }

    // Static inner nested classes:
    static class Inner {
        public void hi() {
            Main.hello();  //Access private method
        }
    }
}

Best practices

  1. If you are not sure whether you need public, you will not declare it as public, that is, expose as few external fields and methods as possible.

  2. Defining the method as package permission is helpful for testing, because as long as the test class and the tested class are in the same package, the test code can access the package permission method of the tested class.

  3. One java files can only contain one public class, but can contain multiple non-public classes. If there is a public class, the file name must be the same as that of the public class.

Inner Class

Ordinary Inner Class

class Outer {
    private String name;

    Outer(String name) {
        this.name = name;
    }

    class Inner {
        void hello() {
            System.out.println("Hello, " + Outer.this.name);
        }
    }
}

To instantiate a Inner, we must first create an instance of Outer, and then invoke the new of the Outer instance to create the Inner instance:

Outer.Inner inner = outer.new Inner();

Because the Inner Class not only has a this pointing to itself, but also implicitly holds an Outer Class instance. You can use Outer This accesses this instance. Therefore, instantiating an Inner Class cannot be separated from the Outer instance.

Compared with ordinary classes, Inner Class has an additional "privilege" besides being able to reference Outer instances, that is, it can modify the private field of Outer Class. Because the scope of Inner Class is within Outer Class, it can access the private field and method of Outer Class.

Observe the Java compiler after compiling Class. Outer can be compiled as an outer class Class, and the Inner class is compiled as outer $Inner class.

Anonymous Class

Belonging to an internal class. This is a little difficult to understand. So I referred to the rookie tutorial and found that it was clearer:
https://www.runoob.com/java/java-anonymous-class.html

class outerClass {

    // Define an anonymous class
    object1 = new Type(parameterList) {
         // Anonymous class code
    };
}

The above code creates an anonymous class object object1. The anonymous class is defined in the form of expression, so it ends with a semicolon; Come to an end.

Usually inherit a parent class or implement an interface:

class Polygon {
   public void display() {
      System.out.println("stay Polygon Class interior");
   }
}

class AnonymousDemo {
   public void createClass() {

      // The anonymous class created inherits the Polygon class
      Polygon p1 = new Polygon() {
         public void display() {
            System.out.println("Inside an anonymous class.");
         }
      };
      p1.display();
   }
}

class Main {
   public static void main(String[] args) {
       AnonymousDemo an = new AnonymousDemo();
       an.createClass();
   }
}

I understand a little. It's a bit like a lambda expression. I don't care about the name, but only the result.

Static Nested Class

The last internal class.

The Inner Class decorated with static is very different from the Inner Class. It is no longer attached to the instance of Outer, but a completely independent class. Therefore, Outer cannot be referenced This, but it can access Outer's private static fields and static methods. If you move StaticNested outside of Outer, you lose access to private.

Internal class summary

The internal classes of Java can be divided into Inner Class, Anonymous Class and Static Nested Class:

Inner Class and Anonymous Class are essentially the same. They must be attached to the instance of Outer Class, that is, they implicitly hold outer This instance and has the private access permission of Outer Class;

Static Nested Class is a separate class, but it has private access to Outer Class.

classpath

classpath is an environment variable used by the JVM to indicate how the JVM searches for class es.

There are three ways to set classpath:

  1. Setting classpath environment variable in system environment variable is not recommended;

  2. Setting classpath variable when starting JVM is recommended:
    java -classpath .;C:\work\project1\bin;C:\shared abc.xyz.Hello
    Or use the abbreviation of - cp:
    java -cp .;C:\work\project1\bin;C:\shared abc.xyz.Hello

  3. Instead of the first two methods, the default is, The current directory. The default current directory Enough for most cases.

Run the Java program in the IDE, and the - cp parameter automatically passed in by the IDE is the bin directory of the current project and the imported jar package.

jar package Java Archive

Jar package can make the directory level of package organization and all files under each directory (including. class files and other files) into a jar file. In this way, it is much easier to back up or send to customers.

The jar package is equivalent to a directory. If we want to execute the class of a jar package, we can put the jar package into the classpath:

java -cp ./hello.jar abc.xyz.Hello

In this way, the JVM will be automatically in hello Search for a class in the jar file.

The jar package is actually a zip file. You can manually package a group of classes into a zip file, and then change the suffix to Jar, a jar package is created successfully.

META-INF

Most JAR files contain a META-INF directory, which is used to store the configuration data of packages and extensions, such as security and version information. The Java 2 platform (Standard Version [J2SE]) identifies and interprets the following files and directories in the META-INF directory to configure applications, extensions and class loaders:

  • MANIFEST.MF: main class and other information can be specified. The JVM will automatically read manifest MF file. If there is a main class, you don't have to specify the name of the class to start on the command line, but use a more convenient command: Java - jar hello jar
    The jar package can also contain other jar packages. At this time, it needs to be in manifest classpath is configured in MF file.
    In large projects, it is not possible to manually write manifest MF file, and then manually create the zip package. The Java community provides a large number of open source construction tools, such as Maven, which can easily create jar packages.
  • Files packaged through MAVEN plug-in, such as:
maven
services :  Store all service provider profiles
  • There are also some things you don't often see:
INDEX.LIST : This file was created by jar New options for tools -i Generation, which contains the location information of the package defined in the application or extension. It is JarIndex Part of the implementation and used by the class loader to speed up the class loading process.
.SF: This is JAR Signature file of the file
.DSA: The signature block file associated with the signature file that stores the information used for signing JAR Public signature of the file.
LICENSE.txt : Certificate information
NOTICE.txt :  Announcement information

reference resources: Talk about JAR files and manifest MF

Module

jar is just a container for storing classes. It doesn't care about the dependencies between classes.

Modules introduced from Java 9 are mainly used to solve the problem of "dependency". If a.jar must rely on another b.jar to run, we should add some instructions to a.jar to make the program automatically locate b.jar when compiling and running. This class container with "dependency" is a module.

In order to show the determination of Java modularization, starting from Java 9, the original Java standard library has been divided into dozens of modules from a single huge rt.jar jmod extension ID, which can be found in $Java_ Find them in the home / jmods Directory:

java.base.jmod
java.compiler.jmod
java.datatransfer.jmod
java.desktop.jmod
...

these Each jmod file is a module, and the module name is the file name. For example: module Java The file corresponding to base is Java base. jmod. The dependencies between modules have been written to module info Class file. All modules rely directly or indirectly on Java Base module, only Java The base module does not depend on any module. It can be regarded as a "root module". For example, all classes inherit directly or indirectly from Object.

Encapsulating a pile of classes into jar s is just a packaging process, while encapsulating a pile of classes into modules requires not only packaging, but also writing dependencies, and can also contain binary code (usually JNI extensions). In addition, the module supports multiple versions, that is, different versions can be provided for different JVM s in the same module.

Topics: Java