"Deep Java" Rtti and reflection

Source: Internet
Author: User

In Java, how do we identify classes and object information at runtime? There are two ways, one is the traditional rtti, the other is reflection.

1.RTTI run-time type infomation run-time types information Why do I need to RTTI?

The more excellent the object-oriented design, the more emphasis on high cohesion and low coupling, as the dependency reversal Principle said: "Both high-rise modules or low-level modules, should be aimed at abstract programming."

For example, we have an abstract parent class:

Shape draw()

Here are three specific classes:

Circle draw()Square draw()Triangle draw()

In some cases, we hold Shape , but not enough-because we want to do special processing for its specific type, but our design is entirely abstract, so we cannot judge the specific type in the current context.
Because of the existence of rtti, so that we do not undermine the design of the premise to achieve the purpose.

Class and Class objects

In fact, each class holds a reference to the object of its corresponding Class class (which Object in the class getClass() allows us to get to it), which contains information related to the class.
It is very easy to note that, for each class, compiling a Java file generates a binary .class file, which holds information about the object that corresponds to that class Class .

.classis used for class LoaderThe files used

The Java program was not fully loaded before it was run, and the parts were loaded when needed.

The preparation for the use of classes consists of three steps:

    1. Load. Performed by the ClassLoader, finds the bytecode and creates an Class object.
    2. Link. Validates the bytecode, allocates storage space for the static domain, and, if necessary, resolves all references to other classes created by the class (for example, the class holds the static domain).
    3. Initialization If the class has a superclass, initialize it, execute the static initializer [note], and static initialization blocks.

Note: The original is static initializers , viewed thinking in Java, meaning that the static domain should be initialized at the definition, such as:
static Dog d = new Dog(0);

All classes are dynamically loaded into the JVM when they are used for the first time. When a program creates the first reference to a static member of a class, the JVM uses the ClassLoader to find the same name based on the class name- .class once the object of a class Class is loaded into memory, it is used to create all the objects of the class. A constructor is also a static method of a class, and using an new operator to create a new object is treated as a reference to a static member of the class.
Note Exceptions: If a static final value is a compile-time constant, reading this value does not require initialization of the class. So for invariant constants, we should always use static final adornments.

Class.forName (String str)

ClassClass has a useful static method forName(String str) that allows us to get a reference to a class without creating it Class , like this:

try {     Class toyClass = Class.forName("com.duanze.Toy"); // 注意必须使用全限定名} catch (ClassNotFoundException e) {}

However, the use forName(String str) has a side effect: If the Toy class is not loaded, invoking it triggers Toy the clause of the class static (static initialization block).

In contrast, it is better to use class literal constants , like this:

Class toyClass = Toy.class;

Compile-time checking is supported, so no exception is thrown. The use of class literal constants to create Class an object's reference differs from the forName(String str) clause that does not trigger Toy the class static (static initialization block). So it's simpler, safer and more efficient.
Class literal constants support classes, interfaces, arrays, and basic data types.

X Expansion x

Class.forName(String className)Loads the specified class using the class loader that loads the current class. Because the method is class.forName(String className) called internally, Class.forName(className, true, this.getClass().getClassLoader()) as you can see, the third parameter is specifying the class loader, which, obviously, specifies an instance of the class loader that loads the current class, which isthis.getClass().getClassLoader();

You can choose to specify the loader manually:

new  ClassLoader();   Class c1 = cl.loadClass(String className, boolean resolve );  

For a more detailed reference

Standardizing's ClassReference

With the generic and wildcard characters, we can type-qualify references to class objects, such as:

int.class; // 注意右边是基本数据类型的类字面常量

The benefit of this is that the compiler can perform additional type checking.
Knowing this, we can rewrite the previous example:

Class toyClass = Toy.class;Class<?> toyClass = Toy.class;

Although these two sentences are equivalent, they are Class<?> better than the readability Class , which means that the programmer did not choose the non-specific version inadvertently, but chose the non-specific version deliberately.

Class.newinstance ()

Now that we've got a reference to the object containing the class information Class , we should be able to construct an instance of the class. Class.newInstance()is such a method, such as:

// Onetry {    Class<?> toyClass = Class.forName("com.duanze.Toy");     Object obj = toyClass.newInstance();} catch (ClassNotFoundException e) {}// TwoClass<?> toyClass = Toy.class;Object obj = toyClass.newInstance();

newInstance()you must have a default constructor with the class that you created.
Because it is just toyClass an Class object reference, there is no further type information at compile time, so you newInstance() only get a reference when you use it Object . If you need to get the exact type, you need to do this:

Class<Toy> toyClass = Toy.class;Toy obj = toyClass.newInstance();

However, if you encounter the following situation, you can only get Object references:

super SubToy> upClass = subToy.getSuperclass(); // 希望拿到SubToy的父类Toy的Class对象引用// This won‘t compile:// Class<Toy> upClass = subToy.getSuperclass();// Only produces Object:Object obj = upClass.newInstance();

While it is common sense that the compiler should be aware SubToy of the superclass at compile time, it Toy does not actually support writing:

// This won‘t compile:Class<Toy> upClass = subToy.getSuperclass();

And can only accept:

super SubToy> upClass = subToy.getSuperclass(); // 希望拿到SubToy的父类Toy

This may seem strange, but the situation is so, and we have to accept it. Fortunately, this is not a big problem, because transformational operations are not difficult.

Type check

You can use keywords for type checking before you make a type conversion, instanceof such as:

if ( x instanceof Shape ) {     Shape s = (Shape)x;}

instanceofIt's usually enough, but there are times when you might need a more dynamic test path: Class.isInstance(Class clz)

Class<Shape> s = Shape.class;s.isInstance(x);

As you can see, instanceof the left and right sides are mutable compared to each other, and isInstance() this dynamic sometimes allows a large number of packages to be if else... instanceof reduced to one sentence.

2. Reflection

I don't know if you noticed. No, the rtti used above have a common limitation: at compile time, the compiler must know all classes to be handled by RTTI.

But sometimes, you get an object reference, but its corresponding class is not in your program space, what to do? (This is not uncommon, for example, when you get a string of strings from a disk file or a network and are told that this string represents a class that will not appear until the compiler generates code for your program.) )

ClassClasses and java.lang.reflect class libraries provide support for the concept of reflection . The reflection mechanism is nothing magical, and when dealing with an object of unknown type through reflection, the JVM simply examines the object to see which particular class it belongs to. Therefore, the class must be available to the .class JVM, either on the local machine or from the network. So the real difference between Rtti and reflection is only that:

    • RTTI, the compiler opens and examines files at compile time .class
    • Reflection, opening and checking files at run time .class

After understanding the above concepts, what getFields() , getMethods() and so getConstructors() on, basically all can be words too literally.

We can look at the common use of Android development for Actionbar, let the overflow in the option to display the icon of how the effect is made out:

The action button in/*overflow should not display the icon, which is determined by the Setoptionaliconsvisible method of the Menubuilder class, and if we pass this method to True when overflow is expanded, Then the icon for each action button inside will be displayed. */@OverridePublicBooleanonmenuopened(int Featureid, menu menu) {if (Featureid = = Window.feature_action_bar && Menu! =NULL) {if (Menu.getclass (). Getsimplename (). Equals ("Menubuilder")) {try {Boolean.type with boolean.class Method m = Menu.getclass (). Getdeclaredmethod ("Setoptionaliconsvisible", Boolean.type); //Through Setaccessible (true), ensure that the method can be called-even if the private method M.setaccessible (true); //equivalent: Menu.setoptionaliconsvisible (True) m.invoke (menu, true);} catch (Exception e) {}}} return super.onmenuopened (Featureid, menu);}
Summarize:
If you don't know the exact type of an object, Rtti will help us investigate. However, there is a limitation that the type must be known during compilation. And reflection allows us to detect a class during operation, the only difference between Rtti and "reflection" is that for Rtti, the compiler will
Compile time to open and check the. class file. However, for "reflection", the. class file is not available during compilation, but is opened and inspected by the runtime environment, and we use the reflection mechanism generally to provide classes and methods to us using the Java.lang.reflect package.

"Deep Java" Rtti and reflection

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.