定义概念
概念:反射就是将Java类中的各种成分映射成相应的Java类
1、获取Class的3种方式
对象 s=new 对象();
s.getClass();
类名.class;
Class.forName("java.lang.String");//主要用这种。
Java中有9个预定义的Class实例对象(8个基本数据类型和void),void.class也是可以的。
2、练习-方法大全
public static void main(String[] args) throws Exception{
//不同方式获取class
String str1="abc";
Class cls1=str1.getClass();
Class cls2=String.class;
Class cls3=Class.forName("java.lang.String");
//结论:不同方法获取到的Class是相同的
System.out.println(cls1==cls2);//true
System.out.println(cls1==cls3);//true
//几种方法
System.out.println(cls1.isPrimitive());//String不是基本类型false
System.out.println(int.class.isPrimitive());//int是基本类型true
System.out.println(int.class==Integer.class);//false,是不同的类型
System.out.println(int.class==Integer.TYPE);//Integer所代表的基本数据类型Class结果是true
System.out.println(int[].class.isPrimitive());//int数组类型不是基本类型false
System.out.println(int[].class.isArray());//int数组类型是数组true
//获取构造方法
//参数是StringBuffer的
Constructor constructor = String.class.getConstructor(StringBuffer.class);
String newInstance = (String) constructor.newInstance(new StringBuffer("abc"));
System.out.println(newInstance);
//得到所有构造方法
Constructor[] constructors = String.class.getConstructors();
//得到默认的构造方法
String newInstance2 = String.class.newInstance();
//获取属性
User u=new User(1,2);
Field fieldX = u.getClass().getField("x");
System.out.println(fieldX.get(u));
Field fieldY = u.getClass().getDeclaredField("y");//获取私有属性,非私有的也能获取到
fieldY.setAccessible(true);//授权
System.out.println(fieldY.get(u));
//将u反射,修改字段值
changeStringValue(u);
//获取方法
//参数是方法名和参数类型
Method method = String.class.getMethod("charAt", int.class);
//如果传入的第一个参数是null,说明调用的是静态方法,不需要对象既可以调用(例如这里的str1可以写成null)
Object invoke = method.invoke(str1, 1);
System.out.println(invoke);
Object invoke2 = method.invoke(str1, new Object[] {2});
System.out.println(invoke2);
//在这个main方法中调用另一个类的main方法,args[0]是那个类的全路径
//需要做一件事,在run as config中添加参数,也就是类的全路径如下图所以
//另一个类中就可以在main方法中循环遍历args[],输出每一个元素
String arg=args[0];
Method method2 = Class.forName(arg).getMethod("main", String[].class);
//main方法是静态的,所以第一个参数传null
//下面2中执行方法都可以。任选其一
//method2.invoke(null, new Object[] {new String[] {"111","222","333"}});
method2.invoke(null, (Object)new String[] {"111","222","333"});
//数组
int[] a1=new int[]{1,2,3};
int[] a2=new int[4];
int[][] a3=new int[2][3];
String[] a4=new String[]{"a","b","c"};
System.out.println(a1.getClass()==a2.getClass());//true
System.out.println(a1.getClass().getName());//[I
System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object
System.out.println(a3.getClass().getSuperclass().getName());//java.lang.Object
System.out.println(a4.getClass().getSuperclass().getName());//java.lang.Object
// Object o1=a1;
// Object o2=a4;
// Object[] o3=a3;
// Object[] o4=a4;
//asList()方法:传int数组,List中每个元素都是数组,而传String数组,每个元素都是String
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));
//数组的反射
printObject(a4);//传的数组循环打印
printObject("xyz");//传的字符串直接打印
//内存泄漏的例子
T1 u1=new T1(1,2);
T1 u2=new T1(1,2);
//前提是HashSet中重写了hashcode和equals方法
Collection c=new HashSet();
c.add(u1);
c.add(u2);
//内存泄漏:由于改了u1中的字段值,所以u1的hashCode值也跟着改变了,在内存中会多出来一个内存地址,以前的不用了也没有进行回收。
u1.i=3;
c.remove(u1);
System.out.println(c.size());
//读取配置文件,通过反射的方式创建对象
InputStream is =new FileInputStream("config.properties");
Properties p=new Properties();
p.load(is);
is.close();
//className=java.util.ArrayList
String className=p.getProperty("className");
//反射成功集合类
Collection collection = (Collection) Class.forName(className).newInstance();
}
//通过反射的方法,将类中的字符串类型字段改变值
private static void changeStringValue(Object obj) throws Exception {
Field[] fields = obj.getClass().getFields();
for(Field field:fields) {
if(field.getType()==String.class) {
String s = (String) field.get(obj);
field.set(obj, s.replace("b","a"));
}
}
}
//数组的反射。。。
private static void printObject(Object obj) {
Class objClass = obj.getClass();
//如果是数组遍历打印,否则直接打印
if(objClass.isArray()) {
int length = Array.getLength(obj);
for(int i=0;i<length;i++) {
System.out.println(Array.get(obj, i));
}
}else {
System.out.println(obj);
}
}
给main方法添加请求参数: