In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article examines "how to understand generics, reflections, and annotations in Java's advanced features." The content is detailed and easy to understand, and friends who are interested in "how to understand generics, reflections and comments in the advanced features of Java" can follow the editor's train of thought to read it in depth. I hope it will be helpful to you after reading. Let's learn more about "how to understand generics, reflections, and annotations in Java's advanced features" with the editor.
1. Introduction of generics
In the process of daily programming, generics are used most frequently of these three features. the word "generics" in the word "generics" can be understood as the meaning of generalization, that is, from specific, individual to general. Oracle's official definition of generics is that generic types are generic classes or interfaces that are parameterized by types. In a word, generics is to solve some problems in the universal design and implementation of programs through type parameterization.
Java generics are introduced after version 1.5 and are mainly used to solve three types of problems:
1. Compiler type checking
For example, example 1 in the figure above designs a simple Box class in which an object property of private is defined, and two behaviors, get () and set (), are defined, where set () is used to save object into Box, and set () is used to get the object object in Box. From an abstract point of view, the Box class abstracts a behavior for storing object and access in a box, and the access method accepts or returns an object of type Object. On the basis of this abstraction, objects of any type except the original type can be stored, and the declaration of Object type embodies the idea of inheritance in object-oriented.
In example 2, the use of Box in different business scenarios is implemented. Two different business scenarios are listed. Scenario one needs to store objects of type String in Box, and scenario two needs to store objects of type Integer in Box. In this case, during actual development, a String object is likely to be mistakenly passed in scenario 2, resulting in runtime errors, and this is precisely because Box can be caused by passing only objects of any type. This is especially true when working with collection classes. For example, in example 3:
First, you declare a boxes object of type List, which holds two objects, one of which is "aaaaa" of type String, and the other is 11111 of type Integer. In the business scenario, the consumer thinks that all the objects stored in the boxes are of type String, so an error occurs when the second object is fetched and converted. This situation often confuses users that there is no problem at compile time, but an exception is generated at run time. That is, in this object-oriented abstraction, there is no way to compile to verify how the type should be used.
So how do generics solve this kind of problem?
Oracle is aware of the above problem, and after introducing generics, it creates a declaration of generic types by changing "public class Box" in the code to "public class Box". Behind this declaration is the introduction of a type variable T that can be used anywhere in the class. As shown in example 4: you can see that except for the new generic type declaration, all the Object that appears in the original code is replaced by the type variable T.
At first glance, the word type variable feels a bit obscure, but in fact, if you think about it carefully, you will find that it is not difficult to understand. The above example 4 can be understood as "when using generics, you can pass the type parameter T to the Box type itself". Combined with the official definition given by Oracle, "the nature of generics is type parameterization" will have a deeper understanding.
In example 5, the type parameter T is specified during object declaration and initialization. In scenario one, T is String;, in scenario two, T is Integer. In this way, when the data "aaaaa" of type String is passed into IntegerBox in scenario 2, the program will report an error. The operation of the generic collection object in example 6 is similar. After declaring a boxes object for List, if you pass Integer object 11111 into boxes, the program will report an error.
As you can see, through the use of generics, the problems in previous multi-business scenarios have been solved, because the previous type mismatch can now be solved during the compilation phase, without having to wait for the runtime to expose the problem. As long as generics are used properly, such risks can be largely avoided. For the use of generics, the role of this parameterized type appears to be a declaration, but behind it is actually a convention.
2. Forced type conversion
Recall from example 3 that two objects, "aaaaa" of type String and 11111 of type Integer, are stored in the boxes object of type List. There is a problem. In the declaration of boxes, the user does not know what type of object should be stored in the list of boxes, and the compiler does not know the data type stored in the collection, so it can only decide what type of box is through the actual business scenario. To achieve the business requirements, the Object is forcibly converted to String.
After using generics, the problem that casting must be done in this scenario has been solved. For example, in example 7, through the generic declaration, the type parameter of the element in the collection is specified as the String type, so that the compiler knows the type of the element directly without relying on the actual business logic to convert, thus solving the problem of casting this type.
3. Readability and flexibility
Generics can not only check compiler types and avoid type casting, but also effectively improve the readability of code. For example 3, if generics are not used, when a person who is not aware of the business scenario is operating on the collection, he cannot know what type of objects are stored in list. If generics are used, the current business scenario can be judged by its type parameters, which also increases the readability of the code. At the same time, it can also boldly develop on the basis of abstract inheritance.
The flexibility in the use of generics is reflected in many ways, because it itself is essentially an enhancement in the use of inheritance. Because when generics are working specifically, when compiling the source code, the compiler should first check the generic type parameters to find out the type mismatch, and then erase the type and insert a cast instruction at the location where the type parameters appear.
In addition to the above basic usage, generics have several special high-level uses:
There are certain scenarios in the design of wildcards, for example, after using generics, first declare a class of Animal, and then declare a Cat class that inherits from the Animal class. Obviously, the Cat class is a subclass of the Animal class, but List is not a subtype of the List class, and often need to express such a logical relationship in the program. To solve this similar scenario, the use of wildcards is added to the parameter types of generics. Specifically, there are three uses:. The first two are called qualified wildcards and unqualified wildcards.
1. Unbounded wildcards
After understanding the upper and lower wildcards, it is natural to understand the unbounded wildcards. Unbounded wildcards are represented by,? Represents any type, can represent any type only null (Object itself is a type, but can not represent any type, so the meaning of List and List is different, the former type is Object, that is, the top layer of the inheritance tree, while the type of the latter is completely unknown).
Second, reflection mechanism
Reflection is an important dynamic mechanism of Java language itself. Explain the definition of reflection in one sentence: self-control, self-description. That is, through reflection, we can not only dynamically obtain the information of classes, attributes and methods, but also construct objects and control the properties and behavior of objects.
In the figure above, there is an Apple class that has two constructors, an attribute, and two behaviors, get () and set (). In the "self-description" on the left, we mainly try to obtain the constructor information of the Apple class and the corresponding number of parameters, attribute information and method information of the class with the help of reflection in the dynamic process. There is a Class type, which can cause the Class object to be loaded by ClassLoader, thus implementing the call to it in jvm. In this program, some class information, class attribute information and class method information are printed. In the "self-control" code on the right, you create some objects and trigger some behavior of the object during the run, and finally try to assign the properties of the object. The basic use of reflection is relatively simple, but this mechanism enhances the flexibility of the Java language.
As shown in the figure above, the general process of running a non-reflective Java class is to write the source file Apple.java, then the compiler compiles it into a bytecode file Apple.class, and finally loads it into jvm and runs it. When using reflection, the compiler knows nothing about its types (compiled types and dynamic types) at first, and the compiler does not know its true types until it is run.
The advantages of reflection mainly lie in two points:
In some scenarios, this "unknown type" actually greatly increases the flexibility of the program at run time, but there is some performance loss.
The type of object can be judged at run time, which is essentially a great enhancement of polymorphism and further decouples the abstraction of the upper layer from the concrete implementation of the lower layer.
These two points are very obvious in JDBC Driver. For example, in the example in the above figure, the driver loading mode of JDBC is realized through reflection mechanism, which ensures that the driver to be loaded can be dynamically selected at runtime, and the program flexibility is greatly enhanced. In addition, JDBC only designs the interface that the driver needs to implement, and does not care about the number and implementation mode of the driver, as long as it installs a unified specification, and the type judgment and specific method trigger can be handed over to the runtime dynamic judgment. The use of this reflection mechanism incisively and vividly reflects polymorphism and reduces the degree of coupling between classes.
III. Use of annotations
Annotations were introduced in version 1.5 and have now become a very important part of daily program development. Annotations are metadata that have no use in themselves and must be attached to specific objects if they are to be. The two most common annotations in daily use are @ Override and @ Deprecated.
Leaving aside the specific concepts, usage, and how annotations work, annotations are very similar to the concept of "tags". @ Override can be understood as adding a tag to a method that represents "this is a method that has been overridden by a subclass in an inheritance relationship." To further understand, after this tag is added to a method, if the method is not in the parent class, an error will be reported at compile time, and it can solve some cases where the method name is inadvertently misspelled in the inheritance scenario. At the same time, the readability of some programs is enhanced.
As shown in the figure above, we also use @ Override as an example to further extract and abstract annotations. Four aspects are abstracted concretely: first, in terms of scope, it can only be applied to the methods of subclass rewriting; secondly, in terms of life cycle, annotations are only checked at compile time and have no effect after compilation; in addition, in terms of document support, as an example to solve the problem of readability, an annotation @ Documented is designed to indicate whether the annotations are included in JavaDoc. In terms of hierarchical design, @ inherited is designed to indicate whether annotations can be inherited by subclasses.
In the figure above, an Apple description annotation is defined, including @ Target, @ Retention, @ Inherited and @ Documented, indicating that its life cycle is the declaration cycle of the program, can be inherited by subclasses, and the document can be included. After designing this annotation, you can use it on the Apple instance in the previous article, such as adding an annotation to the class and method in the figure, and after adding it, you can see the effect of the annotation with reflection, which can better enhance its self-description ability and configuration flexibility.
This is how to understand generics, reflections, and comments in Java's advanced features. I hope the above will improve you. If you want to learn more knowledge, please pay more attention to the editor's updates. Thank you for following the website!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.