反射(三)-------要想使用我,先要获取我的引用。

通过上两节的介绍,我们已经知道:当要使用某个类时,JVM的类加载器会根据类名找到对应的.class文件,类加载器读取.class文件的内容,并根据该内容在内存中创建一个Class对象,这个Class对象包含了类的全部信息。

看到这里有些小伙伴们激动的说:既然Class对象包含了类的全部信息,那么Class类中肯定有很多方法是用来获取和设置对象类型的吧,我们快去查查Java API文档吧!

这时Class突然从API文档中跳出来,愤怒的大叫:你们这帮傻X,现在看我能干啥有个毛用!你要想用哥,先去研究研究怎么获取哥的引用好不,不然你拿毛来和我通信啊?

Class跷起二郎腿继续说道:其实哥的对象和其它普通对象是一样滴,如果你要调用一个对象的方法,是不是要通过这个对象的引用啊?同理,你要调用哥的对象的方法,也要通过哥的对象的引用。

有三种方法可以获取Class对象的引用,下面分别介绍。

场景一:

当你的程序正在内存中欢快的运行时,突然socket接收到一连串的字节流数据,并被告知这堆字节数据就是Xxx类的.class文件数据,你快去构造一个Xxx类的对象,这样你能成大事。——我擦!!成你妹啊!老子现在都已经被编译好并在内存中运行了,你现在才给我这个.class文件,已经晚了!!!Socket内牛满面的说:sorry啊,可是在你编译的时候,我还没有这个.class文件啊,我怎么才能给你啊!!

正当大家都一筹莫展的时候,Class类发话了:擦!小时一桩啊,哥来帮你们解决这个问题。哥有一个静态方法叫做forName,你只要把类的名字以String的形式告诉它,并且可以在ClassPath的指引下找到对应的.class文件,forName就可以把这个类加载到内存,并为其产生Class对象,然后将Class对象的引用作为返回值交给你们。是不是很牛X啊!好吧,哥给你们看个例子。

public class Test
{
	public static void main(String[] args) throws ClassNotFoundException
	{
		Scanner scan = new Scanner(System.in);
		String className = scan.nextLine();
		Class clazz = Class.forName(className);
	}
}
这个程序在运行时接受用户的输入字符串作为类的名字,然后调用Class的静态方法forName加载这个类。好比说有一个类A的.class文件正躺在ClassPath的某个路径下。类A的源代码如下:

class A
{
	static
	{
		System.out.println("AAAAAA");
	}
}
用户在终端输入数据A,可以从输出结果中看到,类A被加载了,并且clazz变量保存着类A的Class对象的引用。

poype

但是你除了告诉我要加载类的名字以外,你还要保证类的.class文件可以在ClassPath路径下被找到,如果找不到对应的.class文件,那我只能翻脸抛出ClassNotFoundException异常了。擦的!告诉我名字,我却找不到对应的.class文件,你TMD逗我玩呢?做事小心点,别逼我翻脸啊!!!!

拿到了一个类的Class对象的引用,就相当于你获得了这个类的全部信息,当然可以构造这个类的对象实例啦!我有一个成员方法叫newInstance,调用这个方法就可以构造相关类的实例对象。我们稍微更改一下上面的代码继续看个例子。

import java.util.*;

public class Test
{
	public static void main(String[] args) 
		throws ClassNotFoundException,InstantiationException,IllegalAccessException
	{
		Scanner scan = new Scanner(System.in);
		String className = scan.nextLine();
		Class clazz = Class.forName(className);
		Object obj = clazz.newInstance();//构造实例对象
		System.out.println(obj);
	}
}

class A
{
	static
	{
		System.out.println("AAAAAA");
	}
	public String toString()
	{
		return "I am A";
	}
}

从输出结果中看以看到,已经构造了类A的实例对象。

总结一下:Class类中有一个静态方法forName,这个方法可以在程序运行期间动态的加载类Xxx产生Class对象,然后通过Class对象的newInstance方法就可以构造Xxx的对象实例了。

场景二:

你已经拥有了一个感兴趣的类型的对象,想要知道这个对象的类型信息,那就可以通过调用对象的getClass方法获取Class对象的应用了。getClass方法是在Object类中定义的,这也就是说,在Java的世界中,任何对象都具有这个方法。下面是一个相关例子和输出结果:

import java.util.*;

public class Test
{
	public static void main(String[] args) 
		throws ClassNotFoundException,InstantiationException,IllegalAccessException
	{
		A a = new A();
		Class clazz = a.getClass();//通过getClass方法获取Class对象的引用
		Object o = clazz.newInstance();
		System.out.println(o);
	}
}

class A
{
	static
	{
		System.out.println("AAAAAA");
	}
	public String toString()
	{
		return "I am A";
	}
}


场景三、类字面常量

Java还可以使用类字面常量的方式来生成对Class对象的引用,对上面的例子来说就是A.class就是类A的Class对象的引用。这种方式更加简单,而且因为没有方法调用,所以效率会高一些。

import java.util.*;

public class Test
{
	public static void main(String[] args) 
		throws ClassNotFoundException,InstantiationException,IllegalAccessException
	{
		Class clazz = A.class; //获取Class对象的应用
		Object o = clazz.newInstance();
		System.out.println(o);
	}
}

class A
{
	static
	{
		System.out.println("AAAAAA");
	}
	public String toString()
	{
		return "I am A";
	}
}

总结:只要你想在运行时获取类型信息,那么第一个想法就是我该如何获取到Class对象的引用,可以通过上面3中方式的任意一种。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值