packagecn.sxt.t01;import static org.junit.Assert.*;importjava.lang.reflect.Constructor;importjava.lang.reflect.Method;importjava.util.Date;importjava.util.Iterator;importorg.junit.Test;public classClassTest01 {private staticDate getObject;/*反射:(reflection):在运行时期,动态地去获取类中的信息(类的信息,方法信息,构造器信息,字段等信息进行操作);
一个类中包含的信息有: 构造器,字段,方法
如何使用反射描述这些相关的信息
Class : 描述类
Method : 描述方法
Constructor :描述构造器
Field :描述字段
**/@Testpublic void testName() throwsException {//编译类型//运行类型(真实类型)
Object obj = newjava.util.Date();//需求:根据对象obj调用Date类中的一个方法,toLocaleString,如何来做?//方案一: 强转
Date d =(Date)obj;
System.out.println(d.toLocaleString());
}//方案二: 使用反射
publicObject getObject() {return newjava.util.Date();
}
@Test//获取类的Class实例三种方式
public void testName1() throwsException {/** 在任何反射的操作之前,都必须先获取某一个类的字节码实例,任何一个类在jvm有且只有一份字节码实例
*
* 获取字节码实例有三种方式
* 1. 类名.class;
* 2. 对象.getClass();
* 3. Class.forName("类的全限定名");
* 全限定名 = 包名+类名
**/
//需求:获取User类的字节码实例//1. 类名.class;
Class clz1=Users.class;
System.out.println(clz1);//2. 对象.getClass();
Users users=newUsers();
Class> clz2=users.getClass();
System.out.println(clz2);//3. Class.forName("类的全限定名");//全限定名 = 包名+类名
Class> clz3 = Class.forName("cn.sxt.t01.Users");
System.out.println(clz3);
}
@Test//获取九大内置类的字节码实例
public void testName2() throwsException {/*对于对象来说,可以直接使用对象.getClass()或者Class.forName(className); 类名.class都可以获取Class实例.
但是我们的基本数据类型,就没有类的权限定名,也没有getClass方法.
问题: 那么如何使用Class类来表示基本数据类型的Class实例?
八大基本数据类型和 void关键字都是有 字节码实例的
byte,short,int,long,char,float,double,boolean ,void关键字
答 : 数据类型/void.class 即可
每个基本数据类型都是包装类型 如 :int ----Integer包装类型
注意: 基本数据类型和包装数据类型底层的字节码实例是不相同*/
//数据也是一种数据类型,也需要单独获取字节码实例 Class clz = 数据类型[].class//获取8大基本数据类型和void的字节码实例(以int,integer为列)//1.获取int类型的字节码实例
Class> intClz=int.class;
System.out.println(intClz);//其他七种基本数据类型 和 第一种相似....//获取void的字节码实例
Class > voidClz=void.class;
System.out.println(voidClz);//所有的基本数据类型都有包装类型//int---Integer//int 和Integer 的字节码是绝对不相等的
Class integeClz=Integer.class;
System.out.println(integeClz);
System.out.println(intClz== integeClz);//false//直接通过数组类型获取字节码实例
Class clz1=int[].class;
System.out.println(clz1);//定义一个数据
int[] arr1 = { 1, 2, 3, 5};
Class clz2=(Class)arr1.getClass();
System.out.println(clz2);//定义一个数据
int[] arr2 = { 10, 2, 3, 5};//3.获取arr1数组的字节码实例
Class clz3 = (Class) arr2.getClass();
System.out.println(clz3);
System.out.println(clz1== clz2);//true
System.out.println(clz3 == clz2);//true//所以不同数组的字节码实例是相同的
}
@Testpublic void testName3() throwsException {/*类的构函数有 有参数构造函数,无参构造函数,公共构造函数,非公共构造函数,根据不同的构造函数 Class提供了几种获取不同构造函数的方法
*
*
* 获取Users类的构造器
*
* 1.获取Users类的字节码实例
* 2.获取Users对应的构造器*/
//1.获取Users类的字节码实例
Class stu=Users.class;//2.获取所有的公共构造器
Constructor>[] constructors =stu.getConstructors();for(Constructor>constructor:constructors){
System.out.println(constructor);
}//3.获取所有的构造器(和访问权限无关)
Constructor>[] de =stu.getDeclaredConstructors();for(Constructor>constructor : de){
System.out.println(constructor);
}//4.获取指定的构造器(公共的)getConstructor
Constructor constructor1 = stu.getConstructor(String.class);
System.out.println(constructor1);//5. getDeclaredConstructor 获取和访问权限无关构造器
Constructor constructor2 = stu.getDeclaredConstructor(String.class,Integer.class);
System.out.println(constructor2);
}
@Testpublic void testName4() throwsException {/*调用构造器,创建对象
Constructor类:表示类中构造器的类型,Constructor的实例就是某一个类中的某一个构造器
常用方法:
public T newInstance(Object... initargs):如调用带参数的构造器,只能使用该方式.
参数:initargs:表示调用构造器的实际参数
返回:返回创建的实例,T表示Class所表示类的类型
如果:一个类中的构造器可以直接访问,同时没有参数.,那么可以直接使用Class类中的newInstance方法创建对象.
public Object newInstance():相当于new 类名();
调用私有的构造器:
*
**/
//需求: 使用反射创建Student的java对象//1.获取字节码实例//Class> clz = Class.forName("cn.sxt.t01.Users");
Class clz = (Class)Class.forName("cn.sxt.t01.Users");//2.获取指定构造器
Constructor cons1 = clz.getConstructor(String.class);//2.1获取私有构造函数
Constructor cons2 = clz.getDeclaredConstructor(String.class,Integer.class);//3.创建对象//3.1. 如果当前类的字节码有一个无参公共数构造器,可以直接使用字节码实例直接创建对象
Users n=clz.newInstance();
n.say();//3.2.使用构造器创建对象;
Users n1 = cons1.newInstance("dewjfe");//3.3使用私有构造函数创建//3.3.1设置忽略访问修饰的权限//如果是私有构造方法,反射默认是无法直接执行的,找到父类中AccessibleObject的方法,设置为true,即可忽略访问权限
cons2.setAccessible(true);
Users n3= cons2.newInstance("fewfew",20);
}
@Testpublic void testName5() throwsException {/*操作方法-Method
一个类创建对象以后,一般就要执行对象的方法等等,使用反射操作对象
首先要获取方法,再去执行,使用Class 获取对应的方法:
getMethods() 获取所有的公共方法,包括父类的公共方法
getDeclaredMethods() 获取所有本类的方法,包括本类的私有方法
getDeclaredMethod(String name, Class>... parameterTypes)
获取指定方法名称的方法,和访问权限无关
ame : 指定的方法名称
parameterTypes : 方法参数的类型
Method执行方法:方法获取以后就需要执行。Method对象中提供方法执行的功能
invoke(Object obj, Object... args)
执行方法
Obj :如果是对象方法,传指定的对象,如果是类方法,传 null
Args: 方法的参数
如果方法有返回结果,可以接收
获取方法和方法的执行
一个类中的方法有很多,无参,有参,静态,可变参数私有方法,等等,针对不同的方法处理,提供了不同的获取方案*/
/** 需求:获取Users类的方法*/
//1.获取Users的字节码实例
Class clz=Users.class;//2.通过类的字节码直接创建对象(必须保证类有一个无参数公共构造函数)
Users newInstance =clz.newInstance();//3.获取方法//3.1获取所有的公共方法(包含父类的方法)
Method[] methods =clz.getMethods();for(Method method : methods) {
System.out.println(method);
}//3.2获取当前类的所有的方法(不包含父类,和访问权限无关,成员或者静态方法都获取)
Method[] de =clz.getDeclaredMethods();for(Method method :de) {
System.out.println(method);
}//3.3获取指定名称的方法
Method hello1 = clz.getMethod("hello1");
System.out.println(hello1);//3.4 获取私有方法
Method hello3 = clz.getDeclaredMethod("hello3", String.class,int.class);
System.out.println(hello3);//3.5获取静态方法
Method staticMethod = clz.getDeclaredMethod("staticMethod", String.class);
System.out.println(staticMethod);//3.6获取有数组参数的方法
Method method1 = clz.getDeclaredMethod("method1", int[].class);
System.out.println(method1);
System.out.println("------------------------------------------------------------");
}
@Testpublic void testName6() throwsException {//1.获取Users的字节码实例
Class clz=Users.class;//2.通过类的字节码直接创建对象(必须保证类有一个无参数公共构造函数)
Users n =clz.newInstance();//3.获取方法//3.1获取指定名称的方法
Method hello1 = clz.getMethod("hello1");
System.out.println(hello1);//3.1.1执行无参数对象方法
hello1.invoke(n);//3.3 获取私有方法
Method hello3 = clz.getDeclaredMethod("hello3", String.class,int.class);
System.out.println(hello3);//3.3.1设置忽略访问权限
hello3.setAccessible(true);//3.3.2 执行私有方法
Object invoke = hello3.invoke(n, "令狐冲",30);
System.out.println( invoke);//3.4获取静态方法
Method staticMethod = clz.getDeclaredMethod("staticMethod", String.class);
System.out.println(staticMethod);//3.4.1执行静态方法
staticMethod.invoke(null, "金毛狮王");//3.5获取基本数据类型整数组参数的方法
Method method1 = clz.getDeclaredMethod("method1", int[].class);
System.out.println(method1);//3.5.1执行 数组参数的方法
int[] intArr = {1,2,5,10};
method1.invoke(null, newObject[] {intArr});//3.6获取基本数据类型整数组参数的方法
Method method2 = clz.getDeclaredMethod("method2", String[].class);
System.out.println(method2);//3.6.1执行字符串数组参数的方法
String[] stringArr = {"A","B","D"};//如果方法中有可变参数(数组),如果反射传递的可变参数是引用类型,底层有一个拆箱的功能,会将数组的元素拆成一个个参数传递过来//解决方案: 将数组外面在包装一层数组,如果拆箱一次,得到还是一个数组`
method2.invoke(null, newObject[] {stringArr});
}
@Testpublic void testName7() throwsException {/*操作字段(成员变量)-Field
* 类中的字段有各种数据类型和各种访问权限,针对这些情况,反射操作有对应的方法来获取和处理
* getFields() 获取当前Class所表示类中所有的public的字段,包括继承的字段.
* getDeclaredFields() 获取当前Class所表示类中所有的字段,不包括继承的字段.
* getField(String name) 获取当前Class所表示类中该fieldName名字的字段,不包括继承和私有的字段.
* getDeclaredField(String name):获取当前Class所表示类中该fieldName名字的字段,不包括继承的字段.
**/
/** Field类常用方法:
void setXX(Object obj, XX value) :为基本类型字段设置值,XX表示基本数据类型
void set(Object obj, Object value) :表示为引用类型字段设置值
参数:
obj: 表示字段底层所属对象,若该字段是static的,该值应该设为null
value: 表示将要设置的值
-------------------------------------------------------------------------------------
XX getXX(Object obj) :获取基本类型字段的值,XX表示基本数据类型
Object get(Object obj) :表示获取引用类型字段的值
参数:
obj: 表示字段底层所属对象,若该字段是static的,该值应该设为null
返回:返回该字段的值.
*
*
*
*set(Object obj, Object value)
设置引用类型的值,非基本数据类型
Obj: 要设置值得对象
Value : 要设置的值/
/*Field操作设置值/获取值
* 给某个类中的字段设置值和获取值:
1,找到被操作字段所在类的字节码
2,获取到该被操作的字段对象
3,设置值/获取值
**/
/** 需求:操作Users类的字段*/
//1.获取Users字节码实例
Class clz=Users.class;//1.1 通过字节码实例创建对象(必须保证有一个无参数public构造器)
Users n =clz.newInstance();//2.获取所有public字段
Field[] fields =clz.getFields();for(Field field : fields) {
System.out.println(field);
}//3.获取所有的字段(与访问权限无关)
Field[] declaredFields =clz.getDeclaredFields();for(Field field : declaredFields) {
System.out.println(field);
}//4.获取指定名称的public字段
Field field = clz.getField("name");//4.1为字段设置值
/** nameField.set(obj, value); obj : 要设置值字段对应的对象 value :具体指*/field.set(n,"fewwwfeg");//5.获取指定名称的和访问权限无关的字段
Field emailField = clz.getDeclaredField("email");//5.1 设置忽略访问权限
emailField.setAccessible(true);//5.2 设置私有字段的值
emailField.set(n, "xln@qq.com");
System.out.println(n);
}}