1、概述 反射的基础class类。
Java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class。
Java中Class类代表着一类事物,它的实例就是类对象;其中Class类对应着java中的类而它的示例就对应着各个类在内存中的字节码;当一个类被类加载器加载到内存中就会占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以他们在空间中的内容也是不同的,而这一个个的空间 可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型就是Class 。
反射:就是把java类中的各种成分映射成相应的java类。
反射机制
• 指的是可以在运行时加载、探知、使用编译期间完全未知的类 。
• 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性 ;
Class c = Class.forName("com.bjsxt.test.User");
•加载完类之后,在堆内存中,就产生了一个 Class类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子 看到类 的结构,所以,我们形象的称之为:反射。
Class类介绍
java.lang.Class类十分特殊,用来表示java中类型(class/interface/enum/annotation /primitive type/void)本身。
•Class类的对象包含了某个被加载类的结构。一个被加载的类对应一个Class对象。
•当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。
•Class类是Reflection的根源。
•针对任何您想动态加载、运行的类,唯有先获得相应的Class 对象
Class类的对象如何获取?
•对象.getClass();
•Class.forName(“类名”);(最常被使用)
•类名.class;
static Class<?> forName(String className) 返回与带有给定字符串名的类或接口相关联的 Class 对象。
static Class<?> forName(String name, boolean initialize, ClassLoader loader) 使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象。
九个预定义 Class实例对象
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void。
即:只要在源程序中出现的类型都有各自的Class实例对象。
2、常用方法
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。故:不可以new对象。
得到各个字节码对应的实例对象(Class类型)的方法。
1、 类名.class; Class a = Systemclass;
2、 对象.getClass(); Class a = new Date().getClass();
3、 Class.forName(“类名”); Class a = Class forName(“java.util.Date”);
Boolean isPrimitive();判定指定的 Class 对象是否表示一个基本类型。
Field getField(String name);获取此类的公共成员字段。
Method[] getMethods();获取此类的公共成员方法
String getName()
Package getPackage();获取此类的包。
Constructor<T> getConstructor(Class<?>...parameterTypes) 获取此类的构造函数
不论一个类被创建多少的实例,但是一个类只对应一个Class对象
2.1、通过反射获取类的名字的常用方法
public T newInstance()创建此 Class 对象所表示的类的一个新实例。
其实是调用无参构造方法,故:每个类必须要有无参的构造方法!
String forName()
String getName() :获得包名+类名
String getSimpleName() :获得类名
2.2、通过反射获取属性信息的常用方法
java.lang.reflect.Field
set(反射的实力对象,预设的数值);
get(反射的实例对象);
public void setAccessible (boolean flag)为true则取消语言访问检查。
Field getField() 只能获得public的一个field
Field[] getFields() 获得public的所有field。
Field getDeclaredField() 只能获得一个field(包含私有成员)
Field[] getDeclaredFields() 获得所有的field(包含私有成员)
2.3、通过反射获取方法信息的常用方法
java.lang.reflect.Method
Object invoke(Object obj, Object... args) 激活此功能
Method getMethod("setUname", String.class)
只能获得public的一个Method
Method[] getMethods("setUname", String.class)
获得public的所有Method。
Method getDeclaredMethod()获得所有的一个Method(包含私有成员)
Method[] getDeclaredMethods()获得所有的Method(包含私有成员)
////如果方法有参,则必须传递参数类型对应的class对象
2.4、通过反射获得构造器信息的常用方法
java.lang.reflect.Constructor
Constructor<T> getConstructor(Class<?>... parameterTypes)
只能获得public的一个Constructor
Constructor<?>[] getConstructors()获得public的所有Constructor。
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获得所有的一个Constructor(包含私有成员)
Constructor<?>[] getDeclaredConstructors()
获得所有的Constructor(包含私有成员)
注:当获取预操作的类的属性和方法以后,若想使用该方法或属性,则必须使用方法newInstance创建实例后才可以操作
2.5、数组的反射
数组类型:只有数组的维数和类型不同时Class对象才不同。
2.5.1 用反射的方式调用主函数
主函数是String类型的数组。
正常的方法为:类名.main(new String[]{“111”,“111”,“111”});
反射方法如下所示:
String ClassName = mainName;
Method mainMetod
= Class.forname(ClassName).getMethod(main,string[].class);
mainMethod.invoke(null,new string[]{“111””222””333”}拆包);
(这个对象必须改成new String[](new string[]{“111””222””333”}),或者(String)new string[]{“111””222””333”}后,参数类型才可以)
2.5.2 数组与Object的关系及其反射类型
String类型的数组的父类全是Object。而其他类型数组int父类不是Object
只有数组的维数和类型不同时Class对象才不同。
方法Arrays.asList(Object obj):将数组转换成List集合;1.4版本是接受Object类型的数组,1.4版本以后是(T…a)其中Object类型的数组可以直接接收;若是int类型的数组则无法接收;
数组类型:只有数组的维数和类型不同时Class对象才不同。
2.5.3数组的反射应用
代码实例://不知道数组类名的时候的打印方法
Public static void printObject(Object obj)
{
Class clazz = obj.getClass();
If(clazz.isArray) //是数组就拆包
{
Int len = Array.getLength(obj);
For(int i=0;i<len;i++)
System,out.println(Array.get(obj,i));
}
Else
System,out.println(obj);
}
如何得到数组的类型:Object[] a = new Object[](“a”,1);
用一个元素a[0].getClass().getName();即可的到数组类型
2.5.4 ArrayList_HashSet的比较及Hashcode分析
ArrayList:可重复的有序数组;依据方法equals();
HashSet: 不可重复没有顺序哈希;依据方法先hashCode()和后equals();
注意:当一个对象被存储进HashSet集合中以后,就不能修改这个对象了,如若修改则这个对象的哈希就会改变,它在该集合中的存储位置就会改变,这是就找不到这个对象了,也就无法对其进行删除或者其他操作这种情况称作:内存泄露。
2.6、反射技术开发框架的原理
框架以及框架要解决的核心问题:
例如:开发商卖房子给住户,用户自己安装门窗和空调,则房子就是框架,用户需要使用框架房子,将门窗安装到开发商提供的房子框架中。框架和工具类有区别:工具类被用户调用,而框架是调用用户提供的类。
但是我开发框架的时候还没有用户我怎么去调用他的类呢?这时就用反射;将用户的类反射到配置文件中,而框架只需要读取配置文件即可。
3、反射的效率问题
•setAccessible
启用和禁用访问安全检查的开关,值为true则指示反射的对象在使用时应该取消Java语言访问检查。值为false则指示反射的对象应该实施 Java 语言访问检查。并不是为true就能访问为false就不能访问。禁止安全检查,可以提高反射的运行速度。
反射的开发效率很高,但是运行效率很低,一把比正常代码慢30倍左右,禁止安全检查时则会提高4倍运行效率 。System.currentTimeMillis();
反射的优点:大大加强了代码的扩展性。 反射的缺点:效率不高,比较消耗资源。
4、反射与正常使用类的区别
1、一般在我们正常使用类的时候一般都是new一个对象,new的意思是:先知道类的名称根据被new的类的名称找寻该类的字节码文件,并加载进内存,然后创建该字节码文件对象,接着创建该字节文件的对应的Person对象;反射也是遵循着个思路就是表现形式不同。
2、在我们正常使用类的时候只要new一个此类的实例化对象即可,使用这种方法时,我们必须要先知道这个类的名字然后才去new对象。但是当我们不知道这个类名字的时候,或者说我们在写程序的时候还不知道要调用的类存不存在,而且我们写完的源代码已经封装完毕不允许被改变这时怎么办呢?这时就要用到反射机制。
|
|