Type information (2): Class Object (lower)

First, the class literals

    Java also provides another method for generating a reference to the Class object, i.e., the use of letter like constant. The above procedure is like this: FancyToy.class.

    This is not only easier, and more secure, because it would be checked at compile time (and therefore do not need to put the try block). It eradicated and the forName call () method, so it is more efficient.

    Class literal can be applied not only to an ordinary class, it may be applied to an interface, and an array of basic data types. Further, the basic data type of wrapper classes, there is a standard fields TYPE. TYPE field is a reference to the basic data types of corresponding Class object, as follows:

Equivalent to
boolean.class Boolean.TYPE
char.class Character.TYPE
byte.class Byte.TYPE
short.class Short.TYPE
int.class Integer.TYPE
long.class Long.TYPE
float.class Float.TYPE
double.class Double.TYPE
void.class Void.TYPE

    I suggest using the form ".class" to maintain consistency with the general class.

    Note that there is very interesting, when you create a reference to the Class object using the ".class", it does not automatically initialize the Class object. In order to use the class to do the preparatory work actually involves three steps:

  1. Loading, which is performed by a class loader. This step finds the byte code (generally designated classpath lookup path, but this is not necessary), and creates a Class object from these bytecodes.
  2. link. The class byte code verification, allocates storage for a static field, and, if necessary, it will resolve references to all other classes at the link stage this class is created.
  3. initialization. If the class has a superclass, then initializing it, and performing static initialization static initializer block.

    Initialization is delayed until the static method (constructor implicitly static) if you are performing or non-constant static field for the first time reference:

import java.util.Random;

class Initable {
	static final int staticFinal = 47;
	static final int staticFinal2 = ClassInitialization.r.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 = 47;

	static {
		System.out.println("Initializing Initable3");
	}
}

public class ClassInitialization {
	public static Random r = new Random();

	public static void main(String[] args) throws ClassNotFoundException {
		Class initable = Initable.class;
		System.out.println("After creating Initable ref");
		System.out.println(Initable.staticFinal);
		System.out.println(Initable.staticFinal2);
		System.out.println(Initable2.staticNonFinal);
		Class initable3 = Class.forName("Initable3");
		System.out.println("After creating Initable3 ref");
		System.out.println(Initable3.staticNonFinal);
	}
}

    Initialization effectively as possible to achieve the "inert." We can see from the creation of initable references, only .class syntax to obtain a reference to a class does not cause initialization. However, in order to produce Class references, Class.forName () immediately initialized, as in the creation of initable3 referenced see.

    If a static final value is "compile-time constants," as Initable.staticFinal so, then this value does not need to Initable class is initialized it can be read. However, if only one field is set to static and final, it is not enough to ensure that such behavior, for example, access to Initable.staticFinal2 will be forced to initialize the class, because it is not a compile-time constants.

    If a static domain is not final, then when you access it, always required before it is read, the first link (for the domain space allocation) and initialization (initialized the storage space), as in for Initable2. access staticNonFinal's have seen.

Second, the generalization of Class references

    Class reference always refers to a Class object instance of the class can be manufactured, and contains all the code applied to the method of these examples. It also contains a static member of the class, therefore, Class reference the exact type of object it points to is the representation of an object while the object is the Class class.

    However, java SE5 designers spotted the opportunity, it's some type of more concrete, and this is by allowing you referenced Class object type pointed to the Class limit is achieved, where the use of generics grammar. In the example below, both syntax is correct:

public class GenericClassReferences {
	public static void main(String[] args) {
		Class intClass = int.class;
		Class<Integer> genericIntClass = int.class;
		genericIntClass = Integer.class;
		intClass = double.class;
		// genericIntClass = double.class;
	}
}

    Normal class references will not produce a warning message, you can see that, despite the generic class reference can only be assigned to type referred to in its statement, but normal class references can be reassigned to point to any other Class object. By using generic syntax allows the compiler to enforce additional type checking.

    If you want to relax a little some of these restrictions, how should we do it? At first glance, it seems you should be able to perform such an operation similar to the following:

Class<Number> genericNumberClass = int.class;

    It seems to be functioning, because Integer inherit from Number. But it does not work, because Integer Class Number object is not a subclass of Class objects. In order to ease restrictions in the use of generalization Class references, I use a wildcard, which is part of java generics. Wildcard is "?" For "anything." Thus, we can add a wildcard in the embodiment of ordinary Class references, and produce the same result:

public class WildcardClassReferences {
	public static void main(String[] args) {
		Class<?> intClass = int.class;
		intClass = double.class;
	}
}

    In the java SE5, Class <?> Better than ordinary Class, even if they are equivalent, and ordinary Class As you can see, does not produce a compiler warning messages. Class <?> Benefit is that it means that you are not by chance or due to negligence, and uses a non-specific class references, you is to choose a non-specific version.

    In order to create a Class references, it is limited to a certain type, or the type of any sub-type, you will need a wildcard and extends keyword combined to create a range. Therefore, the only statement Class <Number> different now make the following statement:

public class BoundedClassRenferences {
	public static void main(String[] args) {
		Class<? extends Number> bounded = int.class;
		bounded = double.class;
		bounded = Number.class;
	}
}

    The reason generics syntax to add a reference to the Class merely to provide compile-time type checking, so if you make a mistake, immediately you will find it later. In reference to the use of ordinary Class, you will not go astray, but if you do make a mistake, then until runtime you will find it, and this is very inconvenient.

    The following example uses the generic grammar classes, it stores a reference to class, and produces a List later, is filled using the List object newInstance () method is generated by this reference:

import java.util.ArrayList;
import java.util.List;

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<>();
		for (int i = 0; i < nElements; i++)
			try {
				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));
	}
}

    Note that this class must be assumed that any type of work it together have a default constructor (no-argument constructor), and if it does not meet the conditions, you will get an exception. The compiler does not generate any warning messages for the program.

    When you generic syntax for the Class object, a very interesting thing happens: newInstance () will return the exact type of the object, not just seen in ToyTest.java basic Object. This to some extent, some restrictions:

public class GenericToyTest {
	public static void main(String[] args) throws InstantiationException, IllegalAccessException {
		Class<FancyToy> ftClass = FancyToy.class;
		FancyToy fancyToy = ftClass.newInstance();
		Class<? super FancyToy> up = ftClass.getSuperclass();
		// Class<Toy> up2 = ftClass.getSuperclass();
		Object obj = up.newInstance();
	}
}

    If your hand is a super class that the compiler will only allow you to declare a superclass reference is "a class, it is FancyToy superclass", as in the expression Class <? Super FancyToy> seen, and We will not accept Class <Toy> such a statement. This seems a bit strange, because getSuperClass () method returns the base class (not an interface), and the compiler at compile time to know what type it is - and that is, in this case, rather than Toy.class-- just "a class, it is FancyToy superclass." In any case, it is precisely because of this ambiguity, up.newInstance () return value is not an exact type, but only Object.

Third, a new transformation grammar

    java SE5 also adds syntax transformation for Class references that cast () method:

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;
	}
}

    Cast () method takes a parameter object, and the type of transformation as referenced Class. Of course, if you look at the above code, you will find that, compared with the realization of the main () function is the same as the last line, this transformation seems to do a lot of extra work. Type of transformation grammar is very useful when not using the common transformation, when you write generic code, if you store a Class references, and hope that through this reference to perform the transformation, this situation will occur. This proved to be a rare case.

    In another java SE5 no useful new feature is Class.asSubclass (), which allows you to transition to a more specific class object types.

If this article is very helpful to you, please also like to look at.

Published 112 original articles · won praise 2 · views 10000 +

Guess you like

Origin blog.csdn.net/qq_40298351/article/details/104669018