Examples of Java RTTI Runtime type recognition mechanism _java

Source: Internet
Author: User
Tags constant generator rand reflection static class

1, RTTI:
run-time type information allows you to discover and use type information while the program is running.

There are two ways to identify objects and classes at runtime in Java: Traditional Rtti, and reflection. Here is the next rtti.

RTTI: Recognizes the type of an object at run time. However, this type must be known at compile time.

The following is an example to see the use of Rtti. This involves the concept of polymorphism: Having the code manipulate only the reference to the base class, and actually invoking the method of a specific subclass, typically creates a specific object (circle,square, or triangle, see the example below), and transitions it up to shape (ignoring the object's specific type), and use a shape reference in the following program that is anonymous (that is, not knowing the exact type):

Abstract class Shape {
  //This invokes the ToString () method of the current class, returning the actual content
  void Draw () {System.out.println (this + draw ());}
  //Declare toString () to be an abstract type, force integration to override this method
  abstract public String toString ();
}

Class Circle extends Shape {public
  String toString () {return "Circle";}
}

Class Square extends Shape {public
  String toString () {return "Square";}
}

Class Triangle extends Shape {public
  String toString () {return "triangle";}
}

public static void Main (string[] args) {
  //When you put a Shape object into a list<shape> array, it transitions up to Shape, which loses the specific type information
  List <Shape> shapelist = arrays.aslist (New Circle (), New Square (), New triangle ());
  When taken out of an array, this container, in fact all elements are held as object, automatically converts the result to shape, which is the basic use of rtti. For
  (Shape shape:shapelist) {
    shape.draw ();
  }
}

The output results are:

Circledraw ()
Squaredraw ()
Triangledraw ()

When stored in an array, it automatically transitions to shape, loses specific types, and when taken out of an array, (the list container holds everything as Object), it automatically converts the result back to shape, which is the basic usage of rtti. All type conversions in Java are checked at runtime for correctness, that is, Rtti: The type of an object is recognized at run time.

The above transformation is not thorough, the element of the array is taken out and the object transforms to shape, rather than the concrete type, this is ensured by the container and the Java generic system at compile time, and there is a type conversion operation at runtime to ensure this.

The specific code that can be executed to subclasses through a Shape object is polymorphic, depending on the specific object that the shape reference points to.

In addition, using RTTI, you can query the exact type of the object that a shape reference points to, and then selectively execute the method of the subclass.

2, Class object:
to understand how Rtti works in Java, you must know how type information is represented at runtime, and this is done by the special object of class.

The class object is used to create all the "general" objects of the class. Java uses a class object to perform its rtti.

Whenever a new class is compiled, a class object (. class file) is generated. The JVM running this program will use the "class loader" subsystem.

Class Loader subsystem: Contains a class loader chain, but only one native class loader, which is part of the JVM implementation. The native class loader loads trusted classes, including Java API classes, which are typically loaded from a local disk. When you need to load classes in a certain way to support Web server applications, you can hook up an extra class loader.

2.1, the time to load the class:
This class is loaded when the program creates the first reference to a static member of a class. This proves that the constructor is also a static method of the class, and the new object that creates the class using the new operator also serves as a reference to the static member of the class.

Dynamically loaded when Java programs are visible, loading on demand. When class is needed, the class loader first checks whether the class object of the classes has already been loaded, and if not, the default class loader finds the. class file based on the class name. Next is the validation phase: when loaded, they are validated to ensure that they are not corrupted and do not contain bad Java code.

2.2, class-related methods, newinstance ()
The following example demonstrates the loading of a class object:

Class A {
  //Static code library, executed on first load, knowing when the class was loaded with
  static {System.out.println ("Loading A")
by printing information Class B {
  static {System.out.println ("Loading B");}
Class C {
  static {System.out.println ("Loading C");}
public class Load {public
  static void Main (string[] args) {
    System.out.println ("Execute main ...");
    New A ();
    System.out.println ("After new A");
    try {
      class.forname ("com.itzhai.test.type.b");
    } catch (ClassNotFoundException e) {
      SYSTEM.OUT.PRINTLN ("Cloud Not find class B");
    }
    System.out.println ("After Class.forName B");
    New C ();
    System.out.println ("After new C");
  }

The output results are:

Execute main ...
Loading A after the
new a
Loading B after the
class.forname b
Loading c after
new C

It is visible that the class object is loaded when it is needed, noting the Class.forName () method:

The forname () method is a way to get a reference to a class object, by which you can use the type information at run time by obtaining a reference to the appropriate class object.

If you already have an object of interest, you can get a class reference by using the GetClass () method provided by class object.

Here is the code for the use of class:

Interface x{} interface y{} interface z{} class Letter {letter () {};
Letter (int i) {}; Class Newletter extends letter implements X, Y, z{Newletter () {super (1);}.} public class Classtest {/** * print Type information * @param c/static void Printinfo (Class C) {//GetName () Gets the fully qualified class name System.out.println ("Class name:"
    + c.getname () + "is interface" + c.isinterface ());
    Gets the class name System.out.println ("Simple name:" + c.getsimplename ()) that does not contain the package name;
  Get fully qualified class name System.out.println ("Canonical name:" + c.getcanonicalname ());
    public static void Main (string[] args) {Class c = null;
    try {//get Class reference c = Class.forName ("Com.itzhai.test.type.NewLetter");
      catch (ClassNotFoundException e) {System.out.println ("Can not find Com.itzhai.test.type.NewLetter");
    System.exit (1);
    }//Print interface type information for (Class face:c.getinterfaces ()) {printinfo (face);
    //Get Superclass class reference class up = C.getsuperclass (); Object obj = NULL;
    try {//The instance of class is created by the newinstance () method obj = Up.newinstance ();
    catch (Instantiationexception e) {System.out.println ("Can not Instantiate");
    catch (Illegalaccessexception e) {System.out.println ("Can not access");
  ///Print superclass type information Printinfo (Obj.getclass ());

 }
}

The output is:

Class name:com.itzhai.test.type.x is interface? True simple
name:x
Canonical name:com.itzhai.test.type.x
Class Name:com.itzhai.test.type.y is interface ? True simple
name:y
Canonical name:com.itzhai.test.type.y
Class Name:com.itzhai.test.type.z is interface ? True simple
name:z
Canonical name:com.itzhai.test.type.z
Class Name:com.itzhai.test.type.Letter is Interface? False simple
Name:letter
Canonical name:com.itzhai.test.type.Letter

Note that the string passed to forname () must use the fully qualified name (including the package name).

By using the method inside the Printinfo, you can discover an object's complete class inheritance structure at run time.

Using the Newinstance () method of class is a way to implement the virtual constructor by creating an instance of class with an object reference, but referring to the letter object. A class that is created using newinstance () must have a default constructor. (and through the reflection API, you can dynamically create objects of a class with any constructor).

2.3. Class literal constants:
In addition to using the GetName () method, Java also provides another way to generate a reference to a class object, that is, to use a literal constant:

Newletter.class;

This method is simple and secure, and is checked and more efficient at compile time. Not only for normal classes, but also for interfaces, arrays, and basic data types. In addition, for the wrapper class of the basic data type, there is also a standard field Type,type field is a reference that executes the corresponding class object of the underlying data type. For the sake of unification, it is recommended to use the. Class form.

2.4. The difference between using. class and creating an object reference using the GetName () method:
when you create with. class, the class object is not automatically initialized. Create the following steps:

(1) loading is performed by the class loader: Lookup bytecode (usually found in the path specified by classpath, but not required), and then create a class object from those bytecode.

(2) The link verifies the bytecode in the class, allocates storage space for the static domain, and, if necessary, resolves all references to the other classes created by the class.

(3) Initialize if the class has a superclass, initialize it, execute the static initializer and the static initialization block.

Initialization is deferred until the first reference to a static method (the constructor is implicitly static) or a very few static fields is performed:

Class data1{
  static final int a = 1;
  Static final Double b = math.random ();
  static {
    System.out.println ("init Data1 ...");
  }

Class data2{
  static int a =;
  static {
    System.out.println ("init Data2 ...");
  }

Class data3{
  static int a =;
  static {
    System.out.println ("init Data3 ...");
  }

public class ClassTest2 {public
  static void Main (string[] args) {
    System.out.println ("Data1.class:");
    Class data1 = Data1.class;
    System.out.println (data1.a); No initialization of Data1
    System.out.println (data1.b);//initialization of Data1
    System.out.println (data2.a);//initialization of DATA2
    try {
      Class data3 = Class.forName ("com.itzhai.test.type.Data3");//initialization of DATA3
    } catch ( ClassNotFoundException e) {
      System.out.println ("Can not found com.itzhai.test.type.Data3 ...");
    }
    System.out.println (data3.a);
  }


The results of the output are:

Data1.class: 
1
init Data1
... 0.26771085109184534
init Data2
...
init Data3
... 23

Initialization effectively implements the "inertia" as much as possible.

2.5, here are some things to decide whether or not to perform initialization:
(1) class syntax obtaining a reference to a class does not cause initialization;

(2) Class.forName () generated a Class reference, immediately initialized;

(3) If a static final value is a "compiler constant", then the value does not need to initialize the class to be read;

(4) If you just set a field to static final is not enough to ensure this behavior, such as the above:

Static final Double b = math.random ();

(5) If a static domain is bushifinal, it is always necessary to link and initialize the advanced nature when accessing it.

2.6, the Generalization of class reference:
A class reference represents the exact type of the object it points to, and is an object of the class class. In JavaSE5, you can qualify the class object that the class reference points to by generics, and you can have the compiler enforce additional type checking:

Class intcls = Int.class;
Use generic qualified Class-pointing reference
class<integer> genintcls = int.class;
Clas that do not use generics can be assigned a value to point to any other class object
intcls = Double.class;
The following compilation will make an error
//genintcls = Double.class;

2.6.1, using wildcard characters? To loosen the limits of generics:

class<?> intcls = Int.class;
Intcls = String.class;

,class<?> is superior to trivial classes in JavaSE5, and it is more recommended to use CLASS<?>, even if they are equivalent, because the advantage of class<?> is that it means that you are not accidentally or negligently, Instead, it uses a class reference that is not specific.

To qualify a reference to class as a type, or a subtype of that type can use wildcard characters with extends, create a range:

class<? Extends number> num = int.class;
Num's Reference range is number and its subclasses, so you can assign num = Double.class According to the following values
;
num = Number.class;

The Newinstance () method under 2.6.2, generic type:
when you use the generic class, the object returned by the call to Newinstance () is the exact type, but when you use Getsuperclass () to get a generic corresponding superclass, the real type has some limitations: The compiler knows the superclass type at compile time, but The Newinstance () method that is referenced through this fetched superclass returns not the exact type, but the object:

Dog Dog = Dogcls.newinstance ();
Abstract class Animal {
}
class Dog extends animal{
}

//The following is an error and can only be returned to CLASS< Super dog> type
/ /class<animal> Animalcls = Dogcls.getsuperclass (); 
class<? Super Dog> animalcls = Dogcls.getsuperclass ();
By getting a superclass reference, you can only create objects object
obj = animalcls.newinstance () that return the object type.

2.6.3, the new Transformation Grammar: Cast () method
look at the code directly:

Animal Animal = new Dog ();
class<dog> dogcls = Dog.class;
Dog Dog = dogcls.cast (animal);
or directly using the following transformation method
dog = (dog) animal;

You can see that the cast () method does the extra work, and this conversion method can be used in situations where the cast () method can be used when writing a generic band, if the class reference is stored, and you want to perform the transformation through this class reference.

3. Type Check instanceof
3.1. Check before type conversion
The compiler allows you to freely do an upward-transition assignment without requiring any of the displayed transformation operations, as if the reference to the superclass is assigned a value.

However, if you do not use the display type conversion, the compiler does not allow you to perform downward conversion assignment, this time we may wish to first check that the object is not a specific type of instance, using the keyword instanceof:

if (x instanceof Dog)
  ((DOG) x). Bark ();

3.2, the form of Rtti:
So so far, we know that the forms of Rtti include:

(1) Traditional type conversion (Shape)

(2) Class object representing the type of object

(3) Keyword instanceof

3.3, the dynamic instanceof method:
The Class.isinstance method provides a way to dynamically test the object.

The following shows the use of instanceof and class.isinstance:

Attribute:

Public interface Attribute {

}

Shape:

/**
 * Create an abstract class
/Public abstract class shape{
  //This invokes the current class's ToString method for information public
  void Draw () { System.out.println (This + ". Draw ()"); }
  //Declares the ToString () method to abstract, forcing the successor to override the method.
  Abstract public String toString ();
}

Circle:

public class Circle extends Shape implements attribute{public
  String toString () {return "Circle";}
}

Square:

public class Square extends shape{public
  String toString () {return "Square";}
}

Triangle:

public class Triangle extends shape{public
  String toString () {return ' triangle ';}
}

Type check:

instanceof
Circle C = new Circle ();
To determine if an instance of the superclass
System.out.format ("Using instanceof:%s is a shape?"). %b\n ", 
    c.tostring (), C instanceof Shape);
To determine if the circle instance
System.out.format ("Using instanceof:%s is a circle?" %b\n ", 
    c.tostring (), C instanceof Circle);
To determine if an instance of the superclass
System.out.format ("Using class.isinstance:%s is a shape?"). %b\n ", 
    c.tostring (), Shape.class.isInstance (c));
Determines whether an instance of an interface
System.out.format ("Using class.isinstance:%s is an Attribute?" %b\n ", 
    c.tostring (), Attribute.class.isInstance (c));

It can be found that the instanceof or Class.isinstance method determines whether an instance of an inherited system, in addition to the judgment itself, also determines whether a superclass or interface is an instance.

The following is a demonstration of using dynamic class.instance usage:

First create an abstract shape Builder class:

 public abstract class Shapecreator {private Random rand = new Random (10); Returns an array of object types, provided by the implementation class, followed by two implementation forms, based on forname and class-literal constants. class public abstract list<class<?
  Extends shape>> types ();
    Randomly generating type object instances in an array of object types public Shape Randomshape () {int n = rand.nextint (types (). Size ());
    try {return types (). get (N). newinstance ();
      catch (Instantiationexception e) {e.printstacktrace ();
    return null;
      catch (Illegalaccessexception e) {e.printstacktrace ();
    return null;
    }//Generate a random array of public shape[] Createarray (int size) {shape[] results = new Shape[size];
    for (int i=0; i<size; i++) {Result[i] = Randomshape ();
  return result; //Generate a random array, generic ArrayList public arraylist<shape> ArrayList (int size) {arraylist<shape> result = new
    Arraylist<shape> ();
    Collections.addall (result, createarray (size));
  return result; }
}

Next, write an implementation of the abstract class:

/**
 * forname Generator Implementation
 * @author arthinking * */Public
class Fornamecreator extends shapecreator{

  private static list<class< extends shape>> types = 
      new Arraylist<class<? extends shape>& gt; ();
  private static string[] Typenames = {
    "com.itzhai.javanote.entity.Circle",
    " Com.itzhai.javanote.entity.Square ",
    " Com.itzhai.javanote.entity.Triangle "
  };

  @SuppressWarnings ("unused")
  private static void loader () {for
    (String name:typenames) {
      try {
        Types.add ((class<? extends shape>) class.forname (name);
      } catch (ClassNotFoundException e) {
        e.printstacktrace ();
  }}} The type array required to initialize the load is
  static {
    loader ();
  }
  Public list<class<? Extends shape>> types () {return
    types;
  }
}

Finally write a statistic of the number of shapes in the class, which uses the instanceof:

public class Shapecount {

  static class Shapecounter extends Hashmap<string, integer>{public
    void Count ( String type) {
      Integer quantity = Get (type);
      if (quantity = null) {Put
        (type, 1);
      } else {put
        (type, quantity + 1);

  }}} Demonstrates using the INSTANCEOF Keyword statistics object type public
  static void Countshapes (Shapecreator creator) {
    Shapecounter counter = new Shapecounter ();
    for (Shape Shape:creator.createArray) {
      if (Shape instanceof Circle)
        counter.count ("Circle");
      if (Shape instanceof Square)
        counter.count ("Square");
      if (shape instanceof triangle) {
        counter.count ("triangle");
      }
    SYSTEM.OUT.PRINTLN (counter);
  }

  public static void Main (string[] args) {
    countshapes (new Fornamecreator ());
  }


Rewrite the implementation of the abstract class, and reuse the class literal constant:

/**
 * Literal generator implementation */public
class Literalcreator extends shapecreator{public

  static final List<class ? Extends shape>> Alltype = collections.unmodifiablelist (Arrays.aslist, Circle.class, 
      Square.class));

  Public list<class<? Extends shape>> types () {return
    alltype;
  }

  public static void Main (string[] args) {
    System.out.println (alltype);
  }



Now use Class.instance to count the number of shapes as follows:

/** * Removes the monotone class.instanceof statement */public class from the original Shapecount by using the instanceof Dynamic test object

  ShapeCount2 {private static final list<class<? extends shape>> shapetypes = Literalcreator.alltype; Static class Shapecounter extends hashmap<string, integer>{public void count (String type) {Integer Quanti
      ty = Get (type);
      if (quantity = = null) {Put (type, 1);
      else {put (type, quantity + 1); ()}//Demo class.isinstance () Statistics object type public static void Countshapes (Shapecreator creator) {Shapecounter Co
    unter = new Shapecounter (); for (Shape Shape:creator.createArray) {for (class<? extends shape> cls:shapetypes) {if (cls.isins
        Tance (Shape)) {Counter.count (Cls.getsimplename ());
  }} System.out.println (counter);
  public static void Main (string[] args) {countshapes (New Fornamecreator ()); }
}

Now that the generator has two implementations, we can add a layer of skins here to set the default implementation:

/**
 * Now there are two implementations of the generator, we add a layer of appearance here, set the default implementation mode
 * * Public
class Shapes {public

  static final Shapecreator Creator =
      new Literalcreator ();
  public static Shape Randomshape () {return
    creator.randomshape ();
  }
  public static shape[] Createarray (int size) {return
    creator.createarray (size);
  }
  public static arraylist<shape> ArrayList (int size) {return
    creator.arraylist (size);
  }
}

3.4, the equivalence of instanceof and class:
instanceof and Isinstance () produce exactly the same results, keeping the concept of type, judging whether a class or a derived class of this class.

Equals () is the same as = =, and using this more realistic class object does not consider inheritance.

System.out.println (New Circle () instanceof Circle); True
System.out.println (Shape.class.isInstance (New Circle ());//True
System.out.println ((New Circle ()) . getclass () = = Circle.class); True
System.out.println ((New Circle (). GetClass ()). Equals (Shape.class);//False

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.