03 JAVA class
When the same attributes and behaviors exist in multiple classes, these contents are extracted into a single class, so multiple classes do not need to define these attributes and behaviors, just inherit that class.
- The emergence of inheritance reduces code redundancy and improves code reusability
- The emergence of inheritance is more conducive to the expansion of functions
- The emergence of inheritance makes the relationship between classes and provides the premise of polymorphism
3.1 general
In Java, you can't do anything without classes. To use an object, you must first construct the object, specify its initial state, and then apply methods to the object.
3.1.1 general
Classes are templates or blueprints for constructing objects. The process of constructing objects from classes is called creating instances of classes.
Encapsulation is a way to combine data and behavior in one package and hide the data from the user of the object. The data in the object is called the instance domain, and the process of manipulating the data is called the method. The key to encapsulation is that the methods in the class must not directly access the instance domain of other classes, and can only call the interfaces provided by other classes.
3.1.2 relationship between classes
Dependency, aggregation (Association), inheritance, etc
-
Inheritance: is-a relation, which is used to express special and general relations. In UML terminology, the relationship describing inheritance is called generalization
-
Implementation: implement the interface implementation of classes in object-oriented programming
-
Dependency: uses-a relationship. The method of one class manipulates the object of another class, that is, one class depends on another class. In development, we should minimize the dependency between classes, that is, reduce the coupling between classes; (there is an object of another class in the method)
-
Association: indicates the relationship between two entities. There are two types of associations: composition and aggregation
- Aggregation: has-a relation, which means that an object of one class contains an object of another class (a class contains an object of another class)
- Composition: one class is part of another
Difference between combination and aggregation:
Aggregation is that one class logically contains another class, but the instance of the contained class can survive outside its context independently of the first class, that is, it can be referenced by other classes. Such as departments and employees
Composition means that when the main class no longer exists, the dependent class no longer exists. Such as house and room
relationship | UML connector | explain |
---|---|---|
Inheritance (generalization) | ![]() | The arrow points to the parent class |
Interface implementation | ![]() | The arrow points to the interface |
rely on | ![]() | The arrow points to the contained object |
relation | ![]() | The arrow points to the associated object |
polymerization | ![]() | The diamond points to the whole |
combination | ![]() | The diamond points to the whole |
3.2 succession
The existing class is called super class, base class or parent class; Newly derived classes are called subclasses and derived classes.
- If a subclass inherits the parent class, it inherits the methods and properties of the parent class
- In a subclass, you can use the methods and properties defined in the parent class, or create new data and methods
3.2.1 super() method
The subclass contains the same methods as the parent class, but the subclass cannot directly access the private domain of the parent class. It must use the public interface, such as the get * () method. At the same time, when calling, use the super keyword to call. Use super in the Java class to call the specified operation in the parent class:
- super can be used to access properties defined in the parent class
- super can be used to call member methods defined in the parent class
- super can be used to call the constructor of the parent class in the subclass constructor.
- super traceability is not limited to direct parent classes
- The usage of super is similar to this. This represents the reference of this class object, and super represents the identification of the memory space of the parent class
Super is not a reference to an object. You cannot assign super to an object variable. It is just a special keyword that instructs the compiler to call superclass methods.
3.2.2 subclass constructor
Because the subclass inherits the properties and methods of the parent class, the properties in the parent class must be initialized when initializing the subclass object. However, since the subclass cannot access the private domain of the parent class, it must call the constructor of the parent class to initialize the private domain of the parent class. You can use super to call the super class constructor. The statement that calls the constructor with super must be the first statement of the subclass constructor.
If the constructor of the subclass does not explicitly call the superclass constructor, the default parameterless constructor of the superclass will be called automatically. Therefore, for the parent class, there must be a parameterless constructor.
3.2.3 final class
A class that does not allow extension is called a final class, that is, the class cannot be inherited by other classes, and its internal methods cannot be overridden. When a class is declared final, its internal methods will automatically become final methods, but do not include the domain.
The purpose of declaring a method or class final is to ensure that they do not change semantics in subclasses.
3.2.4 abstract classes
The class itself that contains one or more abstract methods must be declared abstract.
In addition to abstract methods, abstract classes can also contain concrete data and concrete methods; At the same time, a class can be declared as an abstract class even if it does not contain abstract methods.
Abstract classes cannot be instantiated, that is, objects of abstract classes cannot be created. However, you can define an object variable of an abstract class, and the reference of the variable must be an object of a non Abstract subclass.
3.3 polymorphism
Polymorphism: when the same operation acts on different objects, it can have different interpretations and produce different execution results. This is polymorphism. Is * * using the reference of the parent class to point to the object of the child class**
Each object of a subclass is also an object of a superclass. That is, a parent object variable can reference a parent object or a child object, such as:
//From the perspective of superclass, it reflects polymorphism Parent parent = new Parent(); Parent parent = new Children(); //However, you cannot assign a superclass reference to a subclass variable //Children child = new Parent();
3.3.1 general
(1) Characteristics
Polymorphism of objects -- in Java, objects of subclasses can be used instead of objects of parent classes.
-
A variable can only have one definite data type
-
A reference type variable may point to (Reference) many different types of objects
Person p = new Student(); Object o = new Person(); //Variable o of type Object, pointing to Object of type Person o = new Student(); //Object type variable o, pointing to Student type object
-
The subclass can be regarded as a special parent class, so the reference of the parent type can point to the object of the subclass: upcasting
-
If a reference type variable is declared as the type of the parent class, but actually refers to the subclass object, the variable can no longer access the properties and methods added in the subclass
Student m = new Student(); m.school = "pku"; //Legal. The Student class has a school member variable Person e = new Student(); e.school = "pku"; //Illegal. The Person class does not have a school member variable
The attribute is determined at compile time. At compile time, e is of Person type and there is no school member variable, so there is a compilation error
(2) Virtual method call
-
Normal method call
Person e = new Person(); // The getInfo method is a common method defined in the parent class e.getInfo(); // The getInfo method in the parent class is called Student e = new Student(); e.getInfo(); // The getInfo method in the subclass is called
-
Virtual method call
In the case of polymorphism, a method with the same name and parameters as the parent class is defined in the subclass. In the case of polymorphism, the method of the parent class at this time is called a virtual method. The parent class dynamically calls the method belonging to the subclass according to the different subclass objects assigned to it. Such method calls cannot be determined at compile time.
Person e = new Student(); // The reference of the parent type points to an object of a subclass, which is determined at compile time (static binding) e.getInfo(); // The parent class calls the getInfo() method of the child class Student class, which is determined at runtime (dynamic binding)
Compile time and runtime types:
The type at compile time is the parent class, and the method call is determined at run time, so it calls a common method overridden by one of its subclasses - dynamic binding
3.3.2 overloading and rewriting
Method overloading and rewriting are ways to realize polymorphism. The difference is that the former realizes compile time polymorphism, while the latter realizes run-time polymorphism.

(1) Heavy load
Overloading occurs in a class. Methods with the same name are considered overloaded if they have different parameter lists (different parameter types, different number of parameters, or both); Overload has no special requirements for return type, only for method name and parameter list.
- The method name must be the same
- Different parameter lists [parameter type and number, independent of parameter name]
- The return type is not required, provided that the parameter list is also different
(2) Rewrite
- The overriding method of a subclass must first be consistent with the method declaration of the parent class
- The parameter list of the subclass override method should be consistent with the parameter list of the parent class. Once the parameter list of a method in a subclass changes, the method will be regarded as a member method of the subclass
- If the return type is a basic data type, the return type in the subclass must be consistent with that in the parent class; If the return type is a reference type, the data type of the subclass override method can be different from that in the parent class, and the return type in the subclass method can be set as a derived class of the parent class return type
- The access permission cannot be lower than the access permission of the overridden method in the parent class. For example, if a method of a parent class is declared public, overriding the method in a child class cannot be declared protected
- Member methods of a parent class can only be overridden by its subclasses
- A method declared final cannot be overridden
- Methods declared as static cannot be overridden, but can be declared again
- If the subclass and the parent class are in the same package, the subclass can override all methods of the parent class, except those declared as private and final
- If the subclass and the parent class are not in the same package, the subclass can only override the non final methods declared as public and protected by the parent class
- The overridden method can throw any non mandatory exception, whether or not the overridden method throws an exception. However, the overridden method cannot throw a new mandatory exception, or a wider range of mandatory exceptions than those declared by the overridden method, and vice versa
- Constructor cannot be overridden
- If you cannot inherit a class, you cannot override the methods of that class
(3) Summary
Both rewriting and overloading require method declaration and parameter list, and the return type determines whether there are requirements according to the similarities and differences of parameter list.
- Overload:
- Compilation error when the parameter list is the same
- The parameter list must be different, and the return type is not required
- rewrite:
- The parameter list must be the same. If the return type is a basic data type, it must be the same; If it is a reference data type, the return type can be different, but the return type in the subclass must be a derived class of the parent return type
- If the parameter list is different, the method will be treated as a member method of a subclass
3.4 Object class
3.4.1 general
-
The Object class is the root parent of all Java classes
-
If the extension keyword is not used in the class declaration to indicate its parent class, the default parent class is the java.lang.Object class
public class Person { ... } Equivalent to: public class Person extends Object { ... }
3.4.2 main methods
(1)toString()
The toString() method is defined in the Object class. Its return value is String type and returns the class name and its reference address.
-
The toString() method is automatically called when connecting a String with other types of data
Date now=new Date(); System.out.println("now="+now); // amount to System.out.println("now="+now.toString());
-
You can override the toString() method in user-defined types as needed. If the String class overrides the toString() method, it will return the literal value of the String. If a class does not override the toString() method by default, it will return its class name and reference address.
// The custom type Person of toString() method is not overridden, and the class name @ reference address is returned Person p5 = new Person("zoip", 888); System.out.println(p5); //com.zdp.learn.studyCollection.Person@32a1bec0 // Override the custom type Person of the toString() method to return the contents of the object Person p5 = new Person("zoip", 888); System.out.println(p5); //Person{name='zoip', age=888} // String overrides the toString() method by default s1="hello"; System.out.println(s1); //Return hello, equivalent to System.out.println(s1.toString());
-
When the basic type data is converted to String type, the toString() method of the corresponding wrapper class is called
int a=10; System.out.println("a="+a); // Array is a reference data type public void test() { char[] arr = new char[] { 'a', 'b', 'c' }; System.out.println(arr); // abc int[] arr1 = new int[] { 1, 2, 3 }; System.out.println(arr1); // [I@1d8d30f7 double[] arr2 = new double[] { 1.1, 2.2, 3.3 }; System.out.println(arr2); // [D@3e57cd70 }
(2)equals()
...
(3) Class life cycle related methods
-
getClass()
-
finalize()
(4) Thread communication related methods
- notify()
- notifyAll()
- wait()
3.5 packaging
Java is an almost pure object-oriented programming language, but basic data types are introduced for programming convenience. However, in order to operate these basic data types as objects, Java introduces the corresponding wrapper class for each basic data type. The wrapper class of int is Integer, Since Java 5, the automatic packing / unpacking mechanism has been introduced, so that they can be converted to each other.
3.5.1 object packaging
Java is an Object-oriented language, but it is not "pure Object-oriented", because the basic data type we often use is not an Object. However, in practical applications, we often need to convert basic data into objects for easy operation. For example, the operation of storing basic data types into Object [] arrays or collections, and so on.
In order to solve this problem, Java designs a corresponding class for each basic data type when designing the class. In this way, the eight classes corresponding to the basic data type are collectively referred to as wrapper class. Wrapper classes are located in the java.lang package.
These object wrapper classes are: Integer,Long,Double,Byte,Character,Void,Boolean. Object wrapper classes are final and cannot define their subclasses, that is, they cannot be inherited.
//Must be a reference type within angle brackets ArrayList<Integer> list = new ArrayList<>(); //However, since each value is wrapped in an object, the efficiency of ArrayList in this case is much lower than that of int []
3.5.2 packing and unpacking
//Automatic packing Integer total = 99; //Automatic unpacking int totalprim = total;
Boxing is to automatically convert the basic data type to the wrapper type; Unpacking is to automatically convert the wrapper type to the basic data type.
3.5.3 process analysis
Take Integer as an example:
public class Main { public static void main(String[] args) { //Automatic packing Integer total = 99; //Automatic unpacking int totalprim = total; } }
The specific internal calling process is as follows:
(1) Call function
Call valueOf() to wrap int as Integer
- Integer total = 99;
When executing the above code, the system executes for us: Integer total = Integer.valueOf(99);
Call intValue() to unpack Integer to int
- int totalprim = total;
When executing the above code, the system executes for us: int totalprim = total.intValue();
(2) valueOf() function
Cache: a total of 256 [- 128127] are pre stored in the wrapper to prevent multiple creation:
public static Integer valueOf(int i) { //First determine the size of i: //If i is less than - 128 or greater than or equal to 128, an Integer object is created (using the constructor) //Otherwise, execute SMALL_VALUES[i + 128] if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
(3) Integer() constructor
private final int value; public Integer(int value) { this.value = value; } public Integer(String string) throws NumberFormatException { this(parseInt(string)); }
If you define a value variable and create an Integer object, you will initialize this variable. The second passed in is a String variable, which will first convert it to an int value and then initialize it.
(4)SMALL_VALUES[]
private static final Integer[] SMALL_VALUES = new Integer[256];
It is a static Integer array object and has been created with a capacity of 256.
Cache problem of wrapper class:
For integers, there are only 256 fixed values between [- 128128). Therefore, in order to avoid creating objects many times, we have created an integer array SMALL_VALUES [] with a size of 256 in advance. Therefore, if the value is within this range, we can directly return the integer object we have created in advance.
(5) Cache pool
The difference between new Integer(123) and Integer.valueOf(123) is:
- new Integer(123) creates a new object each time;
- Integer.valueOf(123) will use the objects in the cache pool, and multiple calls will get the reference of the same object.
Integer x = new Integer(123); Integer y = new Integer(123); // Objects do equality operations and compare addresses System.out.println(x == y); // false Integer z = Integer.valueOf(123); Integer k = Integer.valueOf(123); System.out.println(z == k); // true
The implementation of valueOf() method is relatively simple, that is, first judge whether the value is in the cache pool, and if so, directly return the contents of the cache pool.
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
In Java 8, the size of Integer cache pool is - 128 ~ 127 by default.
static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; }
The compiler calls the valueOf() method during the auto boxing process, so if multiple Integer instances with the same value and within the cache pool are created using auto boxing, the same object will be referenced.
Integer m = 123; Integer n = 123; System.out.println(m == n); // true
The buffer pool corresponding to the basic type is as follows:
- Boolean values true and false
- all byte values
- short values between -128 and 127
- int values between -128 and 127
- char in the range \u0000 to \u007F
When using the wrapper type corresponding to these basic types, if the value range is within the buffer pool range, you can directly use the objects in the buffer pool.
Among all the value class buffer pools in jdk 1.8, Integer buffer pool IntegerCache is very special. The lower bound of this buffer pool is - 128 and the upper bound is 127 by default. However, this upper bound is adjustable. When starting the JVM, specify the size of this buffer pool through - XX: autoboxcachemax = < size >. This option will set a buffer pool named java.lang.int during JVM initialization Gercache.high system attribute, and then the system attribute will be read during IntegerCache initialization to determine the upper bound.
(6) Overview
In the constructor of Integer, it can be divided into two cases:
- I > = 128 | I < - 128 = > new integer (I): after each execution, even the number of the same value points to different objects
- I < 128 & & I > = - 128 = > small_values [i + 128] (array subscript is 0-255): after each execution, the number of the same value points to the same object
public class Main { public static void main(String[] args) { Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200; System.out.println(i1==i2); //true System.out.println(i3==i4); //false } } /* i1 And i2 will be automatically boxed and the valueOf function is executed. Their values are in the range (- 128128). They will get the same object SMALL_VALUES[228] in the SMALL_VALUES array. They refer to the same Integer object, so they must be equal. */ /* i3 And i4 will also be automatically boxed and execute the valueOf function. Their value is greater than 128, so they will execute new Integer(200), that is, they will create two different objects respectively, so they must be different. */
However, for floating-point numbers, the result is different every time. Because the number of floating-point numbers in this range is infinite, the operation of floating-point numbers is very direct:
//Each time, a new Double object is created public static Double valueOf(double d) { return new Double(d); }
- Integer faction: the implementation of valueOf methods of integer, Short, Byte, Character and Long is similar.
- Double faction: the implementation of the valueOf methods of double and Float is similar. Different objects are returned each time.