1.反射:一个类有多个组成部分,例如,成员变量,成员方法,构造方法等。反射就是加载类,并解剖出类的各个组成部分。( 解析编译好之后的.class文件 )
[color=brown]变成时什么情况下才需要加载类,并解剖出类的各个组成部分?[/color]
当只有一个类的.class文件或不知道类的内部结构的时候,或只知道某个包名下的.class文件并且知道这个类里边大方法名称,需要反射,解析出需要的原有java类的成员变量,成员方法,构造方法等。
2.详解:
2-1.[color=brown]反射的主要步骤:[/color]
第一步:先加载类
第二部:解析出所需类型的构造器
第三部:创建解析出来的实体
第四步:根据实体对象解析出实体对象里的成员方法或成员属性
2-2. 加载类:java中有一个Class类用于代表某一个类的字节码,并且提供了加载某个类字节码的方法forName(),forName()方法用于加载某个类的字节码到内存中并使用.class对象进行封装,还有另外两种得到class对象的方式 :
--- 类名.class,
--- 对象.getClass()
例: //1.加载类--直接加载
Class cla=Class.forName("cn.isoftstone.reflect.Student");
//2.加载类--创建对象,调用.getClass
Student stu=new Student();
Class cla1= stu.getClass();
//3.加载类--直接 类名.class
Class cla2=Student.class;
2-3.实例演示:
public class Student {
/**单纯的声明一个变量那么它可以叫做一个字段,当这个字段有get方法返回的时候那么它就可以叫做属性
* 不声明字段,直接返回生命get方法的时候,例:getEmail()那么Email就是一个属性
* */
private String name;
private int sum; //字段
private String args[];
public String getEmail(){ //属性
return "zhangsansan@163.com";
}
public String getName(){
return name;
}
public Student() {
//解析默认不带参数的构造器
}
private Student(List list) {
//解析带List参数的构造器
}
public Student(String name, int age) {
//解析带基本数据类型参数的构造器
}
public Student(String str[]) {
}
public Student(String args[],double dou) {
//解析带数组参数的构造器
}
//返回无返回值不带参数的成员方法
public void study() {
System.out.println("学习中,请勿打扰 ... ... ");
}
//解析无返回值 带参数的成员方法
public void study(Integer i){
System.out.println(1);
}
//解析待返回值带参数的成员方法
public int getSum(int a,int b){
sum=a+b;
return sum;
}
//解析主方法
public static void main(String[] args) {
System.out.println("-------");
}
}
解析Student类的各种情况下的构造方法,Junit测试类:
@Test
public void test1() throws Exception{
//解析Student类
//1.加载类
Class cla=Class.forName("cn.isoftstone.reflect.Student");
//2.解析---通过无参数的构造器解析
Constructor constructor=cla.getConstructor(null);
//3.创建类的实例
Student entity=(Student) constructor.newInstance(null);
entity.study();
}
@Test
public void test2() throws Exception{
//解析带参数的构造器
//1.加载类
Class cla=Student.class;
//2.解析---通过带参数的构造器解析
Constructor constructor=cla.getConstructor(String.class,int.class);
//3.创建类的实例
Student stu=(Student) constructor.newInstance("zhang sansan",90);
stu.study();
System.out.println(stu.getName());
}
@Test
public void test3(){
//怎么知道类中有哪些构造器
Class cla=Student.class;
Constructor csr[]=cla.getConstructors();
for(Constructor c:csr){
System.out.println(c.toGenericString());
}
}
@Test
public void test4()throws Exception{
//解析带数组参数的构造器 ---解析带数组的构造器,不能只有一个参数(jdk1.4 jdk1.5的区别) ...........
/* ---或者参数必须声明在外面 ,把数组强制造型成一个Object对象,如下:
String str[]={"a","b","c"};
Student stu=(Student) con.newInstance((Object)str);
*/
Class cla=Class.forName("cn.isoftstone.reflect.Student");
Constructor constructor=cla.getConstructor(String[].class,double.class);
Student stu=(Student) constructor.newInstance(new String[]{"test","test1","test2"},9.0);
stu.study();
}
@Test
public void test6() throws Exception{
//解析私有构造器,私有方法,私有属性要用getDeclaredConstructor(x.class),getDeclaredMethod(ClassObject)解析
Class cla=Class.forName("cn.isoftstone.reflect.Student");
Constructor con=cla.getDeclaredConstructor(List.class);
con.setAccessible(true); //暴力访问 ,强制修改访问权限
Student stu=(Student) con.newInstance(new ArrayList());
stu.study();
}
@Test
public void test8() throws Exception{//解析Student类中固定的成员方法
/**
* 注:如果解析的是private的私有成员方法,那么解析成员方法的时候要用getDeclaredMethod()方法,
* 然后Method对象调用setAccessible(true)方法强制执行反射
* */
Class cla=Student.class;
Student entity=(Student) cla.newInstance();//解析出实体对象的新实例,使用con.newInstance()方法的时候,必须保证Student类中有一个无参的构造方法
//1.解析出所有的成员方法,并遍历
Method methods[]=cla.getMethods();
for(Method method:methods){
System.out.println(method.toGenericString());
}
//2.解析不带返回值 不带参数的成员方法
Method mt1=cla.getMethod("study",null); //解析出目标成员方法,第二个参数是待解析方法的参数数据类型
mt1.invoke(entity,null);//执行解析出的成员方法,第一个参数是方法对应的实体对象,第二个参数是给待解析方法传的值
//3.解析不带返回值的成员方法
Method mt2=cla.getMethod("study",Integer.class); //解析出目标成员方法,第二个参数是待解析方法的参数数据类型
mt2.invoke(entity, 1);//执行解析出的成员方法,第一个参数是方法对应的实体对象,第二个参数是给待解析方法传的值
//4.解析带返回值 带参数的成员方法
Method mt3=cla.getMethod("getSum",int.class,int.class);
Object obj=mt3.invoke(entity, 2,3);//返回的是一个Object
System.out.println(obj);
/**解析主函数main函数
* jdk1.4 -- main(String args[])当做数组来处理
* jdk1.5 -- main(String...str )当做可变参数来处理
* */
Method mt4=cla.getMethod("main",String[].class);
mt4.invoke(entity, new Object[]{new String[]{"aa"}});
/*或 String args[]={};
mt4.invoke(entity, (Object)args);
*/
}
@Test
public void test9() throws Exception{ //解析成员属性或字段,注,解析的成员属性必须是定义好的
Class cla=Class.forName("cn.isoftstone.reflect.Student");
Student entity=(Student) cla.newInstance();
//1.解析所有的成员属性,解析私有的成员属性调用getDeclaredFields()方法,然后强制执行
Field fields[]=cla.getDeclaredFields();
for(Field field:fields){
field.setAccessible(true);//强制执行
System.out.println(field.getName());
}
//2.解析并操作字段或属性---例:赋值
Field fd1=cla.getDeclaredField("name");
fd1.setAccessible(true);
fd1.set(entity, "zhangsansan");//赋值
//System.out.println(stu.getName());//直接通过实体对象的get方法获取值---X
String value=(String) fd1.get(entity);//通过实体对象获取值
System.out.println(value);
}
[color=brown]变成时什么情况下才需要加载类,并解剖出类的各个组成部分?[/color]
当只有一个类的.class文件或不知道类的内部结构的时候,或只知道某个包名下的.class文件并且知道这个类里边大方法名称,需要反射,解析出需要的原有java类的成员变量,成员方法,构造方法等。
2.详解:
2-1.[color=brown]反射的主要步骤:[/color]
第一步:先加载类
第二部:解析出所需类型的构造器
第三部:创建解析出来的实体
第四步:根据实体对象解析出实体对象里的成员方法或成员属性
2-2. 加载类:java中有一个Class类用于代表某一个类的字节码,并且提供了加载某个类字节码的方法forName(),forName()方法用于加载某个类的字节码到内存中并使用.class对象进行封装,还有另外两种得到class对象的方式 :
--- 类名.class,
--- 对象.getClass()
例: //1.加载类--直接加载
Class cla=Class.forName("cn.isoftstone.reflect.Student");
//2.加载类--创建对象,调用.getClass
Student stu=new Student();
Class cla1= stu.getClass();
//3.加载类--直接 类名.class
Class cla2=Student.class;
2-3.实例演示:
public class Student {
/**单纯的声明一个变量那么它可以叫做一个字段,当这个字段有get方法返回的时候那么它就可以叫做属性
* 不声明字段,直接返回生命get方法的时候,例:getEmail()那么Email就是一个属性
* */
private String name;
private int sum; //字段
private String args[];
public String getEmail(){ //属性
return "zhangsansan@163.com";
}
public String getName(){
return name;
}
public Student() {
//解析默认不带参数的构造器
}
private Student(List list) {
//解析带List参数的构造器
}
public Student(String name, int age) {
//解析带基本数据类型参数的构造器
}
public Student(String str[]) {
}
public Student(String args[],double dou) {
//解析带数组参数的构造器
}
//返回无返回值不带参数的成员方法
public void study() {
System.out.println("学习中,请勿打扰 ... ... ");
}
//解析无返回值 带参数的成员方法
public void study(Integer i){
System.out.println(1);
}
//解析待返回值带参数的成员方法
public int getSum(int a,int b){
sum=a+b;
return sum;
}
//解析主方法
public static void main(String[] args) {
System.out.println("-------");
}
}
解析Student类的各种情况下的构造方法,Junit测试类:
@Test
public void test1() throws Exception{
//解析Student类
//1.加载类
Class cla=Class.forName("cn.isoftstone.reflect.Student");
//2.解析---通过无参数的构造器解析
Constructor constructor=cla.getConstructor(null);
//3.创建类的实例
Student entity=(Student) constructor.newInstance(null);
entity.study();
}
@Test
public void test2() throws Exception{
//解析带参数的构造器
//1.加载类
Class cla=Student.class;
//2.解析---通过带参数的构造器解析
Constructor constructor=cla.getConstructor(String.class,int.class);
//3.创建类的实例
Student stu=(Student) constructor.newInstance("zhang sansan",90);
stu.study();
System.out.println(stu.getName());
}
@Test
public void test3(){
//怎么知道类中有哪些构造器
Class cla=Student.class;
Constructor csr[]=cla.getConstructors();
for(Constructor c:csr){
System.out.println(c.toGenericString());
}
}
@Test
public void test4()throws Exception{
//解析带数组参数的构造器 ---解析带数组的构造器,不能只有一个参数(jdk1.4 jdk1.5的区别) ...........
/* ---或者参数必须声明在外面 ,把数组强制造型成一个Object对象,如下:
String str[]={"a","b","c"};
Student stu=(Student) con.newInstance((Object)str);
*/
Class cla=Class.forName("cn.isoftstone.reflect.Student");
Constructor constructor=cla.getConstructor(String[].class,double.class);
Student stu=(Student) constructor.newInstance(new String[]{"test","test1","test2"},9.0);
stu.study();
}
@Test
public void test6() throws Exception{
//解析私有构造器,私有方法,私有属性要用getDeclaredConstructor(x.class),getDeclaredMethod(ClassObject)解析
Class cla=Class.forName("cn.isoftstone.reflect.Student");
Constructor con=cla.getDeclaredConstructor(List.class);
con.setAccessible(true); //暴力访问 ,强制修改访问权限
Student stu=(Student) con.newInstance(new ArrayList());
stu.study();
}
@Test
public void test8() throws Exception{//解析Student类中固定的成员方法
/**
* 注:如果解析的是private的私有成员方法,那么解析成员方法的时候要用getDeclaredMethod()方法,
* 然后Method对象调用setAccessible(true)方法强制执行反射
* */
Class cla=Student.class;
Student entity=(Student) cla.newInstance();//解析出实体对象的新实例,使用con.newInstance()方法的时候,必须保证Student类中有一个无参的构造方法
//1.解析出所有的成员方法,并遍历
Method methods[]=cla.getMethods();
for(Method method:methods){
System.out.println(method.toGenericString());
}
//2.解析不带返回值 不带参数的成员方法
Method mt1=cla.getMethod("study",null); //解析出目标成员方法,第二个参数是待解析方法的参数数据类型
mt1.invoke(entity,null);//执行解析出的成员方法,第一个参数是方法对应的实体对象,第二个参数是给待解析方法传的值
//3.解析不带返回值的成员方法
Method mt2=cla.getMethod("study",Integer.class); //解析出目标成员方法,第二个参数是待解析方法的参数数据类型
mt2.invoke(entity, 1);//执行解析出的成员方法,第一个参数是方法对应的实体对象,第二个参数是给待解析方法传的值
//4.解析带返回值 带参数的成员方法
Method mt3=cla.getMethod("getSum",int.class,int.class);
Object obj=mt3.invoke(entity, 2,3);//返回的是一个Object
System.out.println(obj);
/**解析主函数main函数
* jdk1.4 -- main(String args[])当做数组来处理
* jdk1.5 -- main(String...str )当做可变参数来处理
* */
Method mt4=cla.getMethod("main",String[].class);
mt4.invoke(entity, new Object[]{new String[]{"aa"}});
/*或 String args[]={};
mt4.invoke(entity, (Object)args);
*/
}
@Test
public void test9() throws Exception{ //解析成员属性或字段,注,解析的成员属性必须是定义好的
Class cla=Class.forName("cn.isoftstone.reflect.Student");
Student entity=(Student) cla.newInstance();
//1.解析所有的成员属性,解析私有的成员属性调用getDeclaredFields()方法,然后强制执行
Field fields[]=cla.getDeclaredFields();
for(Field field:fields){
field.setAccessible(true);//强制执行
System.out.println(field.getName());
}
//2.解析并操作字段或属性---例:赋值
Field fd1=cla.getDeclaredField("name");
fd1.setAccessible(true);
fd1.set(entity, "zhangsansan");//赋值
//System.out.println(stu.getName());//直接通过实体对象的get方法获取值---X
String value=(String) fd1.get(entity);//通过实体对象获取值
System.out.println(value);
}