天天看点

【反射学习总结(上)】

【一】Class类是什么样的类?

【二】Class类中包含了一些什么样的具体东西?

【三】定义Class类常用的三种方法是什么?

【四】Class类对象中的原始类有几种,分别是什么?

【五】反射的基本定义,和Class类的具体关系是怎样的?

首先

【一】:对Class类的定义:

我是这样理解的,我们知道:对于java中一些基本数据类型,都可以用数组来存放;对于类对象呢,我们可以用集合来存放;数组和集合都可以比作成为一种形象直观的容器,只要把分类好的东西丢进去就OK了,就相当于现实生活中:装液态东西的容器可以是瓶子,而装固体的是框子的原理!

那么这里的Class类,具体又是什么呢?它既不是瓶子,也不是框子,它其实就是现实生活中的描述这些液体,固体,瓶子,框子等等的一个统一的“物体类”。它的功能很强大,它承载着上述事物的具体共性:这个“物体类”包含了实体的名称,实体的范围,实体的属性!

所以:在JAVA中也就不难以理解了:java中的Class类:是描述JAVA中各个类为同一类事物的这样一个类

它的内容也很丰富:它的成分中包含了各类的名称,各类的类属性,各类所属的包名,各类的字段名称,各类的方法名称等等……再说得形象点吧:我们常用的自定义Person类,String类,Collection接口中的类,这些等等都是属于Class类吧!

【二】:所以对于其Class包含了什么,通过上述知道:简单一句话,就是包含JAVA中各类的各项共同成分的一个大空间。当然空间并不是零乱的,它主要有各类的包名称列表,方法名称列表,字段名称列表等等!

【三】:定义Class类常用的三种方式:也就是让Class类实例化的一种表现形式:

(1)类名.class 例如:

Class clss=String.class;

我的分析过程:我们知道:当一个类通过加载器加载到内存中的时候,它自动占用了内存中的一片储存空间,该空间中的内容就是该类的字节码,当然,不同的类有着不同的字节码文件。换句话说:就是该内存空间中的内容具体是不一样的,我们把这个内存空间用一个具体的对象来表示,这对象就是Class类的具体实例化!它可以是String类的空间,也可以是集合的空间,甚至可以是自定义类的空间,要确定这个空间,也就是要明确该对象:我们就要做到一个具体的实例化才行,这里如果知道了具体的类,直接用字节码就OK了!

(2)通过第一种创建方式之后,就能够理解第二种了

那就是:对象名称.getClass();这样理解对简单:就是既然该类对象都已经存在了,那么直接通过对象就能找到属于Class类的一个实例了:

例如:new String("abc").getClass();

(3)还有第三种方式:主要是把完整的类名目录作为参数传递给JVM,简单一点,就是在告诉JVM这个类的具体地址,包名是不行的,必须是具体的开发中具体的路径!

例如:Class clss=Class.forName("java.util.regex.WkzTestDemo");

具体实例可以看我写的代码:注意通过在java api帮助文档中的学习发现:这里的第三种方法会抛出异常,要处理掉才行!

例如:

<span style="font-size:18px;">/*
关于Class类获取其对象的三种方法:
*/
class ReflectDemo1 
{
	public static void main(String[] args) 
	{
		
		String str="wkzcrytal";
		Class cls1=str.getClass(); //第二种方法

		Class cls2=String.class; //第一种方法
		Class cls3=null;
		try
		{
			cls3=Class.forName("java.lang.String");//这里用的String类型,所以forName中就用引入其java内部的地址就OK
		}
		catch (ClassNotFoundException e)
		{
		}
		
		sop(cls1==cls2); //true
		sop(cls2==cls3); //true
	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}</span>
           

【四】对于Class类中对基本的原始类有几种:

Class类的原始类:一共有九种:8中是基本的数据类型,大家都知道,还有一种就是void类型

通过学习了,我们知道:在Class类中:

Class类的实例有一个重要的判断是不是原始类的方法.Class实例.IsPrimitive();返回内容是boolean类型,是就是true,不是就是false

例如就是以上面的代码继续:

<span style="font-size:18px;">/*
关于Class类获取其对象的三种方法:
该类对象中原始的基本数据类型对象
*/
class ReflectDemo1 
{
	public static void main(String[] args) 
	{
		
		String str="abc";
		Class cls1=str.getClass();

		Class cls2=String.class;
		Class cls3=null;
		try
		{
			cls3=Class.forName("java.lang.String");
		}
		catch (ClassNotFoundException e)
		{
			
		}
		
		sop(cls1==cls2); //true
		sop(cls2==cls3); //true
		
		//void字节码是不是原始的数据类型对象
		sop(void.class.isPrimitive()); //true,因为在9种中,有void的基本数据类型对象
		sop(int.class.isPrimitive()); //true
		sop(int[].class.isPrimitive()); //false
		sop(String.class.isPrimitive()); //false
		sop(cls1.isPrimitive()); //false
		
		sop(int.class==Integer.TYPE);
		//true  组成Integer的基本数据类型对象是不是int.class


		sop(int.class==Integer.class);//false
	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}</span>
           

【五】知道了上面的内容,现在反射就非常好理解了:

反射就是:把各个java类中的成分全部映射到相应的java类中来。

例如:java类中的基本方法,映射到一个java类是:Method类

  java类中的构造方法,映射到一个java类是:Constructor类

 还有很多,例如类中的成员变量类:Field类等等……很多!

       话不多说:实例来啦:

<span style="font-size:18px;">/*
演示:通过反射的思想得到指定类中带参数的构造方法去创建新的指定对象
用反射的思想去完成str的对象创建
String str=new String(new StringBuffer("abc"));
构造方法的类:Constructor
重点:
1.获取构造函数类对象,很关键(编译时段)
2.得到类构造函数是,还得把参数从新传入(运行时段)
*/
import java.lang.reflect.*;
class ReflectDemo2 
{
	public static void main(String[] args) throws Exception
	{
		//这是用反射的机制去是做通过得到类的实例之后,再调用其方法
		//下面是通过实例获取了String类中带StringBuffer类型参数的构造方法
		Constructor cons=String.class.getConstructor(StringBuffer.class);
		//创建一个string的实例对象(通过该构造方法对象new出一个具体的实例来)
		String str=(String)cons.newInstance(new StringBuffer("abc"));

		//上述两句相当于String str=new String(new StringBuffer("abc"));
		System.out.println(str); //abc
	}
}
</span>
           

重点:其实就是通过反射机制来完成一些所映射类中方法的调用等等……

再例如实例:下面是一个自定义的类,通过反射的机制获取其类中的成员变量,【注意】类中的成员变量有私有的情况,应该怎样解决!

/*
演示通过反射得到自定义类中的成员变量
成员变量类:Field
*/
import java.lang.reflect.*;
class PointTest
{
	private int x;
	public  int y;
	int z;

	PointTest(int x,int y)
	{
		this.x=x;
		this.y=y;
	}

	PointTest(int x,int y,int z)
	{
		this(x,y);
		this.z=z;
	}
}

class ReflectDemo3 
{
	public static void main(String[] args) throws Exception 
	{
		PointTest pt=new PointTest(3,9,6);

		//通过反射获取成员变量y的方法:这里是public修饰
		//这里的y是public修饰时,能得到,如果不写修饰符号,也不能得到
		//所以,我们知道这种方法只针对public有效
		Field fieldY=pt.getClass().getField("y");
		int new_y=(int)fieldY.get(pt);//直接获取
		System.out.println("y="+new_y); //

		//通过反射获取成员变量x的方法:这里是private修饰
		Field fieldX=pt.getClass().getDeclaredField("x");//获取所有申明的字段x
		fieldX.setAccessible(true);//强制访问才能得到
		int new_x=(int)fieldX.get(pt);
		System.out.println("x="+new_x);
		
		//对于没有修饰符的,直接得到所有申明的字段z就行
		Field fieldZ=pt.getClass().getDeclaredField("z");
		int new_z=(int)fieldZ.get(pt);//不用强制方法得到
		System.out.println("z="+new_z);
	}
}
           

注意其中private修饰的成员变量:应该用全部被声明的方法才能获取到该Field的实例对象,通过这个Field类的实例对象,将其设置为强制访问之后,才能通过get方法在被映射的实例对象中获取到相应的成员变量值!

继续阅读