The Ribbon source code for class XX is package private. The answer is that class XX is not package private, but is a protected static inner class, so overrides will not fail.

As for the function of Java access control modifiers, I also remember them when I first learned Java, so I can understand them after writing more code, but I am curious about the underlying implementation, so I also try to find the answer from HotSpot VIRTUAL machine source code, to answer my doubts for many years.

What access control modifiers do classes, fields, and methods have?

Private , subclass accessible , public public, package private , default without access control modifier is package private.

Scope of access private package protected public
The same class Can be accessed Can be accessed Can be accessed Can be accessed
Other classes in the same package inaccessible Can be accessed Can be accessed Can be accessed
Subclasses in different packages inaccessible inaccessible Can be accessed Can be accessed
Non-subclasses in different packages inaccessible inaccessible inaccessible Can be accessed

Package private means that only classes in the same package are accessible, and classes in other packages are not.

Today we delve into the Java Virtual Machine to explore the implementation of these access control decorator semantics.

InstanceKlass is the data structure corresponding to the class file structure in HotSpot VM. The InstanceKlass object is a C++ object generated after the Java class is loaded by HotSpot VM and stored in the method area. The Class object we use in our Java code is actually a mirror of InstanceKlass.

Java supports calling a method with “this.”, “suppor.”, “some object.”, or” some class.” Calling a static method, which we think of as calling a static method of a class or a method of an object, is no different in a virtual machine; it’s all a method call.

Calling a static method differs from an object method only in that the method calling an object requires passing a “this” reference to the method parameter, which is an implicit parameter added automatically when the compiler compiles Java code into bytecode.

The difference between Java code using “this.” and “suppor.” to call its own method and its parent method is only the Methodref constant pointed to by the operand of the bytecode instruction that generates the method call. The first implicit argument to the method is passed the same object. Methodref constant refers to a symbolic reference to a method, including the class name, method name, and method descriptor.

As we know, the class loading process includes three stages: loading, linking, and initialization. The linking stage can be subdivided into three stages: verification, preparation, and parsing. The following diagram is helpful but not accurate in understanding several stages of class loading.

The Java Virtual Machine Specification only specifies what needs to be done for class loading, and there is no strict order.

The following figure is a flow chart from my reading of the HotSpot VIRTUAL machine class loading source code for your reference only.

In the HotSpot VIRTUAL machine, the preparation phase of the link phase is completed after the load phase, and the validation of the link phase is also divided into various validations, of which file format validation and metadata validation are crossed during the load phase, bytecode validation is triggered before the class initialization, and parsing phase is triggered after the class initialization.

Several commands cause class initialization, such as new, getStatic, putstatic, invokestatic. When executing these commands, the VIRTUAL machine determines whether the class has been initialized. If the class has not been initialized, the initialization of the class is completed.

The parsing phase of the linking phase is the process in which the Java Virtual machine replaces symbolic references in the constant pool with direct references. According to the Java Virtual Machine Specification, In ane-warray, checkcast, getField, getStatic, Instanceof, InvokeDynamic, InvokeInterface, invoke-Special, InvokeStatic, Invokevirt Ual, LDC, MuLIANewarray, new, putField, putStatic these require operands to refer to symbolic reference constants in the constant pool (e.g. The CONSTANT_Class_info, CONSTANT_Field_info, CONSTANT_Methodref_info) instructions must be resolved before being executed.

Symbolic references describe the target of a reference as a set of symbols, such as CONSTANT_Class_info for the referenced class, CONSTANT_Field_info for which field of which class, and CONSTANT_Methodref_info for which method of which class.

Symbolic reference validation occurs in the parsing phase and includes: Whether the corresponding class can be found by fully qualified names described by strings, whether methods and fields described by simple names exist in the specified class, accessibility of classes, fields, methods in symbolic references ( , , public, ).

In the implementation of the HotSpot VIRTUAL machine, for interpret execution and Dynamic invocation, the parsing phase is resolved before the symbolic reference is to be used.

Method call source: javaCalls. CPP; Linkresolver.cpp;

Check class, method, field accessibility corresponding source code:

LinkResolver::check_klass_accessability // Check methods LinkResolver::check_method_accessability // check fields LinkResolver::check_field_accessabilityCopy the code

Each of these method calls ends up calling the Reflection class’s corresponding verify method to determine whether it is accessible, such as the Reflection::verify_field_access method.

The Java virtual machine also validates access control modifiers during class file structure parsing and during bytecode validation.

For example, when parsing a class file structure, verify that you can inherit from a parent class (Reflection::verify_class_access) :

Class access modifiers determine whether a class can be accessed by other classes. In the parsing class file structure phase, the virtual machine can verify that the current class can inherit from its parent (determined by the parent’s access control modifier) and that it can implement each interface (determined by the interface’s access modifier).

The bytecode validation phase verifies that the current class can access protected methods or fields of the target class:

In the bytecode validation phase, each bytecode instruction in each method of the class is validated by the virtual machine, but only the getField instruction is check_protected during the bytecode validation phase. It can be seen that there is not much access control verification in the bytecode verification phase.

The author level is limited, if this article has the expression wrong place, still hope the reader corrects.