Class variables, class methods, code blocks, abstract classes, interfaces, and inner classes

After learning about encapsulation, inheritance, and polymorphism in object-oriented programming, I recently came into contact with several new knowledge points. Sort it out here, help yourself to review, and also record my learning experience.

1. Class variables and class methods

Instance objects of the same class only share a template prototype, and do not share common variables and common methods, that is, the instance attributes and common methods of each object are stored in independent spaces without interfering with each other. The same is true for parent-child classes with an inheritance relationship, and the access to attributes satisfies the principle of proximity, and the invocation of methods satisfies the dynamic binding mechanism.

//class variable definition
access modifier static data type variable name;

// class method definition
access modifier static data return type method name (){}

Class variables and class methods (hereinafter collectively referred to as class members or static members) are generated when the class is loaded, and the life cycle begins with the loading of the class and ends with the demise of the class. Since class information is loaded only once, class members are also loaded only once. We only need to know that they are stored in an area in the heap (after JDK8), and they can be shared by all instance objects of this class, that is, any instance object can satisfy the access modifier condition in strong> to access them.

But this kind of access is one-way, that is, the instance object can access the class members, but the class members cannot access the ordinary properties and ordinary methods in the instance object. My personal understanding is that because the class members are already generated when the class is loaded, all instance objects of this class can know the storage addresses of the class members, so they can be accessed. However, the instance objects are new after the class is loaded, and the class members cannot know their addresses, so they cannot access their ordinary properties and methods. However, class members can access each other because they are stored in the same memory area in the heap.

Since class members are generated when the class is loaded, they can be called directly through the class name (such as the main method), instead of creating an object and then calling it through the object like ordinary properties and methods. Of course, it is also possible to call class members by object name, as long as the conditions of the access modifier are met, but it is recommended to use the class name to call.

Here are a few things to keep in mind:

1. Class variables cannot be assigned in the object constructor: because class variables are already generated when the class is loaded, its initialization can only be default initialization, explicit initialization at the time of definition, or in a static code block ( This will be discussed later) to initialize. The constructor is a member of the initialized object, not a class member.

2. Object-related keywords such as this and super cannot be used in class methods. It must be made clear that the access between class members and objects is one-way, and class members cannot access objects.

3. Class methods cannot be rewritten: That is, class methods can be inherited, but cannot be rewritten (covered).

Before explaining this, it is necessary to clarify what exactly is rewriting (overriding)?

By definition, rewriting means that a subclass rewrites the method of the parent class. The method name and parameters are required to be the same. The access modifier cannot be narrowed. The return type must be the same class or subclass as the return type of the parent class. But is it enough to just satisfy this definition? If this is the case, for the class method of the parent class, the subclass can write a class method with the same name and parameters according to the definition of rewriting, but in this case, it can only be said that the class method of the subclass replaces the class method of the parent class Methods are hidden, not overridden.

Rewriting must not only meet the requirements from the definition, but also need to have the ability to combine with the dynamic binding mechanism, that is, the method you “rewrite” must be able to meet the dynamic binding mechanism to be called rewriting , otherwise it can only be called hidden. Rewriting is the premise of realizing polymorphism. Let’s think about it carefully. The so-called method polymorphism and object polymorphism are actually the core of which is that the method of the parent class is rewritten (covered) by the subclass. Java’s polymorphism is also called Java’s dynamic binding technology, that is, only at runtime can we know which method is being called, which is called polymorphism.

Back to our beginning: class methods can be inherited, but cannot be overridden. When a subclass tries to override the class method of the parent class, the “overridden” class method will not participate in the dynamic binding mechanism, that is, the “overridden” class method (static method) will not Will be bound to the runtime type, but will be bound to the compiled type like a property.

Java supports the rewriting of class methods syntactically, but it cannot achieve the purpose of polymorphism in terms of operational effect.

for example:

public class Test {
    public static void main(String[] args) {
        AAA a = new BBB();
        System.out.println(a.n);//output 5
        a.aaa();//Output This is class AAA
    }
}

class AAA{
    int n = 5;
    static void aaa(){
        System.out.println("This is class AAA");
    }
}

class BBB extends AAA{
    int n = 10;
    static void aaa(){
        System.out.println("This is class BBB");
    }
}

This is enough to show that class methods cannot be overridden, but can only be hidden.

To sum up the third point: class methods can be inherited, but cannot be overridden. Only ordinary method calls can be polymorphic. The class method is generated when the class is loaded, so it is only related to the compilation type, that is, the compilation type determines which static method of the class is called, and does not implement the dynamic binding mechanism, even if the class method of the subclass has the same name as the class method of the parent class Same as parameters, these two methods have nothing to do, it can only be said that the class method of the subclass hides the class method of the parent class.

2. Code block

Code blocks, also known as initialization blocks, belong to members of a class, similar to methods. But unlike a method, a code block does not have a method name, return value, access modifier and parameters, but only has a method body.

The code block is not explicitly called by the object or class, but is called automatically when the class is loaded or the object is created. It is equivalent to another form of constructor, which can perform initialization operations. And the order of automatic calls is: call the code block first, and then call the constructor (we will explain the order of initialization calls later).

There are two kinds of code blocks: normal code blocks and static code blocks.

//Ordinary code block, ";" can be omitted
{
};

// static code block
static {
};

Let’s talk about static code blocks here. We mentioned static methods earlier. Static code blocks are similar to methods, so static code blocks are also generated with the loading of classes. The storage location is the same as static members, and the same as static methods, only Can call static members. The difference is that the static code block will be executed automatically (after all, it is a code block, and the code block is automatically executed), but because the class information only needs to be loaded once, the static code block will only be executed once. The normal code block is executed every time an object is created.

I mentioned “class loading” earlier, so the question is, when is the class loaded?

At present, there are three situations that can be thought of: 1. When creating an object instance; 2. When creating a subclass object, the information of the parent class will also be loaded; 3. When using the static members of the class. But it should be noted that the class information will only be loaded once.

Now let’s take a look at the steps of an object initialization:

As mentioned in my previous article, “When an object is created, firstly, the relevant information of the class to which the object belongs is loaded in the method area of the JVM. After the loading is completed, when the new statement is executed, it will open up A piece of space, loading attributes, the attribute initialization here is divided into three steps, the first step is to set the default value of the attribute, that is, the Int type is set to 0, the Boolean type is set to false, the reference type is set to null, etc.; the second step is Check whether there is an assignment to the attribute in the class definition, and if so, load it into the heap; the third step is to check whether there is a parameter constructor, and if so, assign the content in the constructor to the attribute Go up. At this point, it can be considered that an initialization of the object has been completed.”

After learning about code blocks and static properties, the initialization of an object can now be expressed as:

When creating an object, the first step is to set the default value of the static property, and then call the static code block and static property initialization (definition assignment). It should be explained here that the priority of code block and attribute initialization is the same, and the order of execution depends on the order of definition. The second step is to set the default value of common properties, and then call common code block and normal property initialization. The third step is to call the constructor.

Comparing these two statements, in fact, there is only one more code block call before the constructor, and the rest are essentially unchanged. Static attributes and static code blocks are already generated when class loading information, so put them in the first step. The steps to load properties are preceded by: default initialization, explicit initialization, then constructor. Now there is an additional code block, and its priority is the same as that of explicit initialization, so the steps to load properties now become: default initialization, explicit initialization and code block call, and then the constructor. Because the constructor is used to initialize objects and has nothing to do with static members, the initialization steps of static properties are only the first two.

If it is to create a subclass object, what is the difference? No, we just need to remember one thing:To create an object instance, the class information must be loaded first, and then the object instance should be initialized. These two steps are to be performed in the order from the parent class to the child class. So to create a subclass object, their static code block, static property initialization, common code block, common property initialization, the calling order of the construction method is as follows (property initialization here refers to explicit initialization, default initialization is always is called first):
1. Static code block and static attribute initialization of the parent class (parent class information loading)
2. Static code block and static attribute initialization of subclasses (subclass information loading)
3. Ordinary code blocks and ordinary properties of the parent class are initialized, and then the parent class constructor (parent class initialization)
4. Ordinary code blocks and ordinary attributes of subclasses are initialized, and then subclass constructors (subclass initialization)

3. Abstract class

Before introducing abstract classes, let’s introduce abstract methods.

The abstract method is: when some methods of a parent class need to be declared, but you are not sure how to implement them, you can declare them as abstract methods at this time, that is, methods without method bodies, and empty {} are not allowed. This abstract method is then implemented by subclasses. A class that contains abstract methods can be declared as an abstract class.

//abstract class A
abstract class A{

//The abstract method eat cannot have a method body.
public abstract void eat();

}

An abstract class does not have to contain an abstract method, but an abstract method can only exist in an abstract class. So if there are abstract methods in an abstract class, then the subclasses that inherit it either implement all the abstract methods, or declare them as abstract classes. The value of abstract classes lies more in design.

In general, abstract classes need to be inherited and abstract methods need to be overridden. So we will learn some modifiers later, and we must pay attention not to contradict these two points. For example, we talked about static static methods above, but can abstract methods be modified by static? No, because static methods cannot be overridden, and abstract methods need to be overridden.

A few notes:

1. abstract can only modify classes or methods.

2. Abstract class cannot be instantiated: A class is a concrete description of an object, but an abstract class is not specific, and we cannot generate an unspecific object. For example, we can new an apple, but not a new fruit. And we cannot accurately allocate memory to the abstract methods in the abstract class, so the compiler stipulates that an abstract class cannot be instantiated.

3. Whether it can be instantiated has nothing to do with whether there is a construction method: the construction method is to initialize the object, and the new keyword is to apply for memory from the JVM to create the object, so abstract classes can have construction methods. (This point can also be considered from the fact that abstract classes generally need to be inherited. Ordinary classes inherit abstract classes, so the initialization of the parent class must be completed before the initialization of ordinary classes, so abstract classes can have constructors. )

Fourth, interface

The interface is to give some methods that have not been implemented, encapsulate them together, and when a certain class is to be used, implement these methods according to the specific situation, which can be used to standardize the code.

Before JDK7.0, all methods in the interface had no method body, that is, they were all abstract methods.

After JDK8.0, interfaces can have static methods, default methods modified by the default keyword, and abstract methods, that is, interfaces can have specific implementations of methods, but they are limited to these three methods.

All methods in the interface are prepended with public abstract by default, and properties are prepended with public static final by default. (The final keyword plays a role of “protection”. The modified class protected class cannot be inherited, the modified method protected method cannot be rewritten, and the modified attribute protected attribute cannot be modified (but finally modified attributes The assignment must be completed during initialization, because this property cannot be modified after initialization~).)

interface interface name{
//Property (must be initialized because it is final)
  //method (three: abstract method, default implementation method, static method)
}

class class name implements interface name{
    // own attributes;
    //Own method;
    //The abstract method of the interface that must be implemented (because abstract methods cannot exist in ordinary classes, they must be implemented, unless abstract classes are used to implement)
}

Analysis of interface and abstract class, implements interface and extends class name:

1. An interface can be regarded as an abstract class in essence. For example, an interface cannot be instantiated, but an interface can only contain abstract methods, default methods, and static methods, while an abstract class can contain all types of methods. Moreover, the properties of the interface have been restricted and must be public static final, so the interface cannot have a constructor (it can be understood from the fact that static property initialization does not require the use of a constructor), while an abstract class can have a constructor.

2. Implement the interface and inherit a class:

First of all, the class that implements the interface and inherits the parent class can access the properties and methods of the interface and the parent class. In this regard, implementing the interface and inheriting are the same. Moreover, the interface can point to the class that implements the interface, that is, the interface can be polymorphic, and it also has a dynamic binding mechanism. At the same time, the relationship of the interface is transferable like the inheritance relationship.

But the difference between implementing an interface and inheriting a class is that implementing an interface only needs to satisfy the like-a relationship, while inheriting a class needs to satisfy the is-a relationship. Implementing an interface can be seen as a complement to the single inheritance mechanism. And a class can implement multiple interfaces at the same time, that is, single inheritance, multiple implementations.

There is a problem here, which I haven’t figured out yet: Interfaces cannot have static code blocks. I understand that there can be no code blocks. After all, attributes are static final, but in the class, I can assign values to this attribute in the static code block, and the interface shows that static code blocks are not allowed to appear here. Maybe you can’t think about the interface problem from the perspective of the class, let’s leave a hole first, and hope to make it up later~

5. Internal classes

As the name implies, a class is completely nested inside another class, the nested class is called an inner class, the class that nests an inner class is called an outer class, and the class parallel to the outer class is called an outer class .

According to the location of the inner class definition, it can be divided into two categories:

1. Defined in the local location of the external class (such as in a method, code block, or constructor):

Here, it can be divided into two categories according to whether there is a class name:

1.1 Local inner class (with class name): It is still a class in essence, but the location of definition is in the local location of the outer class, and its status is a local variable, so it cannot be modified by access modifiers. For example, public class A is not allowed, but modifiers like final are fine, because final itself can be used to modify local variables. And its scope only exists in the code block in which it is defined.

1.2 Anonymous inner class (no class name): The no class name here refers to the name that we can see directly, for example, if we usually define class A, then A It is the class name that we can see. But JDK assigns names to anonymous classes at the bottom layer, but we don’t know it. There are many usage scenarios of anonymous classes. We only need to use some classes once, so we can use anonymous inner classes at this time. Its basic syntax is as follows:

//The parameter list will be passed to the constructor

new class or interface(parameter list){
    
    Class body; //If it is a new abstract class or interface, the abstract method inside must be implemented.
};//The semicolon is indispensable, after all, it is a statement to create an object.

It is equivalent to the class extends or the interface implements, and then a new instance is immediately created.

After an anonymous inner class is used once, it cannot be used again, because it has no name and we cannot find it. But the instance of the anonymous inner class that has been new can be used repeatedly.

When using, you can pass the anonymous inner class directly as an actual parameter, so that the code looks more concise and efficient.

The anonymous inner class is the same as the local inner class mentioned above. Its status is a local variable and cannot have modifiers.

Moreover, we can easily analyze that these two inner classes can directly access all members of the outer class. After all, it is an inner class, and none of the four access modifiers can restrict an inner class. To access these two inner classes, the outer class can create an object of the inner class in the method, and then call the method. If the members of the outer class and the two inner classes have the same name, the principle of proximity is followed by default. If you want to access the members of the outer class, you can access them through “external class name. this. member”, where “external class The name .this” refers to the object of the outer class that calls the method of the inner class. A bit of a mouthful, but still relatively easy to understand.

2. Defined in the member position of the external class

According to the presence or absence of static modification, it can be divided into the following two categories:

2.1 Member inner class: Its positioning is a member, so any access modifier can be added, and the scope is the entire class. Similarly, it can directly access all members of the outer class. When the outer class wants to access the members of the inner class, it also needs to create an object of the inner class in the method, and then call this method. (After all, except for attributes in a class, other statements can only be stored in the method body {})

There are two ways for external classes to call internal classes:

The first type:

class Outer{
class Inner{
        
    }
}

Outer out = new Outer();
Outer.Inner inner = out.new Inner();//The first sentence can also be omitted, directly written as new Outer().new Inner()

It is equivalent to treating new Inner() as a member of out

The second method: write a method in Outer and return an instance of Inner

class Outer{
class Inner{
        
    }
    public Inner returnInner(){
        return new Inner();
    }
}
Outer out = new Outer();
Outer.Inner inner = out.returnInner();

If the attributes of the inner class and the outer class have the same name, the principle of proximity is still followed, just like the local class mentioned above.

2.2 Static inner class

Using static modification, you can directly access all static members of the external class, but you cannot access non-static members. So if the static inner class has the same name as the member of the outer class, if you want to access the member with the same name, you can use “external class name. member” to access, because it can only access static members, so access through the class name .

There are also two ways for an external class to access a static internal class. Compared with accessing a member internal class, except for a little difference in the first method, the second method is exactly the same. Only the first method is described here.

The first type:

class Outer{
satic class Inner{
        
    }
}

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

The difference between a static inner class and a member inner class is reflected in the keyword static. In addition to limited access, a static class can be accessed directly through the class name like other static members, so in the first method and member Inner classes are a little different.

After a brief understanding of the four internal classes, let’s dig deeper into the relationship between inner classes and static members.

You can try it. In the three inner classes except the static inner class, you cannot declare any static member, but you can declare it like this in the static inner class. Why is this?

First analyze the non-static inner class:

Their status is like ordinary properties of the outer class, or local variables in the code block. For ordinary properties or local variables, they depend on the instance of the external class, that is, they will be generated only after the external class is instantiated. The same is true for non-static inner classes, that is, non-static inner classes can be loaded and even instantiated only after the outer class is instantiated.

So if there is a static member in the non-static inner class, we know that the static member is generated when the class is loaded, and its call does not need to create a specific object, it can be called directly through the class name. But Because the loading of non-static inner classes is subject to the instantiation of outer classes, we cannot call static members through non-static inner classes. Static members when the outer class is not instantiated. Therefore, there cannot be static members in non-static inner classes.

Let’s analyze why static inner classes can have static members: Static inner classes can be regarded as static members of outer classes, and static members will be loaded when the outer class is loaded, so static inner classes The loading of the class does not depend on the instantiation of the external class. At this time, it is feasible to use the static inner class. Static members, so there can be static members in the static inner class.

However, static final attributes are allowed in internal classes. This is because the compiler has optimized the bottom layer, and calls to attributes modified by static final will not cause the class to be loaded. Since the class will not be loaded, the problems we mentioned earlier will not appear, so this is allowed.

The four internal classes have been finished here~ Sahua!

In fact, for these four internal classes, as long as you grasp the following four points: 1. The essence of the internal class is still a class; 2. The internal class has different roles according to the position of the definition, which may be a local variable or a member of the class. , On the basis of grasping the role positioning of internal classes, the related problems of accessing external classes and accessing other external classes will be solved easily. 3. What static inner classes need to grasp are some “restrictions” and “privileges” of static members. 4. Anonymous inner classes seem complicated, but in fact, as long as you understand its grammar, you can understand them~

So far, we have introduced the five major members of the class, namely attributes, methods, constructors, code blocks, and inner classes.

If there is something wrong, please criticize and correct me!