------- android培训、java培训、期待与您交流!----------
反射
一.类加载器
1.类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化
加载
就是指将class文件读入内存,并为之创建一个Class对象.任何类被使用时系统都会建立一个Class对象
连接:接阶段又可以分为三个子步骤:验证,准备和解析
验证:是否有正确的内部结构,确保java类型数据格式的正确性,并适于JVM使用
准备:负责为类的静态成员分配内存,并设置默认初始化值
解析:解析过程就是在类型的常量池中寻找类,接口,字段和方法的符号引用,把这些符号引用替换成直接引
用.这个阶段可以被推迟到初始化之后,当程序运行的过程中真正使用某个符号引用的时候再去解析它
类初始化时机
1)创建类的实例
2)访问类的静态变量,或者为静态变量赋值
3)调用类的静态方法
4)使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5)初始化某个类的子类
6)直接使用java.exe命令来运行某个主类
2.类加载器
含义:负责将.class文件加载到内在中,并为之生成对应的Class对象
类加载器的组成及作用
Bootstrap ClassLoader 根类加载器:也被称为引导类加载器,负责Java核心类的加载.比如System,String等.在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader 扩展类加载器:负责JRE的扩展目录中jar包的加载.在JDK中JRE的lib目录下ext目录
Sysetm ClassLoader 系统类加载器:负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
二.反射
1.概述
反射机制:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法.对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
反射技术:其实就是动态加载一个指定的类,并获取该类中的所有的内容,而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员.简单说:反射技术可以对一个类进行解剖
反射的好处:大大的增强了程序的扩展性
2.反射的基本步骤:
获得Class对象,就是获取到指定的名称的字节码文件对象.
实例化对象,获得类的属性.方法或构造函数
访问属性,调用方法,调用构造函数创建对象
3.获取Class对象的三种方式:
每一个类对象都有一个静态的属性class,弊端:必须要先明确该类.如果是明确地获得某个类的Class对象可以用此方式,主要用于传参
Class clazz = Person.class;
通过每个对象都具备的方法getClass来获取.弊端:必须要创建该类对象,才可以调用getClass方法.如果拿到了对象,不知道是什么类型可以用此方式,用于获得对象的类型
Object obj = new Person();
Class clazz1 = obj.getClass();
使用的Class类中的方法,静态的forName方法.指定什么类名(完整的类名),就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可,用于类加载
String classname = “cn.itcast.reflect.Person”;
Class clazz = Class.forName(classname);//当类的字节码已经加载进了内存,就将该字节码返回;如果jvm还没有该字节码,就用类加载器加载,再返回加载的字节码
前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成
三种方式得到的字节码都是同一个字节码:
代码演示:
<strong><span style="font-family:SimHei;font-size:14px;">[java] view plaincopy
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 </span></strong>
4.九个预定义的Class:
1)包括八种基本类型(byte;short;int;long;float;double;char;boolean)的字节码对象和一种返回值为void类型的void.class
2)Integer.TYPE是Integer类的一个常量,它代表此包装类型包装的基本类型的字节码,所以和int.class是相等的.基本数据类型的字节码都可以用与之对应的包装类中的TYPE常量表示
3)只要是在源程序中出现的类型都有各自的Class实例对象,如int[].class.数组类型的Class实例对象,可以用Class.isArray()方法判断是否为数组类型的
5.反射的使用:
Class类
1)类中的方法,不包括获取成员属性及方法对象
static Class forName(String className):返回与给定字符串名的类或接口的相关联的Class对象
Class getClass():返回的是Object运行时的类;即返回Class对象即字节码对象
String getName():以String形式返回此Class对象所表示的实体名称
String getSuperclass():返回此 Class 所表示的实体(类;接口;基本类型或 void)的超类的 Class
boolean isArray():判定此Class对象是否表示一个数组
boolean isPrimitive():判断指定的Class对象是否是一个基本类型
2)通过Class对象获取类实例
如:
String className="包名.Person";
Class clazz=Class.forName(className);
Object obj=clazz.newInstance();
反射获取成员方法并使用:
获取所有方法:
Method[] getMehtods():返回一个包含某些Method对象的数组.是所代表的的类中的公共成员方法
Method[] getDeclareMethods():返回Method 对象的一个数组,这些对象反映此Class 对象表示的类或接口声明的所有方法,包括公共;保护;默认(包)访问和私有方法,但不包括继承的方法
获取单个方法:
Method getMethod(String name,Class<?>… parameterTypes):返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法
Method getDeclaredMethod(String name,Class<?>… parameterTypes):返回一个Method 对象,该对象反映此Class 对象所表示的类或接口的指定已声明方法.name 参数是一个String,它指定所需方法的简称,parameterTypes 参数是Class 对象的一个数组,它按声明顺序标识该方法的形参类型
使用方法:Method类方法
void setAccessible(boolean)方法:值为true时取消 Java 语言访问检查
Object invoke(Object obj ,参数);//调用对象的method方法
代码演示:
[java] view plaincopy
[java] view plaincopy
package itcast;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* @author oyfc
*/
public class MethodDemo {
/**
* 通过反射获取成员方法并使用。
* @param args
* @throws ClassNotFoundException
*/
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception {
<span style="white-space:pre"> </span>//获取字节码文件对象
<span style="white-space:pre"> </span>String className = "itcast.Person";
<span style="white-space:pre"> </span>Class class1 = Class.forName(className);
<span style="white-space:pre"> </span>//创建对象
<span style="white-space:pre"> </span>Constructor constructor = class1.getConstructor(String.class,int.class);
<span style="white-space:pre"> </span>Object object = constructor.newInstance("zhangfei",21);
<span style="white-space:pre"> </span>//获取所有成员方法
<span style="white-space:pre"> </span>Method[] methods = class1.getDeclaredMethods();
<span style="white-space:pre"> </span>for(Method meth: methods){
<span style="white-space:pre"> </span>sop(meth);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>//获取成员方法
<span style="white-space:pre"> </span>Method method = class1.getDeclaredMethod("show");
<span style="white-space:pre"> </span>//暴力访问
<span style="white-space:pre"> </span>method.setAccessible(true);
<span style="white-space:pre"> </span>//调用方法
<span style="white-space:pre"> </span>method.invoke(object, null);
<span style="white-space:pre"> </span>}
/**
* @param method
*/
<span style="white-space:pre"> </span>private static void sop(Object object) {
<span style="white-space:pre"> </span>System.out.println(object);
<span style="white-space:pre"> </span>}
}
反射类的构造函数并使用:
获取所有构造方法:
Constructor<?>[] getConstructors()返回一个包含某些Constructor 对象的数组,这些对象反映此Class 对象所表示的类的所有公共构造方法.
Constructor<?>[] getDeclaredConstructors()返回Constructor 对象的一个数组,这些对象反映此Class 对象表示的类声明的所有构造方法.它们是公共、保护、默认(包)访问和私有构造方法
获取单个构造方法:
Constructor<T> getConstructor(Class<?>...parameterTypes):返回一个Constructor 对象,它反映此Class 对象所表示的类的指定公共构造方法
Constructor<T> gettDeclaredConstructor():
使用方法:Constructor类的方法
T newInstance(Object ... initargs)):创建此Class对象所表示的类的一个新实例
代码演示:
[java] view plaincopy
</pre>程序示例:</p><p><span style="font-size:18px;"></span><pre name="code" class="java">[java] view plaincopy
package itcast;
import java.lang.reflect.Constructor;
/**
* 通过反射获取构造方法并使用。
*
* @author oyfc
*/
<span style="white-space:pre"> </span>public class ConstructorDemo {
/**
* @param args
* @throws Exception
*/
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception {
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>// 获取字节码文件对象
<span style="white-space:pre"> </span>String className = "itcast.Person";
<span style="white-space:pre"> </span>Class class1 = Class.forName(className);
<span style="white-space:pre"> </span>// 获取所有所有公共构造方法
<span style="white-space:pre"> </span>// Constructor[] constructors = class1.getConstructors();
<span style="white-space:pre"> </span>// 获取所有所有构造方法
<span style="white-space:pre"> </span>Constructor[] constructors = class1.getDeclaredConstructors();
<span style="white-space:pre"> </span>for (Constructor con : constructors) {
<span style="white-space:pre"> </span>sop(con);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>//获取无参构造方法
<span style="white-space:pre"> </span>Constructor constructor = class1.getDeclaredConstructor();
<span style="white-space:pre"> </span>//取消访问检查,暴力访问
<span style="white-space:pre"> </span>constructor.setAccessible(true);
<span style="white-space:pre"> </span>//创建对象
<span style="white-space:pre"> </span>Object object = constructor.newInstance();
<span style="white-space:pre"> </span>sop(object);//null::0
<span style="white-space:pre"> </span>//获取有参构造方法
<span style="white-space:pre"> </span>Constructor constructor2 = class1.getDeclaredConstructor(String.class);
<span style="white-space:pre"> </span>//创建对象
<span style="white-space:pre"> </span>Object object2 = constructor2.newInstance("张飞");
<span style="white-space:pre"> </span>sop(object2);//张飞::0
<span style="white-space:pre"> </span>}
/**
* @param con
*/
<span style="white-space:pre"> </span>private static void sop(Object obj) {
<span style="white-space:pre"> </span>System.out.println(obj);
<span style="white-space:pre"> </span>}
}
反射类的成员变量并使用:
获取所有成员:
Field[] getFields():返回包含某些Field对象的数组,表示所代表类中的成员字段
Field[] getDeclaredFields():
获取单个成员:
Field getField(String name):返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段
Field getDeclaredField(String name)
修改成员的值:Field类的方法
set(Object obj,Object value):将指定对象变量上此 Field 对象表示的字段设置为指定的新值
代码演示:
<strong><span style="font-family:SimHei;font-size:14px;">[java] view plaincopy
[java] view plaincopy
Field field = clazz.getField(fieldName);//获取指定的字段值
field.setAccessible(true);//取消访问检查,也称暴力访问
field.set(obj,value);//将指定对象变量上此 Field 对象表示的字段设置为指定的新值.
//如:
[java] view plaincopy
[java] view plaincopy
package itcast;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
* @author oyfc
*/
public class FieldDemo {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//获取字节码文件对象
String className = "itcast.Person";
Class class1 = Class.forName(className);
//创建实例对象
Constructor constructor = class1.getConstructor(String.class,int.class);
Object object = constructor.newInstance("张非",21);
//获取所有成员变量
// Field[] fields = class1.getDeclaredFields();
// for(Field field:fields) {
// sop(field);
// }
//获取单个成员变量
Field field = class1.getField("name");
//为指定变量赋值
field.set(object, "xiaozhang");
sop(object);//xiaozhang::21
}
/**
* @param field
*/
private static void sop(Object object) {
System.out.println(object);
}
} </span></strong>
6.数组的反射
1)每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组属于同一个类型,即都共享该 Class 对象
2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class
3)基本数据类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用;非基本数据类型的一维数组既可以当做Object类型使用,有可以当做object[]类型使用
代码演示:
<span style="font-family:SimHei;">[java] view plaincopy
public class ReflectTest {
public static void main(String[] args) throws Exception {
int [] a1 = new int[]{1,2,3};
int [] a2 = new int[4];
int[][] a3 = new int[2][3];
String [] a4 = new String[]{"a","b","c"};
System.out.println(a1.getClass() == a2.getClass());//true
System.out.println(a1.getClass() == a4.getClass());//false
System.out.println(a1.getClass() == a3.getClass());//false
System.out.println(a1.getClass().getName());//[I
System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object
System.out.println(a4.getClass().getSuperclass().getName());//java.lang.Object
Object aObj1 = a1;
Object aObj2 = a4;
//Object[] aObj3 = a1;//错误
Object[] aObj4 = a3;
Object[] aObj5 = a4;
System.out.println(a1);//打印的是变量a1的值,不是数组的值[I@1cfb549
System.out.println(a4);
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));
}</span>
4)Arrays.asList()方法处理int[]和String[]时的差异
static List asList(T… a)// 返回一个受指定数组支持的固定大小的列表.(对返回列表的更改会“直接写”到数组)
System.out.println(Arrays.asList(a1));//[[I@1cfb549]
System.out.println(Arrays.asList(a4));//[a,b,c]
5)Array工具类用于完成对数组的反射操作
Array 类提供了动态创建和访问 Java 数组的方法
static Object get(Object array,int index)//返回指定数组对象中索引组件的值,如果该值是一个基本类型值,则自动将其包装在一个对象中.array - 数组,index - 索引
static int getLength(Object array) //以 int 形式返回指定数组对象的长度
代码演示:
<strong>[java] view plaincopy
<span style="white-space:pre"> </span>private static void printObject(Object obj) {
<span style="white-space:pre"> </span>Class clazz = obj.getClass();
<span style="white-space:pre"> </span>if(clazz.isArray()){
<span style="white-space:pre"> </span>int len = Array.getLength(obj);
<span style="white-space:pre"> </span>for(int i=0;i<len;i++){
<span style="white-space:pre"> </span>System.out.println(Array.get(obj, i));
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}else{
<span style="white-space:pre"> </span>System.out.println(obj);
<span style="white-space:pre"> </span>}
} </strong>
7.反射的作用:实现框架的功能
框架与工具类有区别,工具类被用户的类调用,而框架式调用用户提供的类
在写框架时,用户可能还不存在,那么我写的框架程序怎么调用用户以后写的类.因为在写程序时无法知道要被调用的类名,所有在程序中无法直接new某个类的实例对象,要用到反射方式
采用配置文件加反射的方式创建ArrayList和HashSet的实例对象
代码演示:
<strong><span style="font-family:SimHei;">[java] view plaincopy
<span style="white-space:pre"> </span>public class ReflectTest2 {
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception{
<span style="white-space:pre"> </span>//InputStream ips = new FileInputStream("config.properties");
<span style="white-space:pre"> </span>//查找资源,类加载器,配置文件放在classpath的目录下
<span style="white-space:pre"> </span>//InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");
<span style="white-space:pre"> </span>//相对该类包的路径,写相对路径
<span style="white-space:pre"> </span>//InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
<span style="white-space:pre"> </span>//在classpath的根目录下找,必须从根开始写绝对路径
<span style="white-space:pre"> </span>InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
<span style="white-space:pre"> </span>Properties props = new Properties();
<span style="white-space:pre"> </span>props.load(ips);
<span style="white-space:pre"> </span>ips.close();
<span style="white-space:pre"> </span>String className = props.getProperty("className");
<span style="white-space:pre"> </span>//Collection collections = new HashSet();
<span style="white-space:pre"> </span>Collection collections = (Collection)Class.forName(className).newInstance();
<span style="white-space:pre"> </span>}
} </span></strong>
版权声明:本文为博主原创文章,未经博主允许不得转载。
反射
一.类加载器
1.类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化
加载
就是指将class文件读入内存,并为之创建一个Class对象.任何类被使用时系统都会建立一个Class对象
连接:接阶段又可以分为三个子步骤:验证,准备和解析
验证:是否有正确的内部结构,确保java类型数据格式的正确性,并适于JVM使用
准备:负责为类的静态成员分配内存,并设置默认初始化值
解析:解析过程就是在类型的常量池中寻找类,接口,字段和方法的符号引用,把这些符号引用替换成直接引
用.这个阶段可以被推迟到初始化之后,当程序运行的过程中真正使用某个符号引用的时候再去解析它
类初始化时机
1)创建类的实例
2)访问类的静态变量,或者为静态变量赋值
3)调用类的静态方法
4)使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5)初始化某个类的子类
6)直接使用java.exe命令来运行某个主类
2.类加载器
含义:负责将.class文件加载到内在中,并为之生成对应的Class对象
类加载器的组成及作用
Bootstrap ClassLoader 根类加载器:也被称为引导类加载器,负责Java核心类的加载.比如System,String等.在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader 扩展类加载器:负责JRE的扩展目录中jar包的加载.在JDK中JRE的lib目录下ext目录
Sysetm ClassLoader 系统类加载器:负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
二.反射
1.概述
反射机制:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法.对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
反射技术:其实就是动态加载一个指定的类,并获取该类中的所有的内容,而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员.简单说:反射技术可以对一个类进行解剖
反射的好处:大大的增强了程序的扩展性
2.反射的基本步骤:
获得Class对象,就是获取到指定的名称的字节码文件对象.
实例化对象,获得类的属性.方法或构造函数
访问属性,调用方法,调用构造函数创建对象
3.获取Class对象的三种方式:
每一个类对象都有一个静态的属性class,弊端:必须要先明确该类.如果是明确地获得某个类的Class对象可以用此方式,主要用于传参
Class clazz = Person.class;
通过每个对象都具备的方法getClass来获取.弊端:必须要创建该类对象,才可以调用getClass方法.如果拿到了对象,不知道是什么类型可以用此方式,用于获得对象的类型
Object obj = new Person();
Class clazz1 = obj.getClass();
使用的Class类中的方法,静态的forName方法.指定什么类名(完整的类名),就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可,用于类加载
String classname = “cn.itcast.reflect.Person”;
Class clazz = Class.forName(classname);//当类的字节码已经加载进了内存,就将该字节码返回;如果jvm还没有该字节码,就用类加载器加载,再返回加载的字节码
前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成
三种方式得到的字节码都是同一个字节码:
代码演示:
<strong><span style="font-family:SimHei;font-size:14px;">[java] view plaincopy
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 </span></strong>
4.九个预定义的Class:
1)包括八种基本类型(byte;short;int;long;float;double;char;boolean)的字节码对象和一种返回值为void类型的void.class
2)Integer.TYPE是Integer类的一个常量,它代表此包装类型包装的基本类型的字节码,所以和int.class是相等的.基本数据类型的字节码都可以用与之对应的包装类中的TYPE常量表示
3)只要是在源程序中出现的类型都有各自的Class实例对象,如int[].class.数组类型的Class实例对象,可以用Class.isArray()方法判断是否为数组类型的
5.反射的使用:
Class类
1)类中的方法,不包括获取成员属性及方法对象
static Class forName(String className):返回与给定字符串名的类或接口的相关联的Class对象
Class getClass():返回的是Object运行时的类;即返回Class对象即字节码对象
String getName():以String形式返回此Class对象所表示的实体名称
String getSuperclass():返回此 Class 所表示的实体(类;接口;基本类型或 void)的超类的 Class
boolean isArray():判定此Class对象是否表示一个数组
boolean isPrimitive():判断指定的Class对象是否是一个基本类型
2)通过Class对象获取类实例
如:
String className="包名.Person";
Class clazz=Class.forName(className);
Object obj=clazz.newInstance();
反射获取成员方法并使用:
获取所有方法:
Method[] getMehtods():返回一个包含某些Method对象的数组.是所代表的的类中的公共成员方法
Method[] getDeclareMethods():返回Method 对象的一个数组,这些对象反映此Class 对象表示的类或接口声明的所有方法,包括公共;保护;默认(包)访问和私有方法,但不包括继承的方法
获取单个方法:
Method getMethod(String name,Class<?>… parameterTypes):返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法
Method getDeclaredMethod(String name,Class<?>… parameterTypes):返回一个Method 对象,该对象反映此Class 对象所表示的类或接口的指定已声明方法.name 参数是一个String,它指定所需方法的简称,parameterTypes 参数是Class 对象的一个数组,它按声明顺序标识该方法的形参类型
使用方法:Method类方法
void setAccessible(boolean)方法:值为true时取消 Java 语言访问检查
Object invoke(Object obj ,参数);//调用对象的method方法
代码演示:
[java] view plaincopy
[java] view plaincopy
package itcast;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* @author oyfc
*/
public class MethodDemo {
/**
* 通过反射获取成员方法并使用。
* @param args
* @throws ClassNotFoundException
*/
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception {
<span style="white-space:pre"> </span>//获取字节码文件对象
<span style="white-space:pre"> </span>String className = "itcast.Person";
<span style="white-space:pre"> </span>Class class1 = Class.forName(className);
<span style="white-space:pre"> </span>//创建对象
<span style="white-space:pre"> </span>Constructor constructor = class1.getConstructor(String.class,int.class);
<span style="white-space:pre"> </span>Object object = constructor.newInstance("zhangfei",21);
<span style="white-space:pre"> </span>//获取所有成员方法
<span style="white-space:pre"> </span>Method[] methods = class1.getDeclaredMethods();
<span style="white-space:pre"> </span>for(Method meth: methods){
<span style="white-space:pre"> </span>sop(meth);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>//获取成员方法
<span style="white-space:pre"> </span>Method method = class1.getDeclaredMethod("show");
<span style="white-space:pre"> </span>//暴力访问
<span style="white-space:pre"> </span>method.setAccessible(true);
<span style="white-space:pre"> </span>//调用方法
<span style="white-space:pre"> </span>method.invoke(object, null);
<span style="white-space:pre"> </span>}
/**
* @param method
*/
<span style="white-space:pre"> </span>private static void sop(Object object) {
<span style="white-space:pre"> </span>System.out.println(object);
<span style="white-space:pre"> </span>}
}
反射类的构造函数并使用:
获取所有构造方法:
Constructor<?>[] getConstructors()返回一个包含某些Constructor 对象的数组,这些对象反映此Class 对象所表示的类的所有公共构造方法.
Constructor<?>[] getDeclaredConstructors()返回Constructor 对象的一个数组,这些对象反映此Class 对象表示的类声明的所有构造方法.它们是公共、保护、默认(包)访问和私有构造方法
获取单个构造方法:
Constructor<T> getConstructor(Class<?>...parameterTypes):返回一个Constructor 对象,它反映此Class 对象所表示的类的指定公共构造方法
Constructor<T> gettDeclaredConstructor():
使用方法:Constructor类的方法
T newInstance(Object ... initargs)):创建此Class对象所表示的类的一个新实例
代码演示:
[java] view plaincopy
</pre>程序示例:</p><p><span style="font-size:18px;"></span><pre name="code" class="java">[java] view plaincopy
package itcast;
import java.lang.reflect.Constructor;
/**
* 通过反射获取构造方法并使用。
*
* @author oyfc
*/
<span style="white-space:pre"> </span>public class ConstructorDemo {
/**
* @param args
* @throws Exception
*/
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception {
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>// 获取字节码文件对象
<span style="white-space:pre"> </span>String className = "itcast.Person";
<span style="white-space:pre"> </span>Class class1 = Class.forName(className);
<span style="white-space:pre"> </span>// 获取所有所有公共构造方法
<span style="white-space:pre"> </span>// Constructor[] constructors = class1.getConstructors();
<span style="white-space:pre"> </span>// 获取所有所有构造方法
<span style="white-space:pre"> </span>Constructor[] constructors = class1.getDeclaredConstructors();
<span style="white-space:pre"> </span>for (Constructor con : constructors) {
<span style="white-space:pre"> </span>sop(con);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>//获取无参构造方法
<span style="white-space:pre"> </span>Constructor constructor = class1.getDeclaredConstructor();
<span style="white-space:pre"> </span>//取消访问检查,暴力访问
<span style="white-space:pre"> </span>constructor.setAccessible(true);
<span style="white-space:pre"> </span>//创建对象
<span style="white-space:pre"> </span>Object object = constructor.newInstance();
<span style="white-space:pre"> </span>sop(object);//null::0
<span style="white-space:pre"> </span>//获取有参构造方法
<span style="white-space:pre"> </span>Constructor constructor2 = class1.getDeclaredConstructor(String.class);
<span style="white-space:pre"> </span>//创建对象
<span style="white-space:pre"> </span>Object object2 = constructor2.newInstance("张飞");
<span style="white-space:pre"> </span>sop(object2);//张飞::0
<span style="white-space:pre"> </span>}
/**
* @param con
*/
<span style="white-space:pre"> </span>private static void sop(Object obj) {
<span style="white-space:pre"> </span>System.out.println(obj);
<span style="white-space:pre"> </span>}
}
反射类的成员变量并使用:
获取所有成员:
Field[] getFields():返回包含某些Field对象的数组,表示所代表类中的成员字段
Field[] getDeclaredFields():
获取单个成员:
Field getField(String name):返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段
Field getDeclaredField(String name)
修改成员的值:Field类的方法
set(Object obj,Object value):将指定对象变量上此 Field 对象表示的字段设置为指定的新值
代码演示:
<strong><span style="font-family:SimHei;font-size:14px;">[java] view plaincopy
[java] view plaincopy
Field field = clazz.getField(fieldName);//获取指定的字段值
field.setAccessible(true);//取消访问检查,也称暴力访问
field.set(obj,value);//将指定对象变量上此 Field 对象表示的字段设置为指定的新值.
//如:
[java] view plaincopy
[java] view plaincopy
package itcast;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
* @author oyfc
*/
public class FieldDemo {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//获取字节码文件对象
String className = "itcast.Person";
Class class1 = Class.forName(className);
//创建实例对象
Constructor constructor = class1.getConstructor(String.class,int.class);
Object object = constructor.newInstance("张非",21);
//获取所有成员变量
// Field[] fields = class1.getDeclaredFields();
// for(Field field:fields) {
// sop(field);
// }
//获取单个成员变量
Field field = class1.getField("name");
//为指定变量赋值
field.set(object, "xiaozhang");
sop(object);//xiaozhang::21
}
/**
* @param field
*/
private static void sop(Object object) {
System.out.println(object);
}
} </span></strong>
6.数组的反射
1)每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组属于同一个类型,即都共享该 Class 对象
2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class
3)基本数据类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用;非基本数据类型的一维数组既可以当做Object类型使用,有可以当做object[]类型使用
代码演示:
<span style="font-family:SimHei;">[java] view plaincopy
public class ReflectTest {
public static void main(String[] args) throws Exception {
int [] a1 = new int[]{1,2,3};
int [] a2 = new int[4];
int[][] a3 = new int[2][3];
String [] a4 = new String[]{"a","b","c"};
System.out.println(a1.getClass() == a2.getClass());//true
System.out.println(a1.getClass() == a4.getClass());//false
System.out.println(a1.getClass() == a3.getClass());//false
System.out.println(a1.getClass().getName());//[I
System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object
System.out.println(a4.getClass().getSuperclass().getName());//java.lang.Object
Object aObj1 = a1;
Object aObj2 = a4;
//Object[] aObj3 = a1;//错误
Object[] aObj4 = a3;
Object[] aObj5 = a4;
System.out.println(a1);//打印的是变量a1的值,不是数组的值[I@1cfb549
System.out.println(a4);
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));
}</span>
4)Arrays.asList()方法处理int[]和String[]时的差异
static List asList(T… a)// 返回一个受指定数组支持的固定大小的列表.(对返回列表的更改会“直接写”到数组)
System.out.println(Arrays.asList(a1));//[[I@1cfb549]
System.out.println(Arrays.asList(a4));//[a,b,c]
5)Array工具类用于完成对数组的反射操作
Array 类提供了动态创建和访问 Java 数组的方法
static Object get(Object array,int index)//返回指定数组对象中索引组件的值,如果该值是一个基本类型值,则自动将其包装在一个对象中.array - 数组,index - 索引
static int getLength(Object array) //以 int 形式返回指定数组对象的长度
代码演示:
<strong>[java] view plaincopy
<span style="white-space:pre"> </span>private static void printObject(Object obj) {
<span style="white-space:pre"> </span>Class clazz = obj.getClass();
<span style="white-space:pre"> </span>if(clazz.isArray()){
<span style="white-space:pre"> </span>int len = Array.getLength(obj);
<span style="white-space:pre"> </span>for(int i=0;i<len;i++){
<span style="white-space:pre"> </span>System.out.println(Array.get(obj, i));
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}else{
<span style="white-space:pre"> </span>System.out.println(obj);
<span style="white-space:pre"> </span>}
} </strong>
7.反射的作用:实现框架的功能
框架与工具类有区别,工具类被用户的类调用,而框架式调用用户提供的类
在写框架时,用户可能还不存在,那么我写的框架程序怎么调用用户以后写的类.因为在写程序时无法知道要被调用的类名,所有在程序中无法直接new某个类的实例对象,要用到反射方式
采用配置文件加反射的方式创建ArrayList和HashSet的实例对象
代码演示:
<strong><span style="font-family:SimHei;">[java] view plaincopy
<span style="white-space:pre"> </span>public class ReflectTest2 {
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception{
<span style="white-space:pre"> </span>//InputStream ips = new FileInputStream("config.properties");
<span style="white-space:pre"> </span>//查找资源,类加载器,配置文件放在classpath的目录下
<span style="white-space:pre"> </span>//InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");
<span style="white-space:pre"> </span>//相对该类包的路径,写相对路径
<span style="white-space:pre"> </span>//InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
<span style="white-space:pre"> </span>//在classpath的根目录下找,必须从根开始写绝对路径
<span style="white-space:pre"> </span>InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
<span style="white-space:pre"> </span>Properties props = new Properties();
<span style="white-space:pre"> </span>props.load(ips);
<span style="white-space:pre"> </span>ips.close();
<span style="white-space:pre"> </span>String className = props.getProperty("className");
<span style="white-space:pre"> </span>//Collection collections = new HashSet();
<span style="white-space:pre"> </span>Collection collections = (Collection)Class.forName(className).newInstance();
<span style="white-space:pre"> </span>}
} </span></strong>
版权声明:本文为博主原创文章,未经博主允许不得转载。