反射的基石 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);
}
}
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);
}
}