Chapter 14. Type Information -- Thinking in Java
1) If an object appears in a string concatenation expression (involving '+' and String objects), the toString( ) method is automatically called to produce a String representation for that object.
2) RTTI(Runtime Type Information) means : At run time, the type of an object is identified.
3) The Class object contains information about the class and it's used to create all of the "regular" objects of your class. Java performs its RTTI using the Class object, even if you’re doing something like a cast. The class Class also has a number of other ways you can use RTTI.
4) There’s one Class object for each class that is part of your program. Each time you write and compile a new class, a single Class object is also created (and stored, appropriately enough, in an identically named .class file). To make an object of that class, the Java Virtual Machine (JVM) that’s executing your program uses a subsystem called a class loader.
5) The class loader subsystem can actually comprise a chain of class loaders, but there’s only one primordial class loader, which is part of the JVM implementation. The primordial class loader loads so-called trusted classes, including Java API classes, typically from the local disk. It’s usually not necessary to have additional class loaders in the chain, but if you have special needs (such as loading classes in a special way to support Web server applications, or downloading classes across a network), then you have a way to hook in additional class loaders.
6) The class loader first checks to see if the Class object for that type is loaded. If not, the default class loader finds the .class file with that name (an add-on class loader might, for example, look for the bytecodes in a database instead). As the bytes for the class are loaded, they are verified to ensure that they have not been corrupted and that they do not comprise bad Java code (this is one of the lines of defense for security in Java).
7) All Class objects belong to the class Class. A Class object is like any other object, so you can get and manipulate a reference to it (that’s what the loader does). One of the ways to get a reference to the Class object is the static forName( ) method, which takes a String containing the textual name (watch the spelling and capitalization!) of the particular class you want a reference for. It returns a Class reference. If it fails, it will throw a ClassNotFoundException.
8) If you already have an object of the type you’re interested in, you can fetch the Class reference by calling a method that’s part of the Object root class: getClass( ). This returns the Class reference representing the actual type of the object.
9) You must use the fully qualified name (including the package name) in the string that you pass to forName( ).
10) getName( ) produces the fully qualified class name, and getSimpleName( ) and getCanonicalName( ) (introduced in Java SE5) produce the name without the package, and the fully qualified name, respectively. islnterface( ) tells you whether this Class object represents an interface. getlnterfaces( ) method returns an array of Class objects representing the interfaces that are implemented by the class of interest. You can also ask for the direct base class of the class using getSuperclass( ).
11) The newlnstance( ) method of Class is a way to implement a "virtual constructor," which allows you to say, "I don’t know exactly what type you are, but create yourself properly anyway." and will return a reference to Object. The class that’s being created with newlnstance( ) must have a default constructor.
12) Java provides a second way to produce the reference to the Class object: the class literal -- a static field of each class with type of Class , name of class. (i.e. Object.class) Class literals work with regular classes as well as interfaces, arrays, and primitive types. In addition, there’s a standard field called TYPE that exists for each of the primitive wrapper classes. The TYPE field produces a reference to the Class object for the associated primitive type.
13) It’s interesting to note that creating a reference to a Class object using ".class" doesn’t automatically initialize the Class object. There are actually three steps in preparing a class for use:
a. Loading, which is performed by the class loader. This finds the bytecodes (usually, but not necessarily, on your disk in your classpath) and creates a Class object from those bytecodes.
b. Linking. The link phase verifies the bytecodes in the class, allocates storage for static fields, and if necessary, resolves all references to other classes made by this class.
c. Initialization. If there’s a superclass, initialize that. Execute static initializers and static initialization blocks.
Initialization is delayed until the first reference to a static method (the constructor is implicitly static) or to a non-constant static field.
14) If a static final value is a "compile-time constant," that value can be read without causing the class to be initialized. Making a field static and final, however, does not guarantee this behavior when the initial value of the static final cannot be decided at compile-time.
15) A Class reference points to a Class object, which manufactures instances of classes and contains all the method code for those instances. It also contains the statics for that class.
16) You are allowed to constrain the type of Class object that the Class reference is pointing to, using the generic syntax (introduced in Java SE5).
17) In Java SE5, Class<?> is preferred over plain Class, even though they are equivalent and the plain Class produces a compiler warning. The benefit of Class<?> is that it indicates that you aren’t just using a non-specific class reference by accident, or out of ignorance. You chose the non-specific version. In order to create a Class reference that is constrained to a type or any subtype, you combine the wildcard with the extends keyword to create a bound. (i.e. Class<? extends Collection> )
18) An interesting thing happens when you use the generic syntax for Class objects: newlnstance( ) will return the exact type of the object, rather than just a basic Object. If you get the superclass of the generic syntax for a Class object (i.e. Class<LinkedHashSet>) using getSuperclass( ), the compiler will only allow you to say that the superclass reference is "some class that is a superclass of that class" using Class <? super LinkedHashSet>. It will not accept a declaration of Class<HashSet>. Also the return type of its newInstance() is not a precise type, but just an Object.
19) The cast( ) method takes the argument object and casts it to the type of the Class reference. Class.asSubclass( ) allows you to cast the class object to a subtype of a more specific type.They are both introduced by Java SE5.
public <U> Class<? extends U> asSubclass(Class<U> clazz) { if (clazz.isAssignableFrom(this)) return (Class<? extends U>) this; else throw new ClassCastException(this.toString()); }
20) The compiler will check to see if the downcast is reasonable, so it won’t let you downcast to a type that’s not actually a subclass.
21) The keyword instanceof tells you if an object is an instance of a particular type. It returns a boolean. It’s important to use instanceof before a downcast when you don’t have other information that tells you the type of the object; otherwise, you’ll end up with a ClassCastException.
22) The Class.islnstance( Object o) method provides a way to dynamically test the type of an object. (This method is native.)
23) Class.isAssignableFrom(Class c ) perform a runtime check to verify that the object that you’ve passed actually belongs to the hierarchy of interest. (whether the class c is the subclass of the class reference)
24) The class Class supports the concept of reflection, along with the java.lang.reflect library which contains the classes Field, Method, and Constructor (each of which implements the Member interface).
25) The true difference between RTTI and reflection is that with RTTI, the compiler opens and examines the .class file at compile time. Put another way, you can call all the methods of an object in the "normal" way. With reflection, the .class file is unavailable at compile time; it is opened and examined by the runtime environment.
26) The Class methods getMethods( ) and getConstructors( ) return an array of Method and array of Constructor that are public, respectively.
27) If you make public class a non-public class (that is, package access), the synthesized default constructor no longer shows up in the getConstructors(). The synthesized default constructor is automatically given the same access as the class.
28) Proxy is one of the basic design patterns. It is an object that you insert in place of the "real" object in order to provide additional or different operations—these usually involve communication with a "real" object, so a proxy typically acts as a go-between.(like delegation) A proxy can be helpful anytime you’d like to separate extra operations into a different place than the "real object," and especially when you want to easily change from not using the extra operations to using them, and vice versa (the point of design patterns is to encapsulate change—so you need to be changing things in order to justify the pattern).
29) Java’s dynamic proxy takes the idea of a proxy one step further, by both creating the proxy object dynamically and handling calls to the proxied methods dynamically. All calls made on a dynamic proxy are redirected to a single invocation handler, which has the job of discovering what the call is and deciding what to do about it.
30) You create a dynamic proxy by calling the static method Proxy.newProxyInstance( ), which requires a class loader (you can generally just hand it a class loader from an object that has already been loaded using Class.getClassLoader( ), a list of interfaces (not classes or abstract classes) that you wish the proxy to implement, and an implementation of the interface InvocationHandler. The dynamic proxy will redirect all calls to the invocation handler, so the constructor for the invocation handler is usually given the reference to the "real" object so that it can forward requests once it performs its intermediary task. The InvocationHandler.invoke( ) method is handed the proxy object, in case you need to distinguish where the request came from. However, be careful when calling methods on the proxy inside invoke( ), because method calls on proxy object are redirected to invoke( ). In general, in InvocationHandler.invoke( ) , you will perform the proxied operation and then use Method.invoke( ) to forward the request to the proxied object (Polymorphism will still take effect for refective method invocation), passing the necessary arguments.
31) Both Mock Object and Stub are stand-ins for the "real" object that will be used in the finished program. However, they both pretend to be live objects that deliver real information, rather than being a more intelligent placeholder for null, as Null Object is. The distinction between Mock Object and Stub is one of degree. Mock Objects tend to be lightweight and self-testing, and usually many of them are created to handle various testing situations. Stubs just return stubbed data, are typically heavyweight and are often reused between tests. Stubs can be configured to change depending on how they are called. So a Stub is a sophisticated object that does lots of things, whereas you usually create lots of small, simple Mock Objects if you need to do many things.
32) It’s still possible to reach in and call all of the methods using reflection, even private methods! If you know the name of the method, you can call setAccessible(true) on the Method object to make it callable. There doesn’t seem to be any way to prevent reflection from reaching in and calling methods that have non-public access. This is also true for fields by using Field, even private fields. However, final fields are actually safe from change. The runtime system accepts any attempts at change without complaint, but nothing actually happens. ( see getDeclaredField() and getDeclaredMethod())
上一篇: tomcat系统架构简介
下一篇: Java虚拟机中的类加载器的类型