java反射

反射的基石 Class类
JAVA的反射是指,可以通过一个类名来探察这个类里面的信息,
比如说类的属性名,属性名的修饰符,方法名,方法返回值,方法修饰符等等,反正除了方法体得不到,
其他都可以用反射得到;反射还可以生成类的实例,通过这个实例定义属性,调用方法,特别是能调用私有的属性和私有的方法
1 所谓的类就是描述现实中的事物 而java程序中的各个类属于同一个事物
  该类事物有什么属性  没有什么属性 至于这个属性的值是什么  则是有这个类的实例对象来确定  
  不同的实例对象有不同的属性值  按照这样的的观点  那么既然事物可以用类描述  那么类又可以用什么来描述了 
  类有名字  访问属性  包名  字段名  方法名  等等  这些都是类有的  于是就用了Class来描述class类
  Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,
  所有具有相同元素类型和维数的数组都共享该 Class 对象。
  基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。 


  Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。 

人       可以用  Person来描述
java类   可以用  Class 来描述


如何获得字节码对应的实例对象(Class)
1 学生 xx=new 学生  然后 xx.class
2 利用Object中的getClass   new 学生.getClass()
3 Class 中有一个方法forName(类名) Class.forName(学生) 


 反射奇偶是把java类中的各个成分映射成相应的java类 例如  一个java类中用一个Class类的对象来表示 一个类中的组成部分 
 成员变量  方法  构造方法  包   等等信息也用一个个的java类来表示 
 就像汽车是一个类  汽车中的发动机  变速箱 等等也就是一个个类  
 表示java类的Class类显然要提供一系列的方法来获其中的变量  方法  构造方法 修饰符 包等信息  
 这些信息就是用相应类的实例对象来表示  他们是Field代表字段  Method代表方法   Constructor代表构造方法  Package代表包   
 反射就是把java类中的各种成分映射成相应的java类




Method类代表某个类中的一个成员方法
得到类中的某一个方法:
例子  Method  charAt=Class.forName("java.lang.String").getMethod("charAt".int.class);


调用方法 :
通常方法  System.out.println(srt.charAt(1));
反射方法  System.out.println(charAt。invoke(str,1))
如果传递给Method对象的invoke()方法的一个参数为null 这有着什么样的意义呢? 说明该Method对象对应的是一个静态方法


jdk 1.4和1.5的invoke方法的区别
jdk1.5  public Object invoke(Object obj,Object...args)
jdk1.4  public Object invoke (Object obj,Object【】args)既按jdk1.4的语法  
需要将一个数组作为参数传递给invoke方法时 数组中的每一个元素分别对应被调用方法中的一个参数  
所以 调用charAt方法的代码也可以用jdk1.4改写为charAt.invoke("str",new Object[]{1})形式。
代码演示:
import java.lang.reflect.*;
class dda 
{
public static void main(String[] args)throws Exception 
{
jj j=new jj();//给构造函数传值
ziduan(j);
diaoyong(j);
System.out.println(j);
fangfa();
}
public static void fangfa()throws Exception
{
//方法
String s="abcde";//要查找的字符串
//获取String字节码 然后在传String的方法,还有参数
Method m=String.class.getMethod("charAt",int.class);//参数2接收的是字节码文件
//对带有指定参数的指定对象调用由此 Method 对象表示的底层方法
System.out.println(m.invoke(s,3));
}
public static void gouzhao()throws Exception
{
/*
获取个类中的所有构造方法
Consrtructor []con=Class.forName("java.lang.String").getConsrtructor();
获取一个类中的构造方法
Consrtructor con1=Class.forName("java.lang.String").getConsrtructor(字节码文件对象 如:StringBuffer);
通常方式  String str=new String(new StringBuffer());
反射方式  String str1=(String).con1.newInstance(new new StringBuffer("abc"));
*/
Constructor g= String.class.getConstructor(StringBuffer.class);//获取String中的一个构造方法
String x=(String)g.newInstance(new StringBuffer("abc"));//创出新的构造方法  强转成String类型
System.out.println(x.charAt(2));
}
public static void ziduan(jj j)throws Exception
{
Field conb=j.getClass().getField("b");//getField获取字段中b的字节码
System.out.println(conb);
int b=(int)conb.get(j);//获取字段中b的值
System.out.println(b);


//下面针对私有
Field cona=j.getClass().getDeclaredField("a");//获取字段中b的字节码
//该getDeclaredField 放可以让被private修饰的成员可见
System.out.println(cona);
cona.setAccessible(true);//该方法是暴力获取private成员
int a=(int)cona.get(j);
System.out.println(a);
}
public static void diaoyong(Object obj)throws Exception
{
Field []f=obj.getClass().getFields();

for (Field ff:f)//将数组变量 获取每一个Field的值
{
if(ff.getType()==String.class)//如果字节码是String类型
{
String str=(String)ff.get(obj);//获取字节码对应的String字段的String值
System.out.println(str);
String str1=str.replace('a','f');//把str的值替换成f
ff.set(obj,str1);//设置进去 私有设置不了
}
}
}
}
class jj 
{
private int a=3;
public int b=5;
public String aa="aazz";
public String bb="ppda";
private String cc="kaak";
public String toString()
{
return aa+"  "+bb+"  "+cc;
}
}








目标: 写一个程序  这个程序能够更加用户通过类名  去执行类中的main方法  通过反射的方式去调用
问题  启动java程序的main方法的参数是一个字符串数组  既public static void main(String【】 args)
通过反射的方式来调用main方法是 如何为invoke方法传递参数呢  按jdk1.5的语法  整个数组是一个参数  
而按jdk1.4的语法 数组中的每个元素对应一个参数  当把一个字符串数组作为参数传递给invoke方法是  


解决方法  
invoke (null,new Object[]{new String []{"xxx"}});
invoke  (null,(Object)new String[]{"xxx"});


编译器会作为特殊处理  编译是不把参数作为数组看待 也就不会数组打散成若干个参数了
代码演示:
import java.lang.reflect.*;
class kk
{
public static void main(String [] aa)throws Exception
{
//利用反射调用mani方法
String []a=new String[]{"qwe","ert","rty"};
Method m=ccc.class.getMethod("main",String[].class);//参数2接收的是字节码文件
m.invoke(null,(Object)a);//调用静态的方法要传null
//ccc.main(new String[]{"asd","ee"});//正常打印
}
}
class ccc //这是另一个类
{
public static void main(String[] args) 
{
for (int a=0;a<args.length ;a++ )
{
System.out.println(args[a]);
}
}
}


数组:
 具有相同维数和元素类型的数组属于同一个类型  具有相同的Class实例对象
 代表数组的Class 实例对象的getSuperClass()方法返回的父类为Object类对应的Class
 基本类型的一位数组可以被当做Object【】类型使用  非基本类型的一维数组  既可以当做Object  类型使用  有可以当做Object【】类型使用
import java.util.*;
import java.lang.reflect.*;
class shuzu 
{
public static void main(String[] args) 
{
int []a=new int[]{1,4,6};
int []aaa=new int [4];
int [][]aa=new int [2][3];
String []str=new String[]{"aa","bb","cc"};
sos(a.getClass()==aaa.getClass());//只有相同的类型才可以比较 维数要一样

sos(a.getClass().getName());//查看名字
sos(a.getClass().getSuperclass().getName());//查看他的父类名称
//sos(a.getClass().getSuperClass().getNmae());
Object obj2=a;
Object []obj=aa;
Object []obj1=str;


sos(Arrays.asList(obj2));
sos(Arrays.asList(obj));
sos(Arrays.asList(obj1));/*Arrays.asList() 如果是String传进去  那么就按照jdk1.4版本的走
如果是int传进去就必须走jdk1.5  1.5等效于T...a 不当做Object类型
只当做Object*/
int []ax={2,5,6,7};
sz(ax);
}
public static void sz(Object a)
{
Class x=a.getClass();
/*将传进来的转成字节码 然后在判断是不是数组
如果是数组就用专门操作反射数组的对象对数组取出*/ 
if(x.isArray())
{
//Array.getLength()传数组进去 算出有多少元素
for (int xx=0;xx<Array.getLength(a) ;xx++ )
{
//获取Array.get(数组对象,索引);
sos(Array.get(a,xx));
}
}
else
{
sos(a);
}
}
public static void sos(Object obj)
{
System.out.println(obj);
}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值