Abstract process

Assembly languages are a slight abstraction of the underlying machine. Imperative languages are vastly improved on assembly languages, but the main abstractions they make still require that problems be solved based on the structure of the computer rather than the structure of the problem to be solved.

OOP allows problems to be described in terms of the problem, rather than the computer on which the solution is running, but it still has a connection to the computer: each object looks a bit like a microcomputer — it has state, and it also has operations that users can ask the object to perform.

Concept and classification of objects

Everything is an object, and programs are collections of objects that tell each other what to do by sending messages.

Objects that have different states but are otherwise similar during program execution are grouped into their classes. This is where the keyword class comes from. The members or elements of each class have some commonality, and each member has its own state.

Objects provide services through interfaces

One of the challenges of object-oriented programming is to create one-to-one mappings between elements of the problem space and objects of the space. Each object can only fulfill certain requests defined by its interface. It is the type that determines the structure (the interface here is a generic abstraction, not a programming element). The interface defines the requests that can be made to a particular object.

When trying to develop or understand a program’s design, one of the best ways to do this is to think of an object as a service provider. The program itself will provide services to users, and it will do so by calling services provided by other objects.

Access control

The first reason access control exists is that client-side programmers (or library consumers) can’t touch parts of the data they shouldn’t — parts that are necessary for internal manipulation of data types, but not part of the interface that users need to solve a particular problem. The second reason is to allow library designers to change the way the classes work internally without worrying about affecting the client programmer (that is, achieving decoupling).

Polymerization of reuse

The most simple way to reuse a class is directly using the class of an object, in addition to the class of an object is put in a new class, we call it the members to create a new object, new classes can be any number, any type of other objects in any possible new class to the function of the way. Combinations are often seen as HAS-A relationships.

When creating a new class, consider composition first because it is simpler and more flexible. If you do this, the design becomes clearer and once you have some experience, you will be able to see where inheritance is necessary.

inheritance

Types describe not only the constraints that apply to a collection of objects, but also relationships with other types. Two types can have the same properties and behaviors, but one type may have more properties than the other.

There are two ways to make a difference between a base class and an exported class. The first way is to directly add a new method to the exported class. The relationship between the base class and the exported class is called IS-like -A, and the base class cannot access the newly added method. The second type: overwrite, directly create a new definition of the method in the exported class, the relationship between the base class and the exported class is called IS-A.

polymorphism

When dealing with type hierarchies, it is often tempting to treat an object not as the property type it belongs to, but as an object of its base class, which allows one to write code independent of a particular type.

By trying to treat an object of exported type as an object of its generalized base type, it is impossible for the compiler to know which code to execute at compile time. A function call produced by a compiler that is not object-oriented programming causes what is called pre-binding, where the compiler produces a call to a specific function name that the runtime resolves to the absolute address of the code to be executed.

To solve this problem, object-oriented programming languages use the concept of late binding. When a message is sent to an object, the code being called is not determined until runtime. The compiler ensures the existence of the called method and performs type checks on the call parameters and return values (languages that do not provide such guarantees are called weakly typed), but does not know the exact code being executed.

To perform late binding, Java replaces absolute address calls with a little special code that uses the information stored in the object to calculate the address of the method body. Dynamic binding is the default behavior in Java, and no additional keywords need to be added to achieve polymorphism.

void doSomething(Shape shape) {
    shape.erase();
}

Circle circle = new Circle();
doSomething(circle);

Line line = new Line();
doSomething(line);
Copy the code

The process of treating the derived class as its base class is called upward transformation.

All objects in a single-root inheritance structure have a common interface, so they all come down to the same basic type. Another construct (provided by C++) is that there is no guarantee that all objects are of the same type. The former makes it much easier to implement garbage collection periods without getting bogged down by the inability to determine the type of objects, and is especially important for system-level operations such as exception handling.

The generic

Objects stored in containers prior to Java SE 5 could only be Objects. The original identity information was lost when the Object was turned up when the element was put in, and the original identity information needed to be turned down when the element was taken out. This step was dangerous, and a wrong turn could throw a runtime exception.

By creating a container that knows the type of the object it is holding, it does not need to be cast down and it eliminates the possibility of making mistakes. This solution is called the parameterized type mechanism, where the compiler can automatically customize classes that operate on a particular type.

Object storage and reclamation

In C++ for maximum execution speed, the storage space and life cycle of objects can be determined at program writing. This can be achieved by placing objects on the stack or in static storage, so that the exact number, life cycle, and type of objects must be known at program writing.

Java uses dynamic memory allocation, where objects are created dynamically in a pool of memory called a heap, not knowing how many objects are needed, what their life cycle is, and what their specific types are until run time. Creating and releasing storage space on the stack requires a single assembly instruction (stack pointer move), and the time to create heap storage space depends on the implementation of the storage mechanism. Java provides a garbage collector that automatically detects when an object is no longer in use and destroys it.