-------android培训、java培训、期待与您交流! -----------
反射的基石--->Class类
java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class
对比提问:众多的人用一个什么类表示?众多的java类用一个什么类表示?
人--->Person
java类--->Class
对比提问:Person类代表人,它的实例对象就是张三、李四这样一个个具体的人,
Class类代表Java类,它的各个实例对象又分别对应什么呢?
对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的
字节码等等
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容
就是类的字节码,不同类得字节码是不同的,所以他们在内存中的内容是不同
的,这一各个的空间可分别用一个个的对象来表示,这些对象显然具有相同的
类型,这个类型是什么呢?
如何得到各个字节码对应的实例对象(Class类型)
类名.class 例如:System.class;
对象.getClass() 例如:new Date().getClass();
Class.forName("类名") 例如:Class.forName("java.util.Data");
九个预定义Class实例对象
参看Class.isPrimitive方法的帮助
int.class == Integer.TYPE
数组类型的Class实例对象
Class.isArray()
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如:int[],void.
Java类用于描述一类事物的共性,给类事物有什么属性,没有什么属性,至于这个
属性的值是什么,则是由这个类得实例对象来确定的,不同的实例对象有不同的属性
值,Java程序中的各个Java类,它们是否属于同一类事物,是不是可以用一个类来
描述这类事物呢?这个类的名字就是Class,要注意与小写class关键字的区别,Class
类描述了哪些方面的信息呢?类的名字,类的访问属性,类所属于的包名,字段名称
的列表、方法名称的列表,等等,学习反射,首先就要明白Class这个类
反射
反射就是吧Java类中的各种成分映射成相应的java类。例如,一个Java类中
用一个Class类的对象类表示,一个类中的组成部分:成员变量,方法,构造方法
包等等信息也用一个个Java类来表示,就像汽车是一个类,汽车中的发动机,
变速箱等等也是一个个的类。表示java类的class类显然要提供一系列的方法,
来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类
的实例对象来表示,他们是 Field Method Contructor Package等等
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。通过调用
Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?
这正是学习和应用反射的要点
Constructor类
Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
例 Constructor[] constructors=Class.forName("java.lang.String").getConstructors();
得到某一个构造方法:
例 Constructor[] constructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class);
//获得方法时要用到类型
创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式:String str = (String)constructor.newlnstance(new StringBuffer("abc"));
//调用获得的方法时要用到上面相同类型的实例对象
Class.newInstance()方法:
例 String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是怎样写的呢?用到了缓冲机制来保存默认构造方法的实例对象
Field类
Field类代表某个类中的一个成员变量
演示用eclipse自动生成Java类的构造方法
问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,
而该类的实例对象有多个,如果是与对象关联,那关联的是哪个对象呢?所以字段fieldX代表的是
X的定义,而不是具体的x变量。
String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
System.out.println(cls1==cls2);//true
System.out.println(cls1==cls3);//true
//说明cls1 cls2 cl3 指向同一个字节码
System.out.println(cls1.isPrimitive());//false 判断是否是基本数据类型
System.out,println(int.class.isPrimitive())//true 是基本数据类型
System.out.println(int.class==Integer.class)//false
//int是基本数据类型,Integer是基本数据类型包装类,它包装了int,
//他们俩的字节码不是一个,而每个包装类型都包含它所包装的类型的字节码
System.out.println(int.class==Integer.TYPE);//true
//Integer里定义的常量TYPE,就是获取所包装的基本数据类型的字节码的
System.out.println(int[].class.isPrimitive());//false 数组类型不是基本数据类型
System.out.println(int[].class.isArray());//true isArray()判断此字节码是不是数组
//new String(new StringBuffer("abc"));
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String)constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str2.charAt(2));//打印角标为2的字符
/*
获取字节码文件的三种方式:
1,Object类中的getClass方法。
想要用这种方式,必须要明确具体的类,并创建对象。麻烦
*/
public static void getClassObject_1()
{
Person p = new Person();
Class clazz = p.getClass();
Person p1 = new Person();
Class clazz1 = p1.getClass();
System.out.println(clazz==clazz1);
}
/*
2,如何数据类型都具备一个静态的属性.class来获取其对应的Class对象
相对简单,但是还是要明确用到类中的静态成员,还是不够扩展
*/
public static void getClassObject_2()
{
Class clazz = Person.class;
Class clazz1 = Person.class;
System.out.println(clazz==clazz1);
}
/*
3,只要通过给定的类的字符串名称就可以获取该类,更为扩展
可以用Class类中的方法完成,该方法就是forName
这种方式只要有名称即可,开发时以这种方式为主
*/
public static void getClassObject_3()throws ClassNotFoundException
{
String className = "Person";//此处类名一定要明确所在包,完整的字符串是“包名.类名”
Class clazz = Class.forName(className);//抛出类灭有找到异常
System.out.println("className="+clazz);
}
//1,通过空参数构造函数创建对象
public static void createNewObject()throws Exception
{
//早期:new对象的时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,
//并创建该类的字节码文件对象,并接着创建该字节码文件的对应的Person对象
Person p = new Person();
//现在:
//给定一个类的字符串名称
String name = "Person";
//找寻该名称的类文件,并加载进内存,产生Class对象
Class clazz = Class.forName(name);
//如何产生该字节码文件的类的对象呢?
Object obj = clazz.newInstance();
}
//2,通过有参数的构造函数创建对象
public static void createNewObject_2() throws Exception
{
/*
当获取指定名称对应类中的所体现的对象时
而该对象初始化不使用空参数构造该怎么办呢
既然是通过指定的构造函数进行对象的初始化
所以应该先获取到该构造函数,通过字节码文件对象即可完成
该方法是:getConstructor(paramterTypes);
*/
//早期:
//Person p = new Person("小强",39);
//现在
String name = "Person";
//找寻该名称类文件,并加载进内存,产生Class对象
Class clazz = Class.forName(name);
//获取到指定的构造函数对象
Constructor constructor = clazz.getConstructor(String.class, int.class);
//通过该构造器对象的newInstance方法进行对象的初始化
Object obj = constructor.newInstance("小明",38);
}
//获取字节码文件中的字段
public static void getFieldDemo()throws Exception
{
Class clazz = Class.forName("Person");
//clazz.getField("字段名");//只能获取本类的共有字段
Field field = clazz.getDeclaredField("age");//获取本类字段,包括私有
//因为age是私有的,想要获取其值就要下面那样
//对私有字段的访问取消权限检查,称为暴力访问
field.setAccessible(true);
//拿到了字段之后,要用对象来操作字段
Object obj = clazz.newInstance();
//通过类的对象(obj)设置字段值
field.set(obj,89);
//通过类的对象(obj)获取字段值,返回Object
Object o = field.get(obj);
System.out.println(o);
}
//获取指定Class中的所有公共函数
public static void getMethodDemo()throws Exception
{
Class clazz = Class.forName("Person");
//clazz.getMethods();//获取共有的所有方法
Method[] methods = clazz.getDeclaredMethods();//只获取本类中的所有方法
for(Method method : methods)
{
System.out.println(method);
}
}
//调用无参数的一般方法
public static void getMethodDemo_2()throws Exception
{
Class clazz = Class.forName("Person");
//指定方法名和参数列表,show方法参数为空
Method method = clazz.getMethod("show",null);
//方法运行需要对象
//Object obj = clazz.newInstance();
Constructor constructor = clazz.getConstructor(String.class,int.class);
Object obj = constructor.newInstance("小明",37);
//运行方法时指定所属对象,与参数列表
method.invoke(obj,null);
}
//调用有参数的一般方法
public static void getMethodDemo_3()throws Exception
{
Class clazz = Class.forName("Person");
Method method = clazz.getMethod("paramMethod",String.class,int.class);
Object obj = clazz.newInstance();
method.invoke(obj,"小强",89);
}