Chapter 11 Operation Type Identification

xiaoxiao2021-03-06  46

The concept of running type identification (RTTI) is very simple - when there is only one handle of the base type, use it to determine the correct type of an object.

However, the need for RTTI needs exposure to object-oriented design many interesting (and often confusing) issues, and officially put the program's construction problem on the desktop.

This chapter will discuss how to use Java to find objects and class information during operation. This mainly takes two forms: one is "traditional" RTTI, which assumes that we have all types we have in compilation and running period; the other is the "reflection" mechanism for Java1.1, and uses it to find independently at runtime Class information. First discuss the "traditional" RTTI and discuss the reflex problem.

11.1 needs to RTTI

Consider the following familiar class structure example, which utilizes versatility. The conventional type is the Shape class, and the type of specially derived is Circle, Square, and Triangle.

516 pages

This is a typical schematic diagram, the base class is located at the top, derived by derived category. Object-oriented programming is to use a large number of code control basic types (here you are shape) handle, so if you decide to add a new class (such as rhomboid, from Shape derived), it will not affect the procedure, then it will not affect the original Code. In this example, the dynamic binding method in the Shape interface is DRAW (), so the customer programmer is to call DRAW () through a normal Shape handle. Draw () is overwritten in all derivatives. And because it is a dynamic binding method, even if it is called by a normal Shape handle, it also shows the correct behavior. This is the function of context.

So, we generally create a specific object (Circle, Square, or Triangle), trace it back to a shape (special type of object), and then use an anonymous Shape handles in the remainder of the program.

As a brief review of velocity and tracetability, it can be encoded as described above (difficulty when performing this program, please refer to Chapter 3 3.1.2 "Assignment"):

516-517 page program

The basic class can be encoded into an interface, an Abstract class or a normal class. Since Shape does not have a real member (that is, a defined member), and does not care we create a pure Shape object, the most suitable and most flexible expression is an interface. And because you don't have to set all the Abstract keywords, the entire code is also more refreshing.

Each derived class covers the basic DRAW method, so it has different behaviors. A specific type of Shape is created in Main () and then add it to a vector. Here is the place where the wind is traced, because the vector is only accommodated. Since all things in Java (except for basic data types) are objects, the vector can accommodate the Shape object. But in the process of tracery to Object, any special information will be lost, and even the object is the fact of geometric shape. For Vector, they are just Object.

When using NexTelement () to extract an element from the vector, the situation is slightly more complicated. Since the vector is only to accommodate Object, nextelement () will naturally have an Object handle. But we know that it is actually a shape handle and wants to send the Shape message to that object. Therefore, it is necessary to use a traditional "shape" mode into a shape. This is the most basic form of RTTI, because in Java, all styles are checked during operation to ensure their correctness. That is the meaning of RTTI: at the course of operation, the type of object will be identified. In this case, the RTTI shape only achieves part: Object is shaped, rather than modeling Circle, Square, or Triangle. It is because the only fact that we are currently affirmed is that the vector is full of geometries, instead of their specific categories. During the compilation, our affirmation is based on our own rules; and during compilation, it is definitely this.

The current situation will be controlled by polymorphism, and the appropriate method is called for the Shape to determine whether the handle is providing Circle, Square, or is supplied to Triangle. Moreover, in general, a versatile solution must be guaranteed. Because we want your code to know some of the specific types of objects as possible, you only put the attention on a certain type of object (here is Shape). Only in this way, our code is more easy to implement, understand, and modify. Therefore, it is a routine target for object-oriented programming.

However, if you encounter a special programming problem, only after knowing the exact type of the regular handle, you can solve this problem easily. What should I do this? For example, we sometimes want your users to make a specific type of geometry (such as triangles) into purple in order to highlight them and quickly find all of this type. In this case, the RTTI technology is used, and it is used to query what the exact type of a Shape handle reference is.

11.1.1 Class object

To understand how RTTI works in Java, you must first understand how type information is expressed in the running period. At this time, you should use a special form of "Class Object", which contain information related to the class (sometimes it is called "class class"). In fact, we have to create all "General" or "General" objects belonging to a class with the Class object.

For each class as part of the program, they have a Class object. In other words, each time you write a new class, it will also create a Class object (more appropriately, it is saved in a .class file that is completely the same name). At runtime, once we want to generate an object of that class, the Java Virtual Machine (JVM) for executing the program first checks if the type of Class object is loaded. If it is not loaded, the JVM looks for the same name. Class file and load it. So the Java program is not fully loaded when starting, which is different from many traditional languages.

Once the type of Class object enters memory, use it to create all of the types of objects.

If this kind of saying makes you have a little confused, or don't really understand it, the following demonstration procedure may provide further help:

519-520 page program

For each class (CANDY, GUM, and Cookie), they have a STATIC clause that is used to execute when the class is first loaded. The corresponding information will be printed and tell us when loading. In Main (), the creation code of the object is between the print statement in order to detect the load time. Special interesting lines are:

Class.Forname ("gum");

This method is a Static member of Class (i.e., all Class from all Class). Class objects and any other objects are similar, so a handle that can be obtained and controlled (the loading module is dry). In order to obtain a handle of Class, one means use forname (). Its role is to obtain a string containing the name of the target class text (note spelling and case). The last returned is a CLASS handle.

The output in a JVM is as follows:

520 page program

It can be seen that each class will only be loaded when it needs, and Static initialization is performed when loaded.

Very interesting is that the output of another JVM becomes another look:

520 page procedure

It seems that JVM has predicted the need for Candy and cookies by checking the code in main (), but can't see gum because it is created by a call to the forname () instead of more typical new. transfer. Although this JVM has also achieved our hopes, because it will be loaded into those classes before we need, but it is not certain that the behavior of the display is 100%.

Class tag

In Java 1.1, a second way can be employed to generate a handle of a Class object: Use "class tag". For the above programs, it looks like this:

Gum.class;

This is not only simpler, but also safer because it will be checked during compilation. Since it cancels the need to call the method, the efficiency of the execution will be higher.

Class tags can not only be applied to ordinary classes, but also applicable to interfaces, arrays, and basic data types. In addition, there is a standard field called Type for each basic data type package. The role of the TYPE field is to generate a handle of the Class object for the relevant basic data type, as shown below:

……Equivalent to……

521 page table

11.1.2 Check before the shape

So far, our known RTTI forms include:

(1) Classic modeling, such as "(Shape), use RTTI to ensure the correctness of the shape, and generate a ClassCastexception violation after encountering a failure.

(2) Represents the Class object of the object type. You can query the Class object to get useful running period.

In C , the classic "Shape" is not executed in RTTI. It simply tells the compiler to treat objects as new types. Java wants to perform type checks, which is typically called "Type Security". The reason why it is called "discontinuation" is caused by historical arrangements of class layered structures. If a Circle is stamped into a Shape (geometric shape), it is called the traceable shape because the circle is just a subset of geometric shapes. Conversely, if Shape is molded to Circle, it is called a discontinuation. However, although we clearly know that Circle is also a Shape, the compiler can automatically trace the shape, but it cannot guarantee that a shape is definitely a Circle. Therefore, the compiler does not allow automatic discontinuation, unless the model is clearly specified. RTTI has three forms in Java. Keyword InstanceOf tells us that the object is not a specific type of instance (instance "instance"). It will return a boolean value to use the problem, just like this:

IF (x instanceof dog)

((DOG) x) .bark ();

Before the X-style to a Dog, the above IF statement checks whether the object X is dependent on the DOG class. Before you make a shape, if you don't have other information, you can tell your own object, then instanceof is very important - otherwise a ClassCastException violation.

Our most general approach is to find a type (such as a triangle to be a purple), but the following program demonstrates how to mark all objects with instanceof.

522-524 page program

In Java 1.0, there is a relatively small restriction on InstanceOf: only compare it to a named type, you cannot compare with the Class object. In the above example, everyone may think that all those instanceOf expressions are very troublesome. This is the case. But in Java 1.0, there is no way to let this work automatically - can't create a Vector of Class, and compare it to it. Everyone will eventually realize that such as a number of instanceOf expressions, the entire design may have problems.

Of course, this example is just an idea - it is best to add a Static data member in each type, and then make it value in the builder to track counts. When writing a program, everyone may imagine the source control of the class and can freely change it. However, since the actual situation is not always, RTTI is particularly convenient.

1. Use class tags

The PETCount.java example can be rewritten over again with the class tag of Java 1.1. The result is more clear and easy to understand:

524-526 page program

Here, the TypeNames array has been deleted and changed from the Class object to get the type name. Note that this additional work is made: for example, the class name is not getBil, but C11.PetCount2.getbil, which contains the name of the package. It is also important to pay attention to the system to be able to classify and interface.

It can also be seen that PETTYPES's creation module does not need to be surrounded by a try block because it will be checked in the compile period, and no violation is like class.Forname ().

After PET is dynamically created, you can see that the random number has been restricted, between 1 and PETTYPES.LENGTH, and does not include zero. It is because zero represents PET.CLASS, and a normal PET object may not be interested. However, since PET.CLASS is part of PETTYPES, all PETs will be counted in a count. 2. Dynamic InstanceOf

Java 1.1 adds an IsInstance method to the Class class. Use it to dynamically call the InstanceOf operator. In Java 1.0, it can only be static (like the previous aspects). Therefore, all of those annoying instanceof statements can be deleted from the Petcount example. As follows:

526-528 page program

It can be seen that the isinstance () method of Java 1.1 has canceled the need to instanceOf expression. In addition, this also means that once the new type of pets are required, simply change the PETTYPES array; do not need to change the remaining parts of the program (but it is required when instanceof is used).

11.2 RTTI syntax

Java implements its own RTTI feature with Class objects - even if we are going to do just some work like styles. The Class class also provides a large number of ways to facilitate our use of RTTI.

First, you must get a handle to the appropriate Class object. As in the pre-example demonstration, a way is to use a string and a class.forname () method. This is very convenient, because one of the types of objects do not require the Class handle. However, for the type of interest, if there is an object, then in order to get the Class handle, one method that belongs to the root root class: getClass (). Its role is to return a specific Class handle to indicate the actual type of object. Class provides several interesting and useful methods that can be seen from the following example:

528-529 page program

As can be seen, Class Fancytoy is quite complicated because it inherits from Toy and implements Hasbatteries, WaterProof, and ShootSthings interface. A Class handle is created in Main () and initializes Forntoy with Forname () located within the corresponding TRY block.

The Class.GetInterfaces method returns an array of Class objects to indicate an interface included in the Class object.

If there is a Class object, you can also query the direct basic class of the object with GetSuperClass (). Of course, this will return a Class handle that can be used for further queries. This means that there is a complete hierarchy of the object to be investigated at the time of the running period.

If viewed from the surface, the Class's newInstance () method seems to be a clone (Clone ()) another means of an object. But both are different. With newInstance (), we can create new objects without "clone" without ready-to-see objects. As with the program above, there is no Toy object at the time, only a handle of CY-ie y's Class object. Use it to implement the Virtual Builder. In other words, we express: "Although I don't know what your exact type is, please create yourself," In the above example, CY is just a Class handle, and there is no further type information during compilation. Once a new instance is created, the Object handle can be obtained. But that handle points to a Toy object. Of course, if you want any any messages that Object can receive, some survey studies must be carried out, and the shape is required. In addition, the class created with newinstance () must have a default builder. There is no way to create objects with non-default builders with newinstance (), so there may be some restrictions in Java 1.0. However, Java 1.1 "Reflection" API (next section discussion) allows us to dynamically use any builder in the class. The last way in the program is PrintInfo (), which gets a Class handle, get its name by getName (), and use interface () to investigate it. Is it an interface.

The output of the program is as follows:

530 page

So use the Class object, we can almost investigate the 18th generation of an object.

11.3 Reflection: Operation class information

If you don't know the exact type of an object, RTTI will help us investigate. But there is a restriction: The type must be known during compilation, otherwise it cannot be investigated in RTTI, which in turn cannot expand the next step. In other words, the compiler must explicitly know all classes to be processed by RTTI.

From the surface, it seems not a big limit, but if you get a handle of an object that is not in your own program space, what will happen? In fact, the object's class cannot be used by our program even during compilation. For example, suppose we get a series of bytes from a disk or network and is informed of those bytes represent a class. Since the compiler does not know the situation when compiling the code, how can I use this class smoothly?

In traditional programming environments, this situation has probabilistic probability may be small. But when we transferred to a larger programming world, we must attach this issue. The first thing to note is the component-based programming. In this environment, we use the "Rapid Application Development" (RAD) model to build a program project. RAD is typically built in the application build tool. This is a visual approach to the program (appearing on the screen). The icon representing the different components can be dragged into the form. Subsequently, the correct configuration is performed by setting the properties or values ​​of these components. The configuration during the design requires that any components can be "exemplified" (ie, they can be free to obtain them). These components also reveal some of their own content, allowing programmers to read and set various values. In addition, components for controlling the GUI event must reveal information related to the corresponding method so that the RAD environment helps programmers override these ways to drive these events. "Reflection" provides a special mechanism that detects available methods and generates method names. With Java Beans (Chapter 13, the Java 1.1 provides an infrastructure for this component-based programming.

Another original power in the runtime query information is to create and execute an object on a remote system over a network. This is called "Remote Method Call" (RMI) that allows the Java program (version 1.1 or more) to use objects published or distributed by multiple machines. The distribution of this object may be caused by many reasons: I may have to make a calculated intensive job, want to split it, allowing other machines in an idle state to share some work, thus speeding up the progress. In some cases, you may need to control specific type tasks (such as "Operational Rules" in the multi-layer client / server architecture) placed on a special machine, so that this machine is described for those actions. A universal storage office. And it is convenient to modify this site to make it an impact on all aspects within the system (this is a particularly useful design idea because the machine is independent, so it can easily modify the software!). Distributed computing can also make further play certain dedicated hardware, which is particularly good at implementing some specific tasks - such as matrix reversal - but is too exaggerated for routine programming. In Java 1.1, the class class (detailed discussion above this chapter) has been extended to support the concept of "reflection". For the Field, Method, and the Constructor class (each implementation of the MemberInterface - member interface), they have added a library: java.lang.reflect. These types of objects are created by JVM at runtime, which is used to represent members of the unknown class. This will create a new object with the builder, read and modify the field associated with the Field object with the GET () and set () methods, and the method associated with the Method object with the Invoke () method. In addition, we can call methods getFields (), getMethods (), getConstructors (), return to an object array for representing fields, methods, and builders, respectively (in online documents, more information related to Class classes ). Therefore, the class information of anonymous objects can be completely revealed in the running period, and there is no need to know anything during compilation.

Everyone should understand that "reflection" is not a magical place. When dealing with the same unknown type of object, JVM simply checks that object and investigates which particular class belongs to which particular class (like the previous RTTI). But after this, the Class object must be loaded before we do anything else. Therefore, it is necessary for the specific type of .class file must be called by JVM (either in the local machine, you can get through the network). So the only difference between RTTI and "Reflection" is to turn on the RTTI, the compiler will open and check the .class file in the compile period. In other words, we can call all the methods of an object in a "normal" manner; but for "reflection", the .CLASS file is not available during compilation, but is turned on and checked by the runtime environment.

11.3.1 A class method extractor

I rarely use the reflection tool directly; the reason why they provide them in the language, just to support other Java features, such as object serialization (Chapter 10, Introduction), Java Beans, and RMI (later in this chapter). However, we still need to dynamically extract information related to a class. A particularly useful tool is a class method extractor. As mentioned earlier, if you find a source code or online document, you can only see the method that is defined or covered in that class definition. There is still a lot of information in the base class. Fortunately, "Reflection" has done this, and it is available to write a simple tool to automatically display the entire interface. The following is a specific program: 533-534 page

Class method getMethods () and getConstructors () can return to an array of Method and Constructors, respectively. Each class provides a further approach to resolve the names, parameters, and return values ​​of the methods they represent. But you can also use TOString () like this to generate a string containing a complete method. The residual part is only used to extract the command line information, and it is determined whether the specific signature is consistent with our target string (using indexof ()) and print out.

The "reflection" technology is used here because the results generated by class.Forname () cannot be known during compilation, so all method signatures are extracted during operation. If you study the part of the "reflection" in the online document, it will find that it has provided sufficient support to actually set a fully unknown object, and a method call. Similarly, this also belongs to a step in which we worry about - Java will use this support, so the program design environment can control Java Beans, but it is very interesting.

A fun test is to run Java Showmehods ShowMethods. Doing this gives a list, including a public default builder, although we don't define a builder in the code. We see the builder that is automatically synthesized by the compiler. If ShowMethods are set to a non-PUBLIC class (ie, replacing "friendly" classes), the synthetic default builder will not appear in the output result. The synthesized default builder automatically obtains the same access rights as class.

SHOWMETHODS's output is still "uncomfortable". For example, the following is part of the output result obtained by calling Java ShowMethods Java.lang.String:

534-535 page program

If you can go out of a qualified word like java.lang, it is obviously more satisfactory. In view of this, the StreamTokenizer class introduced in the previous chapter can be introduced to solve this problem:

535-537 page program

The ShowMethodSclean method is very close to the previous showMethods, just it gains the Method and Constructor arrays and convert them into a single string array. Subsequently, each such String object is "over" in stripqualifiers.strip (), deletes all methods qualified words. As everyone saw, STREAMTOKENIZER and STRING are used to complete this job.

If you can't remember whether a class has a specific method, you don't want to gradually check the class structure in the online document, or you don't know if that class can do something for an object (such as a Color object), this tool saves a lot. Programming time.

Chapter 17 provides a GUI version of this program, running it when you write code, so you can quickly find things you need.

11.4 Summary

Use RTTI to investigate the type information according to an anonymous base class handle. But for this reason, the novices are very easy to misuse it, because some of the opinion is sufficient. For those who have been programmed to be programmed before, it is easy to organize their programs into a series of Switch statements. They may use RTTI to do this, thus losing the importance of multi - shape technology in code development and maintenance. Java's requirements are to make us use of polymorphism as much as possible, and only RTTI is used in very particular case. However, in order to use versions, we have to have control of the basic class definition, because some time may find that the basic class does not include the method we want. If the basic class comes from a library, or if anything is controlled, RTTI is a good solution: you can inherit a new type, then add your own additional method. Other parts of the code, you can detect your own specific type and call the special method. Do not destroy the versions and the extension of the program, because the new type of addition does not require the Switch statement in the program. However, when adding a new code in the body that requires a new feature, you must use RTTI to detect your own specific type.

From the perspective of a particular class, after adding a feature in the basic class, it may mean that all other classes derived from that basic class must get some meaningless "chicken ribs". This makes the interface mean ambiguous. If someone inherits from that basic class, and must cover the abstract method, this phenomenon will cause them to fall into trouble. For example, now use a class structure to indicate the instrument (INSTRUMENT). Assuming that we want to clean all the appropriate instruments in the orchestra (SPT Valve), one of the options is to place a ClearsPitValve () method in the basic class Instrument. But this will cause a misunderstanding because it suggests that there is also a musical instrument and electronic musical instrument. In response to this situation, RTTI provides a more reasonable solution that allows the method into a specific class (which is Wind, "ventilation port") - this is feasible. But in fact, a more reasonable solution is to place prepareinstrument () in the foundation class. At the beginning, beginners often see this, generally determine that they must use RTTI.

Finally, RTTI sometimes resolves the efficiency problem. If the code is widely used, one of the objects is very problematic in the execution efficiency, and the type can be found in the RTTI, and then write a suitable code to improve its efficiency.

11.5 practice

(1) Write a method to pass an object to it, and cycle print all classes in the object hierarchy.

(2) In Toytest.java, mark the default builder of Toy into annotation information and explain what happens.

(3) Creating a collection of types to use a vector. Capture the type of the first object where it is placed, and then only allows the user to insert the type of object from that time.

(4) Write a program to determine that a char array belongs to the basic data type, or a real object.

(5) Realize ClearsPitvalve () in accordance with the description of this chapter.

(6) Implementing the Rotate (Shape) method introduced in this chapter, checking whether it has been rotated (if the rotation is rotated, no rotation operation).

转载请注明原文地址:https://www.9cbs.com/read-59422.html

New Post(0)