类型信息

前言:最近学习状态好像是有点差的,又是联盟又是我的世界。想上白金,上不去,玩我的世界一玩就是没日没夜,终于,在女朋友的威逼利诱下,拿起了上上个礼拜看得第十四章,果然,上次什么都没看进去。

类在使用前要经历三步骤:

1.加载

加载是有类加载器完成的,加载器会检查这个类的Class对象是否被创建,如果没有,则会根据类名查找.class文件并且创建一个Class对象。java中,所有的类都是在对其第一次引用时,动态的加载到JVM中的,当程序创建第一个对类的静态成员的引用的时候,就会加载这个类。(构造器也是类的静态方法)

2.链接

在链接阶段将会验证类中的字节码,为静态域分配空间,并且将解析这个类创建的其他类的所有引用

3.初始化

如果这个类有父类,则对其父类初始化,执行静态初始化器和静态初始化块。初始化被延迟到了对静态方法,或者非常数静态域进行首次引用才执行。

一、什么是Class类。

Class类也是类的一种,java里面所有的类在加载到JVM时都会创建一个Class类的对象(可以简单的理解为,所有类都是Class类的对象)。(区别于关键字class,这里的Class类为大写),Class类里面拥有许多方法,诸如:getName(),getSimpleName(),isInterface(),forName(),getCanonicalName(),getSuperclass(),getInterface(),newInstance()。

扫描二维码关注公众号,回复: 2999642 查看本文章


二、Class类的具体用法

其中,getName(),和getCanonicalName()返回的均为全限定类名,即包名.类名。getSimpleName()返回不包含包名的类名。isInterface()返回该类是否为接口(返回值为Boolean),forName()方法传入一个字符串,返回一个该字符串指向的类Class对象,该字符串为你要使用的类的全限定名,形如:Class c =Class.forName("typinfo.toys.FancyToy")。注意,forName语句要被try,catch包裹起来。

newInstance()功能类似于new,但是newInstance()要求使用newInstance()创建的类必须带有默认构造器。事实上,new是相当于Class.forName(),和newInstance()方法的结合,Class.forName()方法是初始化,newInstance是实例化。具体参考下面这篇文章:

点我

三、为什么要有Class类

Class类记录了类的信息,一旦某个类的Class对象被载入内存,它就会被用来创建这个类的所有对象。

四、类字面常量(.class)

可以通过Object.class语法来获取一个类对Class对象的引用。,这种语法相对于通过Class.forName()方法来说,更加简单也更为安全,因为在编译时就会收到检查,所以它无需被包裹在try_catch语句中,此外,.class不仅可以适用于普通的类,也可以应用于接口,数组,基本数据类型。调用.class产生对Class对象的引用的时候,并不会引发初始化(java编程思想里面原话为:并不会自动的初始化该Class对象,而探讨得知,文中所说的初始化,就是我所要产生的类对象的那个类的初始化,下面的代码能证明这点),这一点不同于Class.forName()方法,后者,会立即进行初始化:

package p563;
import java.util.*;
 class Initable {
	static Random rand =new Random();
	static final int staticFinal =47;
	static final int staticFinal2=rand.nextInt(1000);
	static{
		System.out.println("Initalizing Initable");
	}
}
 class Initable2{
	 static int staticNoFinal=21;
	 static{
		 System.out.println("Initalizing Initable2");
	 }
 }
 class Initable3{
	 static int staticNoFinal =74;
	 static{
		 System.out.println("Initalizing Initable3");
	 }
 }
 public class ClassInitalization{
	 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.staticNoFinal);//会引发
		Class initable3 =Class.forName("p563.Initable3");//会引发,调用Class.forName()方法会立即引发初始化
		System.out.println("After creating Initable3 ref");
		System.out.println(Initable3.staticNoFinal);//会引发
	}
// }output:
//	 After creating Initable ref
//	 47
//	 Initalizing Initable
//	 563
//	 Initalizing Initable2
//	 21
//	 Initalizing Initable3
//	 After creating Initable3 ref
//	 74


 

五、泛化的Class引用

1.泛化Class引用的特点:

Class intClass =int.class;
	Class<Integer> InteClass=int.class;
	Class<?>aClass=int.class;
	InteClass=Integer.class;
	//InteClass=double.class;报错,无法这样做
	intClass=double.class;
	aClass=double.class;

普通的类的引用在可以指向任何的Class对象,并不会报错,这里InteClass先是指向了int,后来又指向了double。这样的话,在实际程序中容易出现错误,而泛化的Class引用则不允许指向其他类型的Class对象,如上面InteClass=double.class就会报错,同时,引用了通配符“?”的泛化Class引用则可以先后指向不同的类型。这样的相比较于直接的引用则更为合理。(在定义时,你就设置他为非具体类型的引用,相比较于直接的Class引用则能够减少许多的不可预期的错误)

事实上,Class引用添加泛型语法仅仅是为了提供编译期类型检查。

2.当newInstance()与泛化Class引用

当泛化Class引用使用newInstance()创建实例时,newInstance()返回的是该对象的具体类型,而不是Object类。

FancyToy fancyToy =ftClass.newInstance();//这里创建的实例就是具体的FancyToy类的对象
	Class<?super FancyToy>up =ftClass.getSuperclass();//只允许这一种超类引用,而且这种超类引用的出得是Object的对象,而不是具体的Toy
	//Class<Toy>up2=ftClass.getSuperclass();无法这么做
	Object obj=up.newInstance();

这种返回具体类型的特性,在用作超类时则不起作用,编译器只允许声明超类引用是“某个类,它是某个类的超类”就像这里的“<?super FancyToy>”,也正是因为这种含糊性导致up.newInstance()返回的不是精确类型,而是Object。

猜你喜欢

转载自blog.csdn.net/qq_41791653/article/details/80366703
今日推荐