注:forName的作用:返回类字节码,两种方式:a、已加载,直接返回;b、还没加载,则用类加载器加载到内存中;
Class.forName(“……”);该方法中的String参数可以换成一个字符串类型的变量,该变量的值可通过配置文件来完成(一般用于框架开发等);
9个预定义实例对象(8个基本数据类型+void)
例:Class cls=void.class;
注:内存中仅有一份字节码,就算同一类的多个对象也是同一份字节码;
基本数据类型包装类中的常量TYPE对应的是该基本数据类型的字节码,即:int.class==Integer.TYPE;//true;
注:基本数据类型的字节码与其对应的基本数据类型包装类的字节码不是同一份,级:int.class==Integer.class;//false;
总之:只要是在源程序中出现的类型,都有各自的Class实例对象,例:int[],void;
注:int[].class与int.class的字节码不同,数组是一个类的对象与其基本数据类型不同;
代表某个类中的一个构造方法
Field类代表某个类中的一个成员变量(代表字节码中的变量,不代表对象中的变量);获取一个类的实例对象上的某个字段(成员变量)的值的方式:
常用方法:
Method类代表某个类中的一个成员方法;
得到类中的某一个方法:
例:Method charAt=Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
调用方法
invoke方法在1.4与1.5中的区别:
常用方法:
例:用反射的方式执行某个类中的main方法;
启用Java程序的main方法的参数时一个字符串数组,即:public static void main(String[] args),通过反射方式来调用这个main方法时,为invoke方法传递参数只能使用以下两种方式:
mainMethod.invoke(null,new Object[]{new String[]{“……”}});
mainMethod.invoke(null,(Object)new String[]{“……”});
而不能直接传入一个”String[]”,因为JDK1.5的语法整个数组作为一个参数,但JDK1.4会将数组拆开,将数组中的元素视为多个参数,此时将于main方法的参数列表不符,JDK1.5兼容JDK1.4,直接传入数组时将按JDK1.4的语法处理,所以需要将数组封装成一个数组或不让其拆包;
具有相同维数和元素类型的数据属于同一个类型,即具有相同的Class实例对象;
例:int[] a1=new int[3];
int[] a2=new int[5];
a1.getClass()==a2.getClass();//true;
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class,即:数组也是Object的子类;
对数组的反射可使用Array类来实现;
附:
内存泄漏:用动态存储分配函数动态开辟的空间,在使用完毕后来释放,结果导致一直占据该内存单元,直到程序结束,即:内存使用完毕之后来释放;
import java.lang.reflect.*;
import java.util.*;
class ReflectTest {
public static void main(String[] args)throws Exception{
String str="abc";
int b=2;
int[] i=new int[0];
Class cls1=String.class;
Class cls2=str.getClass();
Class cls3=Class.forName("java.lang.String");
System.out.println(cls1==cls2);
System.out.println(cls1==cls3);
Class cls4=int.class;
Class cls5=Integer.class;
Class cls6=Integer.TYPE;//该字段等效于int.class;
System.out.println(cls4==cls5);
System.out.println(cls4==cls6);
System.out.println(cls4.isPrimitive());
Class cls7=i.getClass();
System.out.println(cls7.isArray());
Constructor cons=cls1.getConstructor(StringBuffer.class);
String string=(String)cons.newInstance(new StringBuffer("abcd"));
System.out.println(string.charAt(2));
//使用反射的方式获取类中的成员变量
TestDemo td=new TestDemo(6,8);
Class tdclass=td.getClass();
Field fieldy=tdclass.getField("y");//公有化成员可以直接使用getField也可使用getDeclaredField方法返回Field方法;
System.out.println(fieldy.get(td));
Field fieldx=tdclass.getDeclaredField("x");//非公有化成员需用getDeclaredField方法返回Field对象;
fieldx.setAccessible(true);//私有化成员需用setAccessible方法取消访问检查(暴力反射)
System.out.println(fieldx.get(td));
changeStringValue(td);
System.out.println(td.toString());
//获取类中的所有方法
Method[] methods=TestDemo.class.getDeclaredMethods();
for(Method method:methods){
System.out.println(method);
}
// 使用反射的方式获取类中的方法,并调用该方法;
Method concat=str.getClass().getMethod("concat",String.class);
String str8=(String)concat.invoke(str,"def");
System.out.println(str8);
//使用反射的方式获取类中的多个参数的方法;
Method substring=str8.getClass().getMethod("substring",int.class,int.class);
System.out.println(substring.invoke(str8,1,4));
Method valueOf=String.class.getMethod("valueOf",int.class);
System.out.println(valueOf.getName());
System.out.println(valueOf.invoke(null,2));
//使用反射的方式获取类中的空参数方法;
Method getBytes=str8.getClass().getMethod("getBytes");
byte[] bs=(byte[])getBytes.invoke(str8);
for(byte by:bs){
System.out.println((char)by);
}
System.out.println(getBytes.getName());
//用反射的方法调用类中的main方法,并给main传递参数;main的参数是个String[] 在JDK1.5中可使用以下方式传递多个参数;
Method mainMethod=Class.forName("TestDemo").getMethod("main",String[].class);
mainMethod.invoke(null,new Object[]{new String[]{"111","222","333"}});//JDK1.5兼容JDK1.4在传入数组时会将数组中的内容视为多个参数而不是一个数组,故需要将数组打包成一个Object[]传入,或使用下面的方式
//以上书写等效于:mainMethod.invoke(null,(Object)new String[]{"111","222","333"});
//数组与Object的关系及其反射类型
int[] a1=new int[]{1,2,3,4};
int[] a2=new int[]{3,4};
int[][] a3=new int[2][4];
String[] a4=new String[]{"a","b","c"};
String[] a5=new String[]{"a","b","c"};
System.out.println(a1.getClass() == a2.getClass());
//System.out.println(int.class== int[][].class);
//System.out.println(a1.getClass() == a4.getClass());
//System.out.println(a5.getClass() == a4.getClass());
System.out.println(a2.getClass().getSuperclass().getName());
System.out.println(a3.getClass().getSuperclass().getName());
System.out.println(a4.getClass().getSuperclass().getName());
//Object[] obj1=a1;//基本数据类型不是Object类;所以int[]无法转换为Object[];
Object[] obj2=a3;//数组是Object类,所以二维数组int[][]可转换为Object[]的一维数组,内部元素就是数组;
Object[] obj3=a4;//String是Object类……;
//System.out.println(Arrays.asList(obj1));
System.out.println(Arrays.asList(obj2));//asList方法传入数组时按JDK1.4版本语法执行(兼容) //当出入基本数据类型的数组时,因以上原因int不被视为Object,则按JKD1.5版本语法执行,数组被视为一个参数!
System.out.println(Arrays.asList(obj3));
//数组的反射
arrayReflect(a1);
arrayReflect(a4);
arrayReflect("xyz");
}
//以反射的方式获取给定数组中的所有元素,如果不是数组则直接打印;
public static void arrayReflect(Object obj){
if(obj.getClass().isArray()){
for(int x=0;xout.println(Array.get(obj,x));
}
}else{
System.out.println(obj);
}
}
public static void changeStringValue(Object obj)throws Exception{
Class tdcla=obj.getClass();
Field[] fields=tdcla.getFields();
for(Field field:fields){
if(field.getType()==String.class){//if(field.getType().equals(String.class))此处可使用equals方法判断
//使用==是因为同一类字节码在内存中为同一份,所以用==比更专业;
String oldValue=(String)field.get(obj);//获取指定对象中Field的值;
String newValue=oldValue.replace('b','a');//替换字符串中的值;
field.set(obj,newValue);//给指定的对象的该Field字段设置新值;
}
}
}
}
class TestDemo{
int x;
public int y;
public String str1="ball";
public String str2="basketball";
public String str3="itcast";
TestDemo(int x,int y){
this.x=x;
this.y=y;
}
private void show(){
System.out.println("siyounengkanjianma");
}
public String toString(){
return str1+"::"+str2+"::"+str3;
}
public static void main(String[] args){
for(String arg:args){
System.out.println(arg);
}
}
public boolean equals(Object obj){
if(!(obj instanceof TestDemo))
return false;
if(obj==null)
return false;
if(getClass()!=obj.getClass())
return false;
final TestDemo oth=(TestDemo)obj;
if(this.x!=oth.x)
return false;
if(this.y!=oth.y)
return false;
return true;
}
public int hashCode(){
int prime=31;
int result=23;
result=result*prime+x;
result=result*prime+y;
return result;
}
}
例:使用反射的方式创建一个HashSet集合;
InputStream input=new FileInutStream(“properties.txt”);读取配置文件
properties pro=new Properties();
pro.load(input);
input.close();
String className=pro.getProperty(“className”);通过配置文件中的指定键获取值;
Collection hs=(Collection)Class.forName(className).newInstance();//创建集合对象;
import java.util.*;
import java.io.*;
class ReflectTest2 {
public static void main(String[] args) throws Exception{
//Collection al=new ArrayList();
//Collection hs=new HashSet();
InputStream input=new FileInputStream("Properties.txt");
Properties pro=new Properties();
pro.load(input);
input.close();
String classNameSet=pro.getProperty("classNameSet");
String classNameList=pro.getProperty("classNameList");
Collection hs=(Collection)Class.forName(classNameSet).newInstance();
Collection al=(Collection)Class.forName(classNameList).getConstructor().newInstance();
TestDemo td1=new TestDemo(3,4);
TestDemo td2=new TestDemo(3,5);
TestDemo td3=new TestDemo(4,6);
TestDemo td4=new TestDemo(3,4);
al.add(td1);
al.add(td2);
al.add(td3);
al.add(td4);
al.add(td1);
System.out.println(al.size());
hs.add(td1);
hs.add(td2);
hs.add(td3);
hs.add(td4);
hs.add(td1);
//td3.y=18;
//td3.x=8;//在添加集合之后修改参与hashcode运算的参数值,将影响hashcode值
hs.remove(td3);//删除时将找不到该元素,导致删除失败,即:内存泄漏;
System.out.println(hs.size());
}
}