Chapter 1 Objective Getting Started "Why is object-oriented programming cause so shocked impact on software development?" Object-oriented programming (OOP) has many appeals. For managers, it achieves faster and cheaper development and maintenance processes. For analysis and designers, modeling processing becomes simpler, can generate clear and easy maintenance design. For programmers, the object model is so elegant and shallow. In addition, the huge power for object-oriented tools and the library makes programming become a more pleasant task. Everyone can benefit from it, at least the surface. If it has a shortcomings, it is to master it needs to pay. When thinking about the object, you need to use image thinking, not programmed thinking. Compared with programming design, the object's design process is more challenging - especially when attempting to create reusable (renewable) objects. In the past, those who initially targeted object-oriented programming must conduct a painful choice: (1) Select a language such as SmallTalk, and must master a giant library before "outper". (2) Choose C (annotation 1) that does not have the library, then learn from this language until you can write it yourself. 1: Fortunately, this situation has changed significantly. There is now a third-party library and the standard C library for use. In fact, it is difficult to design an object - it is difficult to design anything. Therefore, only the number of "experts" can design the best object and then let others enjoy. For successful OOP languages, they not only integrate this language syntax and a compiler (compiler), and there is a successful development environment, which contains excellent design, easy to use. Therefore, most programmers's primary tasks are to solve their application problems with existing objects. The goal of this chapter is to reveal the concept of the programming of objects to everyone and prove how simple it is. This chapter will explain the number of Java's multi-design ideas and interpreted object-oriented programming. However, pay attention to the reading of this chapter after reading this chapter, you cannot immediately write a full-featured Java program. All detailed descriptions and examples will slowly walk in other chapters of this book. 1.1 Abstract progress All programming language is to provide an "abstract" approach. A more controversial statement is: solving the complexity of the problem directly depends on the type and quality of the abstraction. What kind of "species" here refers to what is "abstracted"? The assembly language is a small amount of abstraction to the basic machine. Later, many "command" languages (such as Fortran, Basic and C) are an abstraction of assembly language. These languages have made great progress than assembly language, but their abstract principles still require us to consider the structure of the computer, not the structure of the problem itself. The programmer must establish a connection between the machine model (located in the "Scenarius") and the actual solution (located in "problem space"). This process requires people to pay greater energy, and since it leaves the scope of the programming language itself, it is difficult to write, and it takes a large cost to maintain maintenance. The side effect caused by this is a perfect "programming method" discipline. Another way to model the machine is to make a model for problem solving. For some early language, such as LISP and APL, their approach is "Observe the world from different angles" - "All issues are summarized as a list" or "all issues are summarized as algorithms." ProLog summarizes all issues as a decision chain. For these languages, we believe that part of them is facing "mandatory" programming, and the other is designed for processing graphic symbols. Each method has its own special purpose, suitable for solving a problem. But as long as it exceeds the scope of their strength, it will be very awkward. Object-oriented programming On this basis, the programmer can use some tools to express the elements in the problem space.
Because this expression is very common, it is not necessary to limit the problem of specific types. We use the elements in the problem space and their representations in the program space (Object). Of course, there are some other objects that have no corresponding body in the problem space. By adding new object types, the program can make flexible adjustments to cooperate with specific issues. Therefore, when the code of the reading scheme is read, the discourse to the problem is read. Compared with our previous opinions, this is undoubtedly a more flexible, more powerful language abstract method. In summary, OOP allows us to describe problems based on the problem, not based on the solution. However, there is still a connection to the computer. Each object is similar to a small computer; they have their own state and can require them to perform specific operations. Compared with the "object" or "object" of the real world, the programming "object" is also commonplace: they all have their own characteristics and behavior. Alan Kay summarizes the five basic features of SmallTalk. This is the first successful object-oriented programming language and the basics of Java. Through these features, we understand what is the "pure" object-oriented programming method:
(1) Everything is an object. Objects can be imagined into a new variable; it saves data, but it can be required to operate itself. In theory, all conceptual components can be proposed from issues to be resolved, and then express them into an object in the program. (2) The program is a combination of a large number of objects; through message delivery, each object knows what you should do. In order to issue a request to an object, you need to "send a message" to that object. More specifically, you can imagine the message as a call request, which calls a subroutine or function from the target object. (3) Each object has its own storage space, which can accommodate other objects. Or, by encapsulating existing objects, new objects can be produced. So, although the concept of object is very simple, it can reach any high complexity in the program. (4) Each object has a type. Depending on the syntax, each object is a "instance" of a "class". Among them, "class" is a synonym of "type" (Type). A class is the most important feature is "what message can I send it?". (5) All objects can receive the same message. This is actually a saying that there is something else, you can understand soon. Since an object of the type "circle" is also an object of the type "Shape" (Shape), a circle can fully receive shape messages. This means that the program code will command "shape" to automatically control all objects that meet the "shape", which naturally include "circle". This feature is called "replaceability" of the object, one of the most important concepts of OOP. Some language designers think that object-oriented programming itself is not enough to facilitate all forms of program problems, advocating different methods into "multi-shaped programming language" (annotation 2). 2: See "Multiparadigm Programming in LEDA" edited by Timothy Budd, Addison-Wesley published in 1995. 1.2 Interface of the object Aristotle may be the first person to carefully study the concept of "Type", and he once talked about "fish and birds". In the world's first object-oriented SIMULA-67, the first time I use this concept: all objects - although each characteristic-part is part of a series of objects, these objects have general features and behavior. In SIMULA-67, the keyword for Class first uses, introduced a new type for the program (CLAS and TYPE usually interchangeable; annotation 3). 3: Some people have further distinguished, they emphasize that "type" determines the interface, and "class" is a special implementation of the interface. SIMULA is a good example. As this name is implicit, its role is "Simulate" like "bank out" such a classic problem. In this example, we have a series of people, customers, accounts, and transactions. Each type of member (element) has some universal characteristics: each account has a certain balance; each of the wigs can receive the deposit of the customer; At the same time, each member has its own state; each account has different balances; each with a name. So in a computer program, you can use a unique entity to indicate the NA, customer, account, and transaction, respectively. This entity is "object", and each object is affiliated with a specific "class", which has its own general feature and behavior. Therefore, in the object-oriented programming, although we really want to do a new various data "type" (Type), almost all object-oriented programming languages use "Class" keywords.
When you see the word "Type", please think "Class" at the same time; vice versa. After building a class, many objects can be generated according to the situation. Subsequently, those objects can be processed as elements to solve problems. In fact, when we perform an object-oriented program design, the biggest challenge is: How to "problem space" in "problem space" (where problems actually exist) Establish an ideal "one-to-one" corresponding or mapping relationship between the elements of the computer. How do I use the object to complete the truly useful job? There must be a way to make a request to the object, making it some practical things, such as completing a transaction, draw something on the screen or open a switch, etc. Each object can only accept a specific request. Our request to objects is in its interface form by "interface" defined by its "interface" (type "or class, or class". The equivalence or correspondence of "Type" and "Interface" is the basis for object-oriented programming. Let us take a light bulb as an example: Light LT = New Light (); lt.on (); In this example, the name of the type / class is light, and the request to the Light object includes open (ON), close (OFF), becoming brighten or darker (DIM). By simply declaring a name (LT), we created a "handle" for the Light object. Then create an object with the NEW keyword to the Light. Use the equal sign to assign it to the handle. In order to send a message to the object, we list the handle name (LT), and then connect it with a message name (ON) with a period symbol (.). It can be seen from it. When using some predefined classes, our code we use is very simple and intuitive. 1.3 Realization of the hidden discussion of the future, let us first classify the practitioners in this area. Fundamentally, there are two people who are involved in object-oriented programming: "Create a new data type person) and" customer programmer "(in its own application); Note 4). For client programmers, the most important goal is to collect a programming "toolbox" full of various classes to quickly develop applications that meet yourself. For class creators, their goal is to build a class from the head, and only all the options (interfaces) open to the customer programmer, all other details are hidden. Why do you do this? After hidden, the customer programmer can not contact and change those details, so the original person does not have to worry about illegal modification, ensuring that they will not affect others. 4: Thanks to my friend Scott Meyers, he helped me got this name. "Interface" specifies which requests can be issued to a particular object. However, some code must be present in some place to meet these requests. These codes are called "hidden implementations" with those hidden data. Standing at the perspective of procedural programming, the entire problem is not complicated. One type contains functions associated with each possible request. Once a specific request is sent to an object, that function is called. We usually summarize this process to "send a message" to the object (propose a request).
The responsibility of the object is to determine how to respond to this message (perform the corresponding code). For any relationship, it is important to make all members who are involved in the same rules. When you create a library, it is equivalent to establishing a relationship with the customer programmer. The other party is also a programmer, but their goal is to combine a specific application (program), or build a larger library with your library. If anyone can use all the members of a class, then the customer programmer can do anything about that class, there is no way to force them to comply with any constraints. Even if you are very reluctant to use some members you contained in the class, if you don't have access control, there is no way to stop this situation - all things will expose.
There are two reasons to control our access to members. The first reason is to prevent programmers from touching things they should not be in touch - usually the design idea of internal data types. If only to solve a specific problem, users only need to operate the interface, do not need to understand this. We are actually a service to users because they can easily see which are very important to themselves, and which can be ignored. The second reason for access control is to allow library designers to modify internal structures, do not worry about what impact on customer programmers. For example, we have started a simple class that can be designed to simplify development. In the future, it will decide to rewrite so far. If the interface and implementation methods have already been separated, they can be assured to do this, and they can be re-linked to it. Java uses three explicit (clarified) keywords and an implicit (hint) keyword to set class boundaries: public, private, protected, and hintted Friendly. If other keywords are not explicitly specified, the latter is silently. The use and meaning of these keywords is quite intuitive, and they determine who can use subsequent definitions. "Public" means that the subsequent definition can be used. On the other hand, "private" means that anyone else can access subsequent definition information in addition to your own, type of creator and the type of internal function member. Private is a wall with a wall between your programmers. If someone tries to access private members, it will get a compile period error. "Friendly" involves the concept of "packaging" or "package" - JAVA is used to build a library. If something is "friendly", it means that it can only be used within this packaging (so this access level is sometimes called "packaging access"). "Protected" is similar to "private", just a inherited class to access protected members, but cannot access private members. The inherited problem will soon be talked. 1.4 Reuse of the program creates and tests a class, it should (from the ideal angle) represent a useful code unit. However, it is not like many people hope, this reuse ability is not easy to implement; it requires more experience and insight, so that a good program can be designed to use it. Many people think that the code or design is reused is the greatest lever for object-oriented programming. To reuse a class, the easiest way is to use only the object of that class directly. But it can also place an object of that class into a new class. We call this called "Create a member of the object." New categories can be constructed from other objects of any quantity and type. In any case, as long as the new category has reached the design requirements. This concept is called "Organization" - organizes a new class on the basis of existing classes. Sometimes, we also tested "including" relationships, such as "a car contains a gearbox." The organization of the subject has great flexibility. The new class "Member Object" is usually set to "private" (private "(private", using this class customer programmer cannot access them. In this way, we can modify those members without interfering with the customer code. You can also change members in the "running period", which further increases flexibility. The "inheritance" to be told later does not have this flexibility because the compiler must limit the class created by inheritance. Due to the importance of inheritance, it is often emphasized in the object-oriented programming. As a newly joined programmer, perhaps, "Inheritance should be seen everywhere." The design that is generated along this idea will be very awkward and will greatly increase the complexity of the program.
On the contrary, when new categories, the "Organization" object should be considered; so it is more simple and flexible. With the organization of the object, our design can be kept refreshing. Once you need to use inheritance, you will be able to realize this. 1.5 Inheritance: Re-use the interface, the concept of objects can bring us great convenience. It is conceptually allowed to package a wide range of data and features together. This will properly express the concept of "problem space" without deliberately follow the expression of the base machine. In programming languages, these concepts are reflected to specific data types (using Class Keywords). After we spend his heart, then after making a data type, if you have to create a type, it will make it roughly the same function, which will be a very discouraged thing. However, if you can use the ready-made data type, it is "clone", and then add and modify according to the situation, the situation is much more ideal. "Inherited" is designed for this goal. But inherit is not completely equivalent to cloning. During the inheritance process, if the original class (the official name is called the basic class, superclass or parent class), the modified "clone" class (official name is called inheritance or subclass) will also reflect this Variety. In Java language, inheritance is equivalent to creating a new class when the use inheritance implemented by an Extends keyword. This new category not only contains all the existing types of members (although the Private member is hidden and cannot be accessed), but more importantly, it copies the basic class interface. That is, all messages that can be transmitted to the base class can also be sent to the object of the derived class. According to the message you can send, we can know the type of class. This means that the derived class has the same type as the base class! In order to truly understand the meaning of the design of the target program, we must first recognize the equivalent relationship of this type. So the interface must be specially designed due to the identical interface of the base class and derivative classes. That is, after the object receives a specific message, there must be a "method" to be executed. If it simply inherits a class, do not do anything else, the method from the basic class interface will be moved directly to the derived class. This means that the object of derivatives not only has the same type, but also the same behavior, this consequence is usually we don't want to see. There are two ways to divide new derivatives to distinguish between the original basic class. The first practice is very simple: add new functions (functions) for derivative classes. These new functions are not part of the base interface. When making this treatment, it is generally realized that the basic class cannot meet our requirements, so more functions need to be added. This is the simplest, most basic inheritance usage, most of which can perfectly solve our problems perfect. However, in advance, you should carefully investigate whether these extra functions are really required. 1.5.1 Improve the basic class Although the Extends keyword suggests that we have to "expand" new features for the interface, the truth is not certain. To distinguish our new class, the second method is to change the behavior of an existing function of the base class. We call it "improvement" function. To improve a function, just create a new definition for the function of the derived class. Our goal is: "Although the function interface used is not changed, its new version has different performances." 1.5.2 Isometric and similar relationships The inheritance may produce such an argument: Can the inheritance can only improve the original basic function? If the answer is yes, the derivative type is identical to the basic class, because all have exactly the same interface. The result of this is: We can completely replace an object of the derived class into a basic class! It can be imagined into a "pure replacement". In a sense, this is an ideal way for inheritance. At this point, we usually believe that there is a "equivalent" relationship between the basic and derivatives - because we can talk to straight: "Circle is a geometric shape."
In order to test inheritance, one means to see if he can set them into this "equivalent" relationship to see if it makes sense. But in many times, we must add new interface elements for derivative types. So not only expand the interface, but also created a new type. This new type can still replace into a basic type, but this replace is not perfect because it is not accessible to the basic class. We call it "similar" relationship; new types have old types of interfaces, but also contain other functions, so they can't say that they are completely equivalent. For example, let's consider the situation of the refrigerator. Assuming our room has a variety of controllers for refrigeration; that is, we have necessary "interface" to control the cooling. Now suppose the machine has failed, we change it into a new type of cold, hot dual-use air conditioner, winter and summer can be used. Cold, hot air conditioners "similar" refrigerator, but you can do more things. Since our room is only installed with a refrigerated device, they are limited to the refrigeration part of the new machine. The interface of the new machine has been expanded, but the existing system does not know anything other than the original interface. When you understand the differences and similar differences, you will have much more. Although most of the "pure replacement" is enough, you will find that in some cases, there is still a significant reason to add new features on the basis of derivatives. By discussing the previous two cases, I believe that everyone has had a number of people. 1.6 Interchange of multi-shaped objects Usually, inherits will eventually create a series of classes, all classes are based on unified interface. We use an upside down tree map to clarify this (Note 5): 5: This uses "unified mark", this book will mainly use this method. An important process we want to do with such a series of classes is to treat a derived object as an object of the basic class. This is very important because it means we only need to write a single code, to ignore the specific details of the type, only deal with the base class. In this way, those code can be separated from the type information. So it is more easier to write, it is also more easy to understand. In addition, if a new type is added by inheritance, such as "triangle", then our code written for the "geometric shape" will work as good as in the old type. Therefore, the program has "extended ability" and has "scalability". Based on the example above, suppose we write such a function with Java: void dostuff (shape s) {
S.RASE ();
// ...
s.draw ();
}
This function can communicate with any "geometric shape", so it is completely independent of it to depict (DRAW) and delete any particular type of object. If we use the dostuff () function in other programs:
Circle C = New circle ();
Triangle T = New Triangle ();
Line L = new line ();
Dostuff (c);
Dostuff (t);
Dostuff (L);
Then the call to dostuff () will automatically work well, regardless of the specific type of object.
This is actually a very useful programming skill. Consider the following line of code:
Dostuff (c);
At this point, a CIRCLE handle is passed to a function that is expected to look forward to the Shape handle. Since the circle is a geometric shape, dostuff () can be processed correctly. That is, any dostuff () can be sent to a shape message, Circle can also receive. So doing this is safe and will not cause errors.
We use this process of derivating the derivative as the basic type of the basic type of "UPCASTING". Among them, "CAST" means creating according to an outgoing model; and "UP" (up) indicates that the direction of inheritance is from "above" - that is, the base class is on top, and the derived class is expanded below. Therefore, according to the base class is a process from above, that is, "Upcasting". In object-oriented programs, top-up techniques are usually used. This is a good way to avoid investigating accurate types. Take a look at the code in dostuff ():
S.RASE ();
// ...
s.draw ();
Note that it doesn't express this: "If you are a circle, you do this; if you are a Square, you do it; etc.". If you write a code, you need to check all possible types, such as circular, rectangular, and more. This is obviously very troublesome, and each time a new Shape type is added, it must be modified accordingly. Here, we only need to say: "You are a geometric shape, I know you can delete yourself, ie ERASE (); please take that action, and to control all the details."
1.6.1 Dynamic Binding
In the code of dostuff (), most surprisingly, although we did not make any special instructions, the operation taken is completely correct and appropriate. We know that the code executed when calling DRAW () for the Circle Different when calling DRAW () for a Square or Line Draw (). However, when the Draw () message is sent to an anonymous Shape, the correct operation is taken according to the actual type of connection at the time of the Shape handle. This is of course surprising, because when the Java compiler is compiled for dostuff (), it doesn't know what is the exact type you have to operate. Although we do can guarantee that ERASE () will eventually call your exiled (), call Draw (), but does not guarantee what is specific Circle, Square or Line call what is. However, the last operation taken is equally correct, how did this do it?
When a message is sent to an object, if it doesn't know what the specific type of the other party is, the action taken is the same, which is called "Polymorphism). For the programming language of the object-oriented object, they are called "dynamic binding" methods for achieving polymorphism. The compiler and the runtime system will be responsible for the control of all details; we only need to know what will happen, and more importantly, how to use it to help you design the program.
Some languages require us to use a special keyword to allow dynamic binding. In C , this keyword is Virtual. In Java, we don't have to remember to add a keyword because the dynamic binding of the function is automatically made. So when you send a message to the object, we can affirm the object at all, even though it involves processing such as winding.
1.6.2 Abstract basic and interface
When designing programs, we often want the basic class to provide an interface for our derivative class. That is, we don't want anyone else to actually create an object of the basic class, just shape it into it in order to use their interfaces. To achieve this, you need to turn that class into "abstraction" - use the Abstract keyword. If someone tries to create an object of an abstract class, the compiler will block them. This tool can effectively enforce a special design.
It is also possible to describe a method that has not been implemented - as a "root", pointing out: "This is an interface function for all types of interfaces that inherited from this class, but there is currently no form of implementation. "Abstract method may only be created in an abstract class. After inheriting a class, that method must be implemented, otherwise the inherited class will also become an "abstract" class. By creating an abstract method, we can place a method into an interface without having to provide the possible body code for that method. The Interface keyword extends the concept of abstract classes more step, it is completely disabled all of the function definitions. "Interface" is a quite effective and common tool. In addition, if you are willing, you can also merge multiple interfaces together (you cannot inherit from multiple ordinary Class or Abstract Class).
1.7 Object creation and existence time
From a technical point of view, OOP (object-oriented programming) is only involved in abstract data types, inheritance, and versatility, but others may be very important. This section will discuss these issues.
One of the most important issues is the creation and destruction of objects. Where is the data required by the object, how to control the "existing time" of the object? In response to this problem, the solution solution is everything. C believes that the execution efficiency of the program is one of the most important issues, so it allows programmers to make a selection. To get the fastest running speed, storage, and existence time can be determined when writing a program, simply placing the object in the stack (sometimes called an automatic or domain variable) or the static storage area. This provides a priority for allocation and release of storage space. In some cases, this priority control is very valuable. However, we also sacrificed flexibility because when writing programs, you must know the accurate quantity of objects, time, and types. If you want to solve a more conventional problem, such as computer-aided design, storage management, or air traffic control, this method is too limited.
The second method is to dynamically create an object in a memory pool, which is also called "heap" or "memory". If this is used, unless you enter the running period, you don't know how many objects needed at all, nor do you know how long they have time, and what is the exact type. These parameters are determined when the program is officially run. To need a new object, just simply create it in the memory pile when you need it. Since the management of storage space is dynamically performed during operation, the time to allocate storage space in memory is much longer than in the stack (create a storage space in the stack, only a simple instruction is required, and the stack pointer will be required. Move down or down). Since the dynamic creation method makes the object it will tend to be complex, find the stored space and the additional overhead they need will not have a significant impact on the creation of the object. In addition, greater flexibility is critical to conventional programming problems.
C allows us to decide whether to create an object when writing a program, or is created during operation, which is more flexible. Everyone may think that since it is so flexible, you should create an object in memory in memory, not in the stack. However, it is also necessary to consider another problem, that is, the "existing time" or "Lifetime" of the object. If an object is created in the stack or static storage space, the compiler will determine how long the duration of the object is automatically "destroyed" or "clear" it. Programmers can use two ways to destroy an object: use programmatic ways to decide when to destroy objects, or use a "garbage collector" feature provided by the operating environment to automatically find objects that are no longer used, and will Clear. Of course, the garbage collector is much convenient, but all applications must tolerate the existence of garbage collectors and can pass the additional overhead brought by garbage collection. But this does not meet the design tenet of C language, so it is not included in C . However, Java did provide a garbage collector (SmallTalk has such a design; although Delphi defaults to no garbage collector, you can choose to install; while C can also use some garbage collection products developed by other companies). The remaining parts of this section will discuss additional factors to consider when manipulating objects.
1.7.1 Collection and Inheritors
For a specific problem solving, if you don't know how many objects needed in advance, or how long your duration is, you don't know how to save those objects. In this case, how can I know how many spaces? I can't know in advance, unless you enter the running period.
In object-oriented design, the solution to most problems seems to be a little probability - just simply creates another type of object. Novel objects for solving a particular problem accommodate handle to other objects. Of course, you can also use the array to do the same thing, that is a function of most languages. But you can't just see this. This new object is typically called "collection" (also called a "container", but AWT applies this term in different occasions, so this book will always use the "collection" name. When needed, the collection will automatically Expand yourself in order to adapt to anything we are in place. So we don't have to know how much things are going to have a collection in advance. Just create a collection, the future work makes it accountable.
Fortunately, design excellent OOP language supports a collection of collections. In C , they are provided in the form of "Standard Template" (STL). Object Pascal provides a collection with its own "visual component library" (VCL). SmallTalk offers a very complete collection. Java also provides a collection with its own standard library. In some libraries, a regular collection can meet most of the requirements; in other libraries (especially C libraries), different types of collection are provided for different needs. For example, you can use a vector unified access to all elements; a link list is used to ensure that all elements are unified. So we can choose the appropriate type according to your needs. These include sets, queues, hash tables, trees, stacks, and more.
All collections provide corresponding read and write functions. The way to use something in the collection, the way is very obvious. There is a function called "Push" (Push), "Add" (add) or other similar names for this. However, when the data is removed from the collection, the way is not always so obvious. If it is an entity in an array, such as a vector, then it may be able to use an index operator or function. But in many cases, this will tend to return. In addition, the function of single-selection functions is very limited. If you want to manipulate or compare a series of elements in the collection, not just one, what should I do? The way is to use a "ender" that belongs to an object, which is responsible for selecting the elements within the collection and supplies them to the user. As a class, it also provides levels of abstraction. With this level, the collection details can be separated from the code used to access the set. The collection is abstract into a simple sequence through the actuator. The heir allows us to traverse that sequence, while doing care for the infrastructure - in other words, no matter whether it is a vector, a link list, a stack, or something else. In this way, we can flexibly change the basic data, and will not interfere with the code in the program. Java is the first (in version 1.0 and 1.1), providing a standard heir, named Enumeration, serving all of its collection class. Java 1.2 adds a more complex collection library that contains a hemerry named Iterator that can do more than vintage enumeration.
From the design perspective, we need a full-featured sequence. By manipulating it, you should solve your own problems. If a type of sequence can meet all our requirements, there is no need to replace different types again. There are two reasons to prompt us to choose a collection. First, the collection provides different interface types as well as external behavior. The interface between the stack is different from the behavior and the queue, and the interface between the queue is different from a set (SET) or list. With this feature, we have greater flexibility when we solve the problem.
Second, different collections often have different efficiency when performing specific operations. The best example is the difference between vector (vector) and list (list). They all belong to a simple sequence, with a fully consistent interface and external behavior. But when performing some specific tasks, it is completely different. Random access (access) for elements in the vector is a normal operation; whether we choose what is selected, the amount of time required is the same. But in a list of links, if you want to move, and randomly select an element, you need to pay the price of "heavy". And assume that an element is located far from the list, it will live a lot of time it takes. But on the other hand, if you want to insert an element in the middle of the sequence, use a list more than the vector. These and other operations have different execution efficiency, which depends on what is the infrastructure of the sequence. In the design phase, we can start with a list first. In the final adjustment, change it to the vector according to the situation. Since the abstraction is made through the hemer, it can be easily handled in both the two, and the impact on the code is negligible.
Finally, remember that the collection is just a storage center for placing an object. If the storage can meet all our needs, it is completely unnecessary to care about how it is implemented (this is a basic concept of most type objects). If you work in a programming environment, it produces internal overhead due to other factors (such as running under Windows, or brought overhead by the garbage collector), the difference between the vector and the link list is perhaps Not a big problem. We may only need a type of sequence. I can even imagine a "perfect" collection, it can automatically change the realization of the base layer according to their own way. 1.7.2 single structure
In an object-oriented programming, a problem with particularly prominence due to the introduction of C is: All classes will be inherited from a separate basic class. In Java (like other almost all OOP languages), the answer to this question is certain, and the name of this final base class is very simple, that is, "Object". This "single structure" has many advantages.
All objects in a single structure have a general interface, so they are ultimately the same type. Another solution (like C ) is that we cannot guarantee that all things belong to the same basic type. From a backward-compatible perspective, this solution can be better coordinated with the C model, and it can be considered to limit less. But the holiday we want to make pure object-oriented programming, then you must build your own structure, in order to get the same convenience in the other OOP language. You need to add the new categories we have to use, but also use other incompatible interfaces. It is naturally necessary to pay additional energy to bring new interfaces with their own design (possibly need multiple inheritance). Do you have such a price to get this cost for C extra "flexibility"? Of course, if you really need - if you have already been C expert, if you have an advice to C, it is really worth it. But if you are a newbie, the first contact such design, like a replacement scheme like Java, may save more effort.
All objects in a single structure (such as all Java objects) guarantee that there are some specific functions. In your own system, we know some basic operations for each object. A single structure, plus all objects are created in the memory, which can greatly simplify the passage of the parameters (this is a complex concept in C ).
Using a single structure, we can make it easier to implement a garbage collector. The necessary support related to this can be installed in the base class, while the garbage collector can send the appropriate message to any object within the system. If there is no such single structure, and the system can manipulate the object through a handle, the way to achieve the garbage collector is very different, and it will face many obstacles.
Since the type of runtime is affirmed in all objects, it will never encounter a case where it is not judged. This is particularly important for system-level operations, such as violation control; and get greater flexibility in programming.
But everyone may also have questions. Since you say the benefits so the sky, why does C use single structure? In fact, this is a result of early efficiency and control. Single structure will bring some restrictions on programming. Moreover, more importantly, it increases the difficulty of new procedures and original C code. Although these restrictions only cause problems only in a particular occasion, in order to obtain the maximum flexibility, C finally decided to give up the practice of single structure. And Java does not have the above problems, it is a language that is new design, does not have to maintain so-called "backward compatibility" with existing languages. So naturally, like other major object-oriented programming languages, single structure is soon implemented in Java's design. 1.7.3 Collection Library and Easy Use Collection
Since the collection is a tool we often use, a collection library is very necessary, it should be easily reused. In this way, we can easily take a variety of collections and insert them into your own procedure. Java offers such a library, although it is very limited in Java 1.0 and 1.1 (Java 1.2's collection library is undoubtedly a masterpiece).
Drop-style and template / versatility
In order to make these sets can be reused, or "regenerate", Java provides a general type, which previously called "Object". Single structure means that everything is an object in the end of the root.
To use such a collection, simply add the object handle pointing to it, you can reuse the object by the handle. However, since the collection can only accommodate Object, when we add an object handle to the collection, it will trace the Object, which lost its identity or identification information. When using it again, you will get an Object handle, not to the type of handle we have earlier. So how can I return its original appearance, call the useful interface of the object that earlier in first,?
Here, we use it again. But this time is not traceable in a hierarchical structure into a more "universal" type. Instead, discontinuation is a more type of "special". This type of styling is called "Downcasting". For example, we know that when the shape is traced, the Circle is a type of Shape (geometric shape), so the upper traceability is safe. But we don't know that an Object is Circle or Shape, so it is difficult to ensure the safety of the discrete, unless it knows what you have to operate.
But this is not absolutely dangerous, because if you are traceable, you will get an running error we call "illegal" (Exception). We will explain this later. But when you extract the object handle from a collection, you must use some way to accurately remember what they are in order to ensure the correct shape.
Drop-style and runtime tests require additional time to run procedures, and programmers must pay additional energy. In this case, can we create a "smart" collection, let it know the type of yourself? This is necessary to eliminate the necessary and potential errors. The answer is certain, we can use "parameterization type", which is class that can be customized automatically and can cooperate with specific types. For example, by using a parameterized set, the compiler can customize the collection to only accept Shape and only the Shape is extracted.
The parameterization type is an important part of C , which is C no single structure. In C , the keyword for implementing the parameterized type is Template. Java has not yet provided parametric types because it is a bit awkward because of the use of a single structure. But this does not guarantee that the later version will not be implemented, because the word "generic" has been implemented by Java "(in the ADA language," generic "is used to implement its template). This keyword reservation mechanism taken by Java is actually often impressed, it is difficult to determine what will happen. 1.7.4 Difficulties in clear: Who is responsible for clear?
Each object requires resources to "survive", where the most striking resource is memory. If you no longer need to use an object, you must clear it to release these resources so that other objects are used. If you want to solve very simple questions, how to clean an object is not very prominent: We create an object, call it when you need it, then clear or "destroy". But on the other hand, the problems we usually encounter are often more complicated than this.
For example, suppose we want to design a system, use it to manage air traffic in an airport (the same model may also be suitable for managing containers in a warehouse, or a set of zip rental systems, or pet stores This first looks like it is very simple: constructing a collection to accommodate the plane, then create a new aircraft, put it into a collection. All the aircraft entering the air traffic control area is treated so. As for the clearance, leave in a plane This area can simply delete it.
But things are not as simple, there may also need another system to record data related to the aircraft. Of course, the main functions of the controller are different, and the importance of these data may not be revealed at the beginning. For example, this record reflects the flight plan of all small aircrafts leaving the airport. So we got another collection of small aircraft. Once an aircraft object is created, if it is a small plane, then it must also put it into this collection. The objects in this collection are then subject to some background processing in the system free period.
The problem is now more complicated: How can I know when to delete an object? After using the object, some other parts of the system may still have to play. The same problem will also appear in other places, and in the programming system (such as C ), it must be deleted after using an object, so the problem will become abnormal (note 6).
6: Note that this is only established on the object created in the memory (created with the new command). But on the other hand, it requires objects to create in memory stacks on the other hand and all other common programming issues.
In Java, the garbage collector has taken into account the release problem of memory (although this does not include clearing other aspects involved). The garbage collector "knows" when an object is no longer used, then automatically releases the memory space occupied by the object. In this way, the facts that are inherited from a single root type Object, and because we can only create objects in one way in memory stacks, Java programming is much easier than C . We only need to make a small amount of choices, you can overcome the original existing obstacles.
1. Influence of garbage collector on efficiency and flexibility
Since this is such a good means, why didn't you get full in C ? Of course, we must pay a certain amount of convenience for this programming, the price is the cost period overhead. As mentioned earlier, in C , we can create an object in the stack. In this case, the object is automatically cleared (but does not have flexibility to create objects during operation). Creating an object in the stack is the most effective way to assign a storage space for an object, but also to release those rooms most effective. Creating an object in the HEAP may have to pay much more expensive. If you always inherit from the same basic class, all function calls have the "homogeneous" feature, so inevitably need to pay a certain price. But garbage collectors are a special problem because we can never determine when it starts or spends more time. This means that there is an incoherent factor during the execution of the Java program. So in some special occasions, we must avoid it - such as the execution of a program must remain stable, while calling them as "real-time programs", although not all real-time programming issues must be Requirements - Note 7). 7: According to some technical readers of this book, there is a ready-made real-time Java system (www.newmonics.com), it is indeed possible to ensure the efficacy of the garbage collector.
The designer of the C language once issued a request to the C programmer (but also very successful), do not want to add any features that may have an impact on C speed or use anywhere in C, not to use C . This purpose is reached, but the price is C programming inevitably complicated. Java is simpler than C , but the cost of pay is efficient and a certain degree of flexibility. But for most programming problems, Java is undoubtedly our preferred.
1.8 violation control: solve the error
Starting from the oldest programming language, error control has always been a big problem that designers need to solve. Since it is difficult to design a set of perfect error control schemes, many languages simply ignore problems, pass it to the library designers. For most error control schemes, the most important problem is that they have seriously dependent on programmers, rather than relying on the language itself. If the programmer is not alert enough - if it is more in a hurry, this is almost certain-that the error control scheme depends on the program will be invalid.
"Violation Control" sets the error control scheme to the programming language, sometimes even built into the operating system. The "illegal" (Exception) belongs to a special object, which will "throw" or "throw" from the generated place. Subsequently, this violation will be designed to control the "violation controller" capture for specific types of errors. When the situation becomes unsatisfactory, there may be several violation controllers to capture the corresponding violation objects in parallel. Since the use of a separate executive path, we will not interfere with our conventional execution code. This makes the writing of code easier because you don't have to force the code. In addition, a violation of "throw" is different from the error value returned from the function, and is different from a flag set by the function. The role of those error values or logos is to indicate an error status, which is negligible. But the violation cannot be ignored, so it will definitely get an arrangement in some place. Finally, the use of violations can reliably recover from a bad environment. At this point, you can generally don't need to exit, we can take some processing and the regular execution of the recovery program. Obviously, the program prepared is more reliable.
Java's violation control mechanism is different from most programming languages. Because in Java, the violation control module is packaged from the beginning, so it must be used! If you don't write some code to correctly control your violation, you will get a compile time error message. This ensures the coherence of the program, making the error control easier. Note that violation control is not object-oriented, although in an object-oriented programming language, the violation is usually represented by an object. As early as an object-oriented language, violation control already exists.
1.9 multi-threaded
In computer programming, a basic concept is to control multiple tasks simultaneously. Many programming problems require the program to stop the work of the hand, change to other problems, return to the main process. This goal can be achieved by a variety of ways. At the beginning, those programmers who have the lower level of the machine have written some "interrupt service routines", and the pause of the main process is implemented by the hardware level interrupt. Although this is a useful method, it is difficult to transplant, resulting in a high cost of another class.
Sometimes, it is necessary to interrupt it for those tasks that are very real-time. However, there are many other problems that only require the problem into independently running program, so that the entire program can respond more quickly to the user's request. In a program, these independently running pieces are called "Thread", which is called "multi-threaded processing" using the concept it programmed. A common example of multi-threading process is the user interface. With threads, users can press the next button, then the program will respond immediately, rather than let the user wait for the program to start responding in the current task.
At the beginning, the thread is only a tool for processing a single processor. However, if the operating system itself supports multiple processors, each thread can be assigned to a different processor, truly enter the "parallel operation" state. From the perspective of programming language, one of the most valuable features of multi-threaded operation is that the programmer does not have to care how many processors have been used. The program is split into several threads in the logical sense; if the machine itself has multiple processors installed, the program will run faster and do not require any special adjustment.
According to the previous discussion, everyone may feel that the thread is very simple. But you must pay attention to a question: share resources! If there are multiple threads run simultaneously, and they try to access the same resources, they will encounter a problem. For example, the two processes cannot send information to a printer at the same time. To solve this problem, for those that can be shared (such as printers), they must enter the lock state during use. So a thread can lock the resource. After completing its task, unlock (release) this lock so that other threads can then use the same resources.
The multi-threaded mechanism of Java has been built into the language, which makes a more complex problem simple. Support for multi-threaded tension is supported at the level of object, so an execution thread can be expressed as an object. Java also provides a limited resource lock scheme. It can lock any object occupied by any object (the memory is actually one of a variety of shared resources), so there is only one thread to use a specific memory space at the same time. For this purpose, you need to use the synchronized keyword. Other types of resources must be explicitly locked by programmers, which usually requires programmers to create an object, with it represents a lock, all threads must check this lock when accessing that resource.
1.10 permanent
After creating an object, as long as we need, it will always exist. However, when the program ends run, the "survival" of the object will also declare the end. Although this phenomenon is very reasonable, it will find that in depth, it will find that the object can continue to exist after the program stops, and can retain all of its information, then in some cases a very valuable Best. When the program is started next, the object is still there, and the information reserved inside is still the information of the program last time. Of course, you can write information into a file or database to achieve the same effect. But although all things can be seen as an object, if the object can be declared into "permanent", it is undoubtedly a quite convenient thing to look at all other details. Java 1.1 provides support for "limited permanent", which means that we can simply save the object to disk, and can be retrieved any time in the future. The reason why it is "limited" is because we still need to make a call, and the preservation and retrieval of objects are made. These work cannot be carried out automatically. In the future version of Java, it is expected to be more comprehensive for "permanent" support.