14. The type of information programming ideas

Run-time type information so that you can find and use type information at run time , there are two main ways:

  1. "Traditional" RTTI, which assumes we already know at compile time, all types;
  2. "Reflection" mechanism, which allows the information we discovered at runtime and use classes.

14.1 Why RTTI

RTTI type of maintenance type of information, provide the basis for multi-state mechanisms.

14.2 Class Object

Type information at runtime by Classthe object represented, the completed Classobject contains information related to the class. ClassObject is used to create all the "normal" objects, Java using Classobjects to perform RTTI
class is part of the program, each class has an Classobject of the same name is stored in a .classfile.

Class loader
  1. Class loader subsystem may actually comprise a class loader chain, but only a native class loader , which is part of the JVM implementation. Native class loader loads are credible categories , including Java API class.
  2. All classes are in it for the first time (static members or new objects), dynamically loaded into the JVM.
  3. ClassObjects are only loaded when needed, staticthe initialization is done when the class is loaded.
  4. Class loader first checks this class Classif an object has been loaded before, if not already loaded, the default class loader will look for the corresponding class name .classfile.
Class Class Methods

Want to use the type information at run time, the Class object must obtain a reference to the object: Class.forName("s2.A");. The method automatically initializes the Class object, attention must be fully qualified name (including the package name) .


clz.getSimpleName()
// 获取全限定名
clz.getCanonicalName()
// 获取接口
clz.getInterfaces();
// 获取父类
clz.getSuperClass();
// 创建该类对象
clz.newInstance();

14.2.1 class literals

Java also provides a kind of literal way to generate a reference to the Class object: Class clz = A.class. Note that in this way does not automatically initialize the Class object .

basic type
  1. Class literal not only for normal class, an interface may also be used, an array (int []. Class) and basic data types (int.class) .
  2. Basic types of packaging, there is a standard field TYPE, which is a point corresponding to the basic data types Class object reference: Thepublic static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
Preparation class
  1. Load : performed by the class loader, the step of searching for a corresponding byte code, create a Class object
  2. Links : Verify class bytecode for static field distribution space; and, if necessary, it will resolve references to all other classes of this class is created.
  3. Initialization : If the class has a superclass, then its initialization, performs static initialization and static initialization block
Initialization of inert
  1. Use Class.forName()will be automatically initialized; use A.classno automatic initialization class
  2. Compile-time constants: static final int i = 1;the value , you do not need initialization can be read.
  3. If only one field to static finalinsufficient to ensure a compiler constants, such as static final int ii = new Random().nextInt();.
  4. If a staticdomain is not final, then the first link and initialized before the visit.

14.2.2 Generalization of Class references

After Java SE5, Class can also support the paradigm.
The reason cited is added to the grammar paradigm Class merely to provide compile-time type checking.

14.2.3 new transformation grammar

  1. Cast () method takes a parameter object, which is the transition type Class reference.
  2. Class.asSubclass (), which allows you to tell a class object transformation into a more specific type.
    Class<String> clz = String.class;
    String str1 = clz.cast("");

14.3 type conversion before checking to do first

  1. Java provides a class instanceOfkeyword, you can determine whether the object is an instance of a class (and its parent) of.
  2. clz.isInstance()The method takes an object, the object is determined whether the clzinstance of that class.
  3. clz.isAssignableFrom()The method accepts a Classtarget, which is determined Classwhether the object is clzitself or subclass.
public class Test {
    public static void main(String[] args) throws Exception {
        System.out.println(A.class.isAssignableFrom(C.class));
        System.out.println(B.class.isAssignableFrom(C.class));
        System.out.println(A.class.isInstance(new C()));
        System.out.println(B.class.isInstance(new C()));
    }
}

class A { }
interface B {}
class C extends A implements B {}
// Output:
// true
// true
// true
// true

14.4 registered factory

Use the factory model designed, will create work objects to the class of your own time. Factory method can be polymorphic calls to create an object of the appropriate type for you.

14.5 instanceOf and Equivalence Class

  1. The results instanceOf and isInstance () is exactly the same, when they are considered relatively inheritance
  2. A.class.equals (B.class) and A.class == B.class can only compare whether the same class, without considering inheritance

Runtime class information: 14.6 reflected

RTTI restrictions
  • If you do not know the exact type of an object, RTTI can tell you, but there is a limit: the type must be known at compile time . In other words, the compiler must know all the classes to be handled by the RTTI at compile time.
  • Suppose you get a certain point in your program is not a reference to an object in space, at compile time your application can not learn like this object belongs.
  • Obtaining information of the scene class runtime: based programming member, remote method invocation (RMI).
Reflection and there is no magic
  1. When dealing with an object by reflection of an unknown type, the JVM simply checks the object, to see which class it belongs to a specific (like RTTI like).
  2. Class object must be loaded before the class to do other things with it. Therefore, the class of .class files for the JVM must be taken: either on the local machine, or can be obtained through the network.
  3. So the real distinction between reflection and RTTI only in that, the opening and the compiler at compile time checks .class file is for RTTI; for reflection is, at compile time .class file is unavailable, it is open and check the class file is run.
Reflex action

Java is used in the reflective support other features, such as object serialization and JavaBean.

14.7 Dynamic Proxy

Acting is one of the basic design pattern, which is to provide additional or different actions for you, and inserted objects used in place of "real" object. These operations are usually designed to communicate with the object of "real" and therefore normally acts as a proxy intermediary role.

Static agents
  1. Static proxy form is to write dead add functionality to perform before and after the implementation of this method in the proxy object.
  2. Advantages: can be done on the target object extensions in conformity with the principle of opening and closing.
  3. Cons: We have had to create for each service proxy class, heavy workload and difficult to manage. Once changed while the interface, the proxy class have to be amended accordingly.
public class Test {
    public static void main(String[] args) throws Exception {
        new RealObject().doSomething();
        System.out.println("代理之后:");
        new SimpleProxy(new RealObject()).doSomething();
    }
}

interface MyInterface {
    void doSomething();
}

class RealObject implements MyInterface {
    @Override
    public void doSomething() {
        System.out.println("RealObject");
    }
}

class SimpleProxy implements MyInterface {
    private MyInterface myInterface;

    public SimpleProxy(MyInterface myInterface) {
        this.myInterface = myInterface;
    }

    // 代理后增加方法
    @Override
    public void doSomething() {
        System.out.println("SimpleProxy");
        myInterface.doSomething();
    }
}
Dynamic Proxy
  1. Java's dynamic proxy agents thought more than a step forward, because it can dynamically create proxy and dynamically handle calls to the proxy approach. In the dynamic proxy all calls made will be redirected to the processor on a single call.
  2. By Proxy.newProxyInstance () to create a dynamic proxy, you need a class loader (usually the objects are loaded acquisition), a wish list of interfaces implemented (not a class or an abstract class), as well as a realization of InvocationHandler.
  3. Dynamic proxy can redirect all calls to interface with a call to the agent.
  4. Using dynamic proxy to write a system to achieve the transaction , which is the agent in the agent call executed successfully (no exception is thrown) commit, and rollback failed during execution. You commit and rollback both for an external text file, the file is not abnormal control within the scope of Java. You have to pay attention to the operation of atomicity .
    MyInterface myInterface = (MyInterface) Proxy.newProxyInstance(MyInterface.class.getClassLoader(), new Class[]{MyInterface.class}大专栏  编程思想14.类型信息oken punctuation">, new InvocationHandler() {
            @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("代理方法");
            return method.invoke(new RealObject(), args);
        }
    });
    myInterface.doSomething();

14.8 null object

  1. Using the nulltime to check every time whether it is null, this is a very troublesome thing.
  2. The idea of introducing a null object would be useful, it can accept a message passed to it represents the object, but will return expressed as a value does not actually exist any "real" objects. This way, you can assume that all objects are valid, without having to waste energy to check the programming null.
  3. Singleton objects are usually empty, so you can not only use instanceOfto compare, you can also use equalsor ==to compare.
  4. Note: In some places still have to test for null objects, which checks whether nullthere is no difference, but in many places it is not necessary to perform additional tests, we can directly assume that all objects are valid.
public class Test {
    public static void main(String[] args) throws Exception {
       // 在使用的时候可以直接使用而不会报错空指针
        Person p = Person.NULL_PERSON;
        System.out.println(p.toString());
    }
}

// 空标记接口
interface Null {}

class Person {
    void func() {
        System.out.println("Person");
    }

    // 空对象
    private static class NullPerson extends Person implements Null {
        private NullPerson() {}

        @Override
        public String toString() {
            return "NullPerson";
        }
    }

    public static final Person NULL_PERSON = new NullPerson();
}
Dynamic proxy to create an empty object

Suppose there are a plurality of different Personsub-classes, we each create a relatively empty object. Whenever you need an empty Personobject need only call newNullPerson()and pass required proxy Persontype.

public class Test {
    public static Person newNullPerson(Class<? extends Person> type) {
        return (Person) Proxy.newProxyInstance(NullPerson.NULL_PERSON.getClass().getClassLoader(), new Class[]{type}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("代理");
                return method.invoke(NullPerson.NULL_PERSON, args);
            }
        });
    }

    public static void main(String[] args) throws Exception {
        Person p = newNullPerson(Person.class);
        p.func();
    }
}
// 空标记接口
interface Null {}

// 父接口
interface Person {
    void func();
}

// 空Person
class NullPerson implements Person, Null {
    @Override
    public void func() {
        System.out.println("NullPerson");
    }

    public static final Person NULL_PERSON = new NullPerson();
    private NullPerson() {}
}

14.8.1 mock object pile

Logical variation empty object is simulated objects and piles . Like the empty object, they all represent the "real" objects in the final program used. However, the mock objects and piles are just posing as actual live objects can pass information, rather than an empty object that can become nulla more intelligent alternative.

The difference between the simulation objects and the pile by different degrees. Mock objects tend to be lightweight and self-test, usually a lot of mock object is created to handle a variety of test conditions. Pile pile just returns the data, it is usually heavyweight, and is often between multiplexed test. Piles can be carried out in the manner they are called by configuration changes, so the pile is a complex object, it needs to do a lot of things. However, for mock objects, if you need to do a lot of things, usually it creates a lot of small and simple mock objects.

14.9 interface type information

an important goal is to allow the programmer interface keyword spacer member, thereby reducing the coupling. If you write an interface, then you can achieve this goal, but by the type of information, this coupling will still spread out - the interface is not a guarantee of a decoupling impeccable .

public class Test {
    public static void main(String[] args) {
        A a = new B();
        a.a();
        // 我们需要的是用户使用接口,但是强制转型还是可以访问不存在于接口中的方法
        ((B) a).b();
    }
}

interface A {
    void a();
}

class B implements A {
    @Override
    public void a() {}
    public void b() {}
}
Solution 1: method is a direct statement

If programmers do not use interfaces but subclasses, they are responsible for themselves. That B a = new B();substitute A a = new B();.

Solution 2: package access Hide

In this case outside this package can only be used Hidden.newA () to get the object, and because there is no information of B type, can not casts.

class B implements A {
    @Override
    public void a() {}
    public void b() {}
}

public class HiddenB {
    public static A newA() {
        return new B();
    }
}
Reflected back door
  1. By using reflection, and calls you can still reach all methods, even the privatemethod! If you know the name of the method, in which you can Methodcall on the object setAccessible(true).
  2. finalActually domain in the event of modification is safe. Runtime system will accept any attempt to modify without throwing an exception, but any changes will not actually happen.

14.10 summary

  1. RTTI allows to find the type of information through an anonymous reference the base class.
  2. The purpose object-oriented programming language is to allow us use of polymorphism can be used in all places, use RTTI only when necessary.
  3. Inherit a new class, and then add the method you need. In other parts of the code, you can check your own specific type, and call your own way, this does not destroy the polymorphism and extensibility of the program.
  4. But if you add the new features of the code in the program body needs, you must use RTTI to check your specific type.
  5. There is a consistent error reporting model allows us to write dynamic code by using reflection. Of course, try to write code to perform static checking is worth it, as long as you can really do. But I believe that dynamic code is an important tool to differentiate the Java with other languages ​​such as C ++ this area.

Guess you like

Origin www.cnblogs.com/lijianming180/p/12041149.html