Type Information
来源:互联网 发布:男朋友礼物学生知乎 编辑:程序博客网 时间:2024/05/15 03:11
Runtime type information (RTTI) allows you to discover and use type information while a program is running.
It frees you from the constraint of doing type-oriented things only at compile time, and can enable some very powerful programs. The need for RTTI uncovers a plethora of interesting (and often perplexing) OO design issues, and raises fundamental questions about how you should structure your programs.
This chapter looks at the ways that Java allows you to discover information about objects and classes at run time. This takes two forms: "traditional" RTTI, which assumes that you have all the types available at compile time,and the reflection mechanism, which allows you to discover and use class information solely at run time.
The need for RTTI
package typeinfo;//: typeinfo/Shapes.java import java.util.Arrays;import java.util.List;abstract class Shape {void draw() {System.out.println(this + ".draw()");}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 class Shapes {public static void main(String[] args) {List<Shape> shapeList = Arrays.asList(new Circle(), new Square(),new Triangle());for (Shape shape : shapeList)shape.draw();}}/*Output:Circle.draw()Square.draw()Triangle.draw()*/
The base class contains a draw( ) method that indirectly uses toString( ) to print an identifier for the class by passing this to System.out.println( ) (notice that toString( ) is declared abstract to force inheritors to override it, and to prevent the instantiation of a plain Shape). 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.Each of the derived classes overrides the toString( ) method (from Object) so that draw( ) ends up (polymorphically) printing something different in each case.
The Class object
// : typeinfo/SweetShop.java // Examination of the way the class loader works. import static net.mindview.util.Print.print;class Candy {static {print("Loading Candy");}}class Gum {static {print("Loading Gum");}}class Cookie {static {print("Loading Cookie");}}public class Sweetshop {public static void main(String[] args) {print("inside main");new Candy();print("After creating Candy");try {Class.forName("Gum");} catch (ClassNotFoundException e) {print("Couldn't find Gum");}print("After Class.forName(\"Gum\")");new Cookie();print("After creating Cookie");}}
Each of the classes Candy, Gum, and Cookie has a static clause that is executed as the class is loaded for the first time. Information will be printed to tell you when loading occurs for that class. In main( ), the object creations are spread out between print statements to help detect the time of loading.
Class.forName("Gum");
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, which is being ignored here; the call to forName( ) is being made for its side effect, which is to load the class Gum if it isn't already loaded. In the process of loading, Gum's static clause is executed.
2. 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.
3. 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:
//: typeinfo/ClassInitialization.Java import java.util.*;class Initable {static final int staticFinal = 47;static final int staticFinal2 = ClassInitialization.rand.nextInt(1000);static {System.out.println("Initializing Initable");}}class Initable2 {static int staticNonFinal = 147;static {System.out.println("Initializing Initable2");}}class Initable3 {static int staticNonFinal = 74;static {System.out.println("Initializing Initable3");}}public class ClassInitialization {public static Random rand = new Random(47);public static void main(String[] args) throws Exception {Class initable = Initable.class;System.out.println("After creating Initable ref");// Does not trigger initialization:System.out.println(Initable.staticFinal);// Does trigger initialization:System.out.println(Initable.staticFinal2);// Does trigger initialization:System.out.println(Initable2.staticNonFinal);Class initable3 = Class.forName("Initable3");System.out.println("After creating Initable3 ref");System.out.println(Initable3.staticNonFinal);}}
Effectively, initialization is "as lazy as possible." From the creation of the initable reference, you can see that just using the .class syntax to get a reference to the class doesn't cause initialization. However, Class.forName( ) initializes the class immediately in order to produce the Class reference, as you can see in the creation of initable3.
Generic class references
//: typeinfo/GenericClassReferences.Java public class GenericClassReferences {public static void main(String[] args) {Class intClass = int.class;Class<Integer> genericIntClass = int.class;genericIntClass = Integer.class; // Same thingintClass = double.class;//generidntClass = double. class ; / / Illegal}} // /: -
The ordinary class reference does not produce a warning. However, you can see that the ordinary class reference can be reassigned to any other Class object, whereas the generic class reference can only be assigned to its declared type. By using the generic syntax, you allow the compiler to enforce extra type checking.
Class<Number> genericNumberClass = int.class ;
This would seem to make sense because Integer is inherited from Number.But this doesn't work, because the Integer Class object is not a subclass of the Number Class object (this may seem like a subtle distinction; we'll look into it more deeply in the Generics chapter). //: typeinfo/WiIdcardClassReferences.Java public class WiIdcardClassReferences {public static void main(String[] args) {Class<?> intClass = int.class;intClass = double.class;}} // /:-
In Java SE5, Class<?> is preferred over plain Class, even though they are equivalent and the plain Class, as you saw, doesn't produce 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.
//: typeinfo/BoundedClassReferences.java public class BoundedClassReferences {public static void main(String[] args) {Class<? extends Number> bounded = int.class;bounded = double.class;bounded = Number.class;// Or anything else derived from Number.}} // /:-
The reason for adding the generic syntax to Class references is only to provide compile-time type checking, so that if you do something wrong you find out about it a little sooner. You can't actually go astray with ordinary Class references, but if you make a mistake you won't find out until run time, which can be inconvenient.
//: typeinfo/FilledList.java import java.util.*;class CountedInteger {private static long counter;private final long id = counter++;public String toString() {return Long.toString(id);}}public class FilledList<T> {private Class<T> type;public FilledList(Class<T> type) {this.type = type;}public List<T> create(int nElements) {List<T> result = new ArrayList<T>();try {for (int i = 0; i < nElements; i++)result.add(type.newInstance());} catch (Exception e) {throw new RuntimeException(e);}return result;}public static void main(String[] args) {FilledList<CountedInteger> fl = new FilledList<CountedInteger>(CountedInteger.class);System.out.println(fl.create(15));}}/*Output:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]*/
//: typeinfo/toys/GenericToyTest.Java // Testing class Class, package typeinfo.toys;public class GenericToyTest {public static void main(String[] args) throws Exception {Class<FancyToy> ftClass = FancyToy.class;// Produces exact type:FancyToy fancyToy = ftClass.newInstance();Class<? super FancyToy> up = ftClass.getSuperclass();// This won't compile:// Class<Toy> up2 = ftClass.getSuperclass();// Only produces Object:Object obj = up.newInstance();}} // /:-
If you get the superclass, the compiler will only allow you to say that the superclass reference is "some class that is a superclass of FancyToy" as seen in the expression Class <? super FancyToy >. It will not accept a declaration of Class<Toy>. This seems a bit strange because getSuperclass( ) returns the base class (not interface) and the compiler knows what that class is at compile time—in this case, Toy.class, not just "some superclass of FancyToy." In any event, because of the vagueness, the
return value of up.newlnstance( ) is not a precise type, but just an Object.
New cast syntax
package typeinfo.toys;//: typeinfo/ClassCasts.Java class Building {}class House extends Building {}public class ClassCasts {public static void main(String[] args) {Building b = new House();Class<House> houseType = House.class;House h = houseType.cast(b);h = (House) b; // ... or just do this.}} // /:-
The cast( ) method takes the argument object and casts it to the type of the Class reference. Of course, if you look at the above code it seems like a lot of extra work compared to the last line in main( ), which does the same thing.
Another new feature had no usage in the Java SE5 library: Class.asSubclass( ). This allows you to cast the class object to a more specific type.
Checking before a cast
1. The classic cast; e.g., "(Shape)," which uses RTTI to make sure the cast is correct. This will throw a ClassCastException if you've performed a bad cast.
2. The Class object representing the type of your object. The Class object can be queried for useful runtime information.
if (x instanceof Dog) ((Dog)x).bark();The if statement checks to see if the object x belongs to the class Dog before casting x to a Dog. 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.
Ordinarily, you might be hunting for one type (triangles to turn purple, for example), but you can easily tally all of the objects by using instanceof. For example, suppose you have a family of classes to describe Pets (and their people, a feature which will come in handy in a later example). Each Individual in the hierarchy has an id and an optional name. Although the classes that follow inherit from Individual, there are some complexities in the Individual class, so that code will be shown and explained in the Containers in Depth chapter. As you can see, it's not really necessary to see the code for Individual at this point—you only need to know that you can create it with or without a name, and that each Individual has a method id( ) that returns a unique identifier (created by counting each object).There's also a toString( ) method; if you don't provide a name for an Individual, toString( ) only produces the simple type name.
//: typeinfo/pets/Person.Java package typeinfo.pets;import typeinfo.pets.Individual;public class Person extends Individual {public Person(String name) {super(name);}} // /:-
//: typeinfo/pets/Pet.Java package typeinfo.pets;public class Pet extends Individual {public Pet(String name) {super(name);}public Pet() {super();}} // /:-
//: typeinfo/pets/Dog.Java package typeinfo.pets;public class Dog extends Pet {public Dog(String name) {super(name);}public Dog() {super();}} // /:-
//: typeinfo/pets/Mutt.java package typeinfo.pets;public class Mutt extends Dog {public Mutt(String name) {super(name);}public Mutt() {super();}} // /:-
//: typeinfo/pets/Pug.java package typeinfo.pets;public class Pug extends Dog {public Pug(String name) {super(name);}public Pug() {super();}} // /:-
//: typeinfo/pets/Cat.java package typeinfo.pets;public class Cat extends Pet {public Cat(String name) {super(name);}public Cat() {super();}}
//: typeinfo/pets/EgyptianMau.java package typeinfo.pets;public class EgyptianMau extends Cat {public EgyptianMau(String name) {super(name);}public EgyptianMau() {super();}} // /:-
//: typeinfo/pets/Manx.java package typeinfo.pets;public class Manx extends Cat {public Manx(String name) {super(name);}public Manx() {super();}}
//: typeinfo/pets/Cymric.java package typeinfo.pets;public class Cymric extends Manx {public Cymric(String name) {super(name);}public Cymric() {super();}} // /:-
//: typeinfo/pets/Rodent.java package typeinfo.pets;public class Rodent extends Pet {public Rodent(String name) {super(name);}public Rodent() {super();}} // /:-
//: typeinfo/pets/Rat.java package typeinfo.pets;public class Rat extends Rodent {public Rat(String name) {super(name);}public Rat() {super();}} // /:-
//: typeinfo/pets/Mouse.Java package typeinfo.pets;public class Mouse extends Rodent {public Mouse(String name) {super(name);}public Mouse() {super();}} // /:-
//: typeinfo/pets/Hamster.Java package typeinfo.pets;public class Hamster extends Rodent {public Hamster(String name) {super(name);}public Hamster() {super();}}
Next, we need a way to randomly create different types of pets, and for convenience, to create arrays and Lists of pets. To allow this tool to evolve through several different implementations, we'll define it as an abstract class:
//: typeinfo/pets/PetCreator.Java // Creates random sequences of Pets, package typeinfo.pets;import java.util.*;public abstract class PetCreator {private Random rand = new Random(47);// The List of the different types of Pet to create:public abstract List<Class<? extends Pet>> types();public Pet randomPet() { // Create one random Petint n = rand.nextInt(types().size());try {return types().get(n).newInstance();} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}public Pet[] createArray(int size) {Pet[] result = new Pet[size];for (int i = 0; i < size; i++)result[i] = randomPet();return result;}public ArrayList<Pet> arrayList(int size) {ArrayList<Pet> result = new ArrayList<Pet>();Collections.addAll(result, createArray(size));return result;}} // /:-
The abstract getTypes( ) method defers to a derived class to get the List of Class objects (this is a variation of the Template Method design pattern).Notice that the type of class is specified to be "anything derived from Pet," so that newlnstance( ) produces a Pet without requiring a cast.randomPet( ) randomly indexes into the List and uses the selected Class object to generate a new instance of that class with Class.newlnstance( ).The createArray( ) method uses randomPet( ) to fill an array, and arrayList( ) uses createArray( ) in turn.
//: typeinf0/pets/ForNameCreator.Java package typeinfo.pets;import java.util.*;public class ForNameCreator extends PetCreator {private static List<Class<? extends Pet>> types = new ArrayList<Class<? extends Pet>>();// Types that you want to be randomly created:private static String[] typeNames = { "typeinfo.pets.Mutt","typeinfo.pets.Pug", "typeinfo.pets.EgyptianMau","typei nfo.pets.Manx", "typeinfo.pets.Cymric","typei nfo.pets.Rat", "typeinfo.pets.Mouse","typeinfo.pets.Hamster" };@SuppressWarnings("unchecked")private static void loader() {try {for (String name : typeNames)types.add((Class<? extends Pet>) Class.forName(name));} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}static {loader();}public List<Class<? extends Pet>> types() {return types;}} // /: -
The loader( ) method creates the List of Class objects using Class.forName( ). This may generate a ClassNotFoundException,which makes sense since you're passing it a String which cannot be validated at compile time. Since the Pet objects are in package typeinfo, the package name must be used when referring to the classes.
// : typeinfo/PetCount.java // Using instanceof . import static net.mindview.util.Print.print;import static net.mindview.util.Print.printnb;import java.util.HashMap;import typeinfo.pets.Cat;import typeinfo.pets.Dog;import typeinfo.pets.ForNameCreator;import typeinfo.pets.Hamster;import typeinfo.pets.Manx;import typeinfo.pets.Mouse;import typeinfo.pets.Mutt;import typeinfo.pets.Pet;import typeinfo.pets.PetCreator;import typeinfo.pets.Pug;import typeinfo.pets.Rat;import typeinfo.pets.Rodent;public class PetCount {static class PetCounter extends HashMap<String, Integer> {public void count(String type) {Integer quantity = get(type);if (quantity == null)put(type, 1);elseput(type, quantity + 1);}}public static void countPets(PetCreator creator) {PetCounter counter = new PetCounter();for (Pet pet : creator.createArray(20)) {// List each individual pet:printnb(pet.getClass().getSimpleName() + " ");if (pet instanceof Pet)counter.count("Pet");if (pet instanceof Dog)counter.count("Dog");if (pet instanceof Mutt)counter.count("Mutt");if (pet instanceof Pug)counter.count("Pug");if (pet instanceof Cat)counter.count("Cat");if (pet instanceof Manx)counter.count("EgyptianMau");if (pet instanceof Manx)counter.count("Manx");if (pet instanceof Manx)counter.count("Cymric");if (pet instanceof Rodent)counter.count("Rodent");if (pet instanceof Rat)counter.count("Rat");if (pet instanceof Mouse)counter.count("Mouse");if (pet instanceof Hamster)counter.count("Hamster");}// Show the counts:print();print(counter);}public static void main(String[] args) {countPets(new ForNameCreator());}}
In countPets( ), an array is randomly filled with Pets using a PetCreator. Then each Pet in the array is tested and counted using instanceof.
Using class literals
//: typeinfo/pets/LiteralPetCreator.java // Using class literals, package typeinfo.pets;import java.util.Arrays;import java.util.Collections;import java.util.List;public class LiteralPetCreator extends PetCreator {// No try block needed.@SuppressWarnings("unchecked")public static final List<Class<? extends Pet>> allTypes = Collections.unmodifiableList(Arrays.asList(Pet.class, Dog.class, Cat.class,Rodent.class, Mutt.class, Pug.class, EgyptianMau.class,Manx.class, Cymric.class, Rat.class, Mouse.class,Hamster.class));// Types for random creation:private static final List<Class<? extends Pet>> types = allTypes.subList(allTypes.indexOf(Mutt.class), allTypes.size());public List<Class<? extends Pet>> types() {return types;}public static void main(String[] args) {System.out.println(types);}}
In the upcoming PetCount3.java example, we need to pre-load a Map with all the Pet types (not just the ones that are to be randomly generated), so the allTypes List is necessary. The types list is the portion of allTypes (created using List.subList( )) that includes the exact pet types, so it is used for random Pet generation.
//: typeinfo/pets/Pets.java // Facade to produce a default PetCreator. package typeinfo.pets;import java.util.*;public class Pets {public static final PetCreator creator = new LiteralPetCreator();public static Pet randomPet() {return creator.randomPet();}public static Pet[] createArray(int size) {return creator.createArray(size);}public static ArrayList<Pet> arrayList(int size) {return creator.arrayList(size);}} // /:-
This also provides indirection to randomPet( ), createArray( ) and arrayList( ).
package typeinfo.pets;import typeinfo.PetCount;//: typeinfo/PetCount2.java public class PetCount2 {public static void main(String[] args) {PetCount.countPets(Pets.creator);}} /* (Execute to see output) */// :-
The output is the same as that of PetCount.java.
A dynamic instanceof
package typeinfo.pets;//: typeinfo/PetCount3.Java // Using islnstance() import static net.mindview.util.Print.print;import static net.mindview.util.Print.printnb;import java.util.LinkedHashMap;import java.util.Map;import net.mindview.util.MapData;public class PetCount3 {static class PetCounter extendsLinkedHashMap<Class<? extends Pet>, Integer> {public PetCounter() {super(MapData.map(LiteralPetCreator.allTypes, 0));}public void count(Pet pet) {// Class.1slnstance() eliminates instanceofs:for (Map.Entry<Class<? extends Pet>, Integer> pair : entrySet())if (pair.getKey().isInstance(pet))put(pair.getKey(), pair.getValue() + 1);}public String toString() {StringBuilder result = new StringBuilder(" {");for (Map.Entry<Class<? extends Pet>, Integer> pair : entrySet()) {result.append(pair.getKey().getSimpleName());result.append("=");result.append(pair.getValue());result.append(", ");}result.delete(result.length() - 2, result.length());result.append("}");return result.toString();}}public static void main(String[] args) {PetCounter petCount = new PetCounter();for (Pet pet : Pets.createArray(20)) {printnb(pet.getClass().getSimpleName() + " ");petCount.count(pet);}print();print(petCount);}}
In order to count all the different types of Pet, the PetCounter Map is pre-loaded with the types from LiteralPetCreator.allTypes. This uses the net.mindview.util.MapData class, which takes an Iterable (the allTypes List) and a constant value (zero, in this case), and fills the Map with keys taken from allTypes and values of zero). Without pre-loading the Map, you would only end up counting the types that are randomly generated, and not the base types like Pet and Cat.
Counting recursively
//: net/mindview/uti1/TypeCounter.Java // Counts instances of a type family, package net.mindview.util;import java.util.*;public class TypeCounter extends HashMap<Class<?>, Integer> {private Class<?> baseType;public TypeCounter(Class<?> baseType) {this.baseType = baseType;}public void count(Object obj) {Class<?> type = obj.getClass();if (!baseType.isAssignableFrom(type))throw new RuntimeException(obj + " incorrect type: " + type+ ", should be type or subtype of " + baseType);countClass(type);}private void countClass(Class<?> type) {Integer quantity = get(type);put(type, quantity == null ? 1 : quantity + 1);Class<?> superclass = type.getSuperclass();if (superclass != null && baseType.isAssignableFrom(superclass))countClass(superclass);}public String toString() {StringBuilder result = new StringBuilder("{");for (Map.Entry<Class<?>, Integer> pair : entrySet()) {result.append(pair.getKey().getSimpleName());result.append("=");result.append(pair.getValue());result.append(", ");}result.delete(result.length() - 2, result.length());result.append("}");return result.toString();}} // /:-
The count( ) method gets the Class of its argument, and uses isAssignableFrom( ) to perform a runtime check to verify that the object that you've passed actually belongs to the hierarchy of interest.countClass( ) first counts the exact type of the class. Then, if baseType is assignable from the superclass, countClass( ) is called recursively on the superclass.
package net.mindview.util;// : typeinfo/PetCount4.java import static net.mindview.util.Print.print;import static net.mindview.util.Print.printnb;import typeinfo.pets.Pet;import typeinfo.pets.Pets;public class PetCount4 {public static void main(String[] args) {TypeCounter counter = new TypeCounter(Pet.class);for (Pet pet : Pets.createArray(20)) {printnb(pet.getClass().getSimpleName() + " ");counter.count(pet);}print();print(counter);}}As you can see from the output, both base types as well as exact types are counted.
Registered factories
// : typeinfo/factory/Factory.Javapackage typeinfo.factory; public interface Factory<T> { T create(); }
The generic parameter T allows create( ) to return a different type for each implementation of Factory. This also makes use of covariant return types.
package typeinfo.factory;// : type info/RegisteredFactories.jav a // Registering Class Factories in the base class. import java.util.ArrayList;import java.util.List;import java.util.Random;class Part {public String toString() {return getClass().getSimpleName();}static List<Factory<? extends Part>> partFactories = new ArrayList<Factory<? extends Part>>();static {// Collections.addAll() gives an "unchecked generic// array creation ... for varargs parameter" warning.partFactories.add(new FuelFilter.Factory());partFactories.add(new AirFilter.Factory());partFactories.add(new CabinAirFilter.Factory());partFactories.add(new OilFilter.Factory());partFactories.add(new FanBelt.Factory());partFactories.add(new PowerSteeringBelt.Factory());partFactories.add(new GeneratorBelt.Factory());}private static Random rand = new Random(47);public static Part createRandom() {int n = rand.nextInt(partFactories.size());return partFactories.get(n).create();}}class Filter extends Part {}class FuelFilter extends Filter {// Create a Class Factory for each specific type:public static class Factory implements typeinfo.factory.Factory<FuelFilter> {public FuelFilter create() {return new FuelFilter();}}}class AirFilter extends Filter {public static class Factory implements typeinfo.factory.Factory<AirFilter> {public AirFilter create() {return new AirFilter();}}}class CabinAirFilter extends Filter {public static class Factory implementstypeinfo.factory.Factory<CabinAirFilter> {public CabinAirFilter create() {return new CabinAirFilter();}}}class OilFilter extends Filter {public static class Factory implements typeinfo.factory.Factory<OilFilter> {public OilFilter create() {return new OilFilter();}}}class Belt extends Part {}class FanBelt extends Belt {public static class Factory implements typeinfo.factory.Factory<FanBelt> {public FanBelt create() {return new FanBelt();}}}class GeneratorBelt extends Belt {public static class Factory implementstypeinfo.factory.Factory<GeneratorBelt> {public GeneratorBelt create() {return new GeneratorBelt();}}}class PowerSteeringBelt extends Belt {public static class Factory implementstypeinfo.factory.Factory<PowerSteeringBelt> {public PowerSteeringBelt create() {return new PowerSteeringBelt();}}}public class RegisteredFactories {public static void main(String[] args) {for (int i = 0; i < 10; i++)System.out.println(Part.createRandom());}}
Not all classes in the hierarchy should be instantiated; in this case Filter and Belt are just classifiers so you do not create an instance of either one, but only of their subclasses. If a class should be created by createRandom( ), it contains an inner Factory class. The only way to reuse the name Factory as seen above is by qualifying typeinfo.factory.Factory.
instanceof vs. Class equivalence
//: typeinfo/FamilyVsExactType.Java // The difference between instanceof and class package typeinfo;import static net.mindview.util.Print.*;class Base {}class Derived extends Base {}public class FamilyVsExactType {static void test(Object x) {print("Testing x of type " + x.getClass());print("x instanceof Base " + (x instanceof Base));print("x instanceof Derived " + (x instanceof Derived));print("Base.isInstance(x) " + Base.class.isInstance(x));print("Derived.islnstance(x) " + Derived.class.isInstance(x));print("x.getClass() == Base.class " + (x.getClass() == Base.class));print(" x.getClass() == Derived.class "+ (x.getClass() == Derived.class));print("x.getClass().equals(Base.class)) "+ (x.getClass().equals(Base.class)));print("x.getClassO.equals(Derived.class)) "+ (x.getClass().equals(Derived.class)));}public static void main(String[] args) {test(new Base());test(new Derived());}}
The test( ) method performs type checking with its argument using both forms of instanceof. It then gets the Class reference and uses == and equals( ) to test for equality of the Class objects. Reassuringly, instanceof and islnstance( ) produce exactly the same results, as do equals( ) and ==.But the tests themselves draw different conclusions. In keeping with the concept of type, instanceof says, "Are you this class, or a class derived from this class?" On the other hand, if you compare the actual Class objects using ==, there is no concern with inheritance—it's either the exact type or it isn't.
Reflection: runtime
class information
particular machine, so the machine becomes a common repository describing those actions, and it can be easily changed to affect everyone in the system.(This is an interesting development, since the machine exists solely to make software changes easy!) Along these lines, distributed computing also supports specialized hardware that might be good at a particular task—matrix inversions, for example—but inappropriate or too expensive for general-purpose programming.
import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.io.Serializable;public class WriteObjectToFile {public static void main(String[] args) throws FileNotFoundException, IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myObject"));oos.writeObject(new MyObject());oos.flush();oos.close();}}class MyObject implements Serializable{private static final int INSTANCE = 10;public void printInstance(Integer i){System.out.println(INSTANCE + i);}}
import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.ObjectInputStream;import java.lang.reflect.Method;public class ReadObjectFromFile {public static void main(String[] args) throws FileNotFoundException, IOException, Exception {ObjectInputStream iis = new ObjectInputStream(new FileInputStream("myObject"));Object o = iis.readObject();Method m = o.getClass().getMethod("printInstance", Integer.class);m.invoke(o,1);//Assumption that I don't know anything,for example,method name,method parameter typeMethod[] ms = o.getClass().getDeclaredMethods();for(Method mt : ms){String methodName = mt.getName();Class<?>[] classs = mt.getParameterTypes();for(Class c : classs){if(c.equals(Integer.class)){mt.invoke(o, 11);}}}}}
其实上如果你没有这个类是绝对调用不了其中的方法的
public interface MyInterface {public void printInstance(Integer i);}
import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.io.Serializable;public class WriteObjectToFile {public static void main(String[] args) throws FileNotFoundException, IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myObject"));oos.writeObject(new MyObject());oos.flush();oos.close();}}class MyObject implements Serializable,MyInterface{private static final int INSTANCE = 10;public void printInstance(Integer i){System.out.println(INSTANCE + i);}}
import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.ObjectInputStream;import java.lang.reflect.Method;public class ReadObjectFromFile {public static void main(String[] args) throws FileNotFoundException, IOException, Exception {ObjectInputStream iis = new ObjectInputStream(new FileInputStream("myObject"));MyInterface o = (MyInterface)iis.readObject();o.printInstance(10);}}
现在就是有一个问题,在你编译的时候你没有这个.class文件,后来在运行的过程中从网络上或者是数据库中接收到了某个.class文件,你要怎么加载进来呢?
- Type information
- Type Information
- Type information
- Type Information笔记
- 关于runtime type information
- VC 调试Error in OMF type information
- C++ typeid 与RTTI(Runtime Type Information)
- 第22章:run time type information
- C++中的RTTI(runtime type information) 机制
- Thinking in Java笔记:Runtime Type Information
- 关于“error in OMF type information”的问题
- Automatic Query Type Identification Based on Click Through Information
- 41.windbg-调试技巧(解决Type information missing error for)
- RTTI(runtime type information Identification) 运行时类型识别
- C++ - RTTI(RunTime Type Information)运行时类型信息 详解
- Cast from pointer to smaller type 'int' loses information
- Cast from pointer to smaller type 'int' loses information
- Cast from pointer to smaller type 'int' loses information解决方案
- 实战 SSH 端口转发
- 3Sum
- MINA2官方教程翻译 2.x与1.x的变化
- 版本管理:Git 使用起步(二) Repo
- 找到单向链表中间那个元素,如果有两个则取前面一个
- Type Information
- “识时务者为俊杰”------hao123峰会给渠道商们的启示
- 黑马程序员 jsp乱码,sevlet乱码,struts乱码,tomcat乱码,get乱码,post乱码 解决方式
- 基于mina的websocket初步实现
- 惠普将于六月份发布商用型3D打印机
- 爱上,就别问情深情浅
- 用HTML制作用户注册网页
- 栈和队列
- varchar和Nvarchar区别