您的位置:首页 > 职场人生

黑马程序员——反射

2015-09-20 09:15 405 查看

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

}

-------android培训java培训、期待与您交流!
---------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: