反射
反射
反射是程序在运行时能够获取自身的信息。
优点
运行时确定类型,绑定对象。动态编译最大发挥java的灵活性,体现多态应用,降低程序耦合性。
缺点
反射其实就是一种解释操作,这种操作慢于直接执行相同操作。
class
class代表java类,就相当于person代表人。
类被加载到内存中,这片内存空间就是类的字节码,不同的类字节码是不同的,一个类在内存中只有一份字节码。
获取字节码的三种方式
public class GetClass { public static void main(String[] args)throws Exception{ Class c1=String.class; //调用某个类的class属性获取Class对象 Class c2=Class.forName("java.lang.String"); //使用Class类的forName(String className)静态方法 Class c3=new String().getClass(); //用某个对象的getClass()方法,该方法属于Object类 } }
预定义Class对象
基本java类型:int,short,long,byte,char,boolean,double,float和关键字void通过class属性也能表示为class对象。
IsPrimitive判断对象是否是基本类型。
IsArry判断对象是否是数组。
public class ClassDemo { public static void main(String[] args) { Class i1=int.class; Class i2=Integer.class; Class i3=Integer.TYPE; //包装类都有一个常量TYPE,用来表示其基本数据类型的字节码 System.out.println(i1); System.out.println(i2); System.out.println(i3); System.out.println(i1==i2); System.out.println(i2==i3); //证明TYPE值是int Class i4=String[].class; Class i5=int[].class; /*System.out.println(i4==i5); * 会报错,因为int[]里面的是不是一个对象,String[]里是对象*/ Class i6=Integer[].class; System.out.println(i4==i6); //这样就可以,因为Integer[]里放的是对象所以可以String[]里面的对象比赛 System.out.println(i1.isPrimitive()); //判断i1是否是基本类型 System.out.println(i4.isArray()); //判断i4是否是数组类型 } }
用Class类获取类的信息
package JustTest; class Fu{} interface A{} interface B{} class Zi extends Fu implements A,B { public class imclass{} //定义一个内部类 public interface iminterface{} //定义一个内部接口 } public class ClassDemo { public static void main(String[] args) { Class c=Zi.class; System.out.println(c); //得到字节码 System.out.println(c.getPackage()); //得到包名 System.out.println(c.getName()); //得到全限定名 System.out.println(c.getSimpleName()); //得到类名 System.out.println(c.getSuperclass()); //得到父类 System.out.println(c.getSuperclass().getSimpleName()); //得到父类名 Class[] c2=c.getInterfaces(); //因为接口可以有很多个,所以用一数组装结果 for(Class c1:c2)//高级for循环迭代 { System.out.println(c1); } Class[] c3=c.getClasses(); //得到内部类和内部接口 for(Class c4:c3) { System.out.println(c4); } System.out.println(c.getModifiers()); //得到修饰符,如果返回1,则该类修饰符为public } }
得到构造方法和newInstance创建对象
用newInstance方法创建该class对象的实例,此类必须有无参的构造方法
如果构造方法被私有,在创建之前申请访问,也就是将AccessibleObject对象的setAccessible方法设为true
package JustTest; import java.lang.reflect.*; public class GetConStructor { public static void main(String[] args)throws Exception { Class c=String.class; Constructor[] con=c.getConstructors(); ////前面的修饰符必须是public才可以在这个方法下获取到 for(Constructor cons:con) { System.out.println(cons); } Constructor con2=c.getConstructor(String.class); //得到指定的构造函数,此函数必需是pulibc。 //参数是构造方法中的形参 String str=(String)con2.newInstance("abc"); //newInstance方法形参是Object,返回的也是Object,所以"abc"传到里面会向上转型 //赋值时必须向下转型 System.out.println(str); Constructor[] c2=c.getDeclaredConstructors(); //暴力反射,不管是否是public for(Constructor con3:c2) { System.out.println("暴力反射..."+con3); } } }
步骤
1:获取该类的字节码
2:用Class对象getConstructor()方法获取指定的构造方法
3:申请访问(如果构造方法为public可不用)
4:调用Constructor的newInstance方法创建对象
得到方法和反射调用方法
获得Method对象后,可以用Method中的invoke方法来执行指向的方法
invoke(Object obj,Object...args)obj表示方法的对象,args是方法的参数,如果方法是静态的那么第一个参数写null,形参亦此
package JustTest; import java.lang.reflect.*; public class GetMethod { public static void main(String[] args)throws Exception { String str="abcdefg"; Class c=String.class; Method[] m=c.getMethods(); //得到所有方法,包括父类的,但必须是被public修饰过的 for(Method ms:m) { System.out.println("getMethods.."+ms); } Method m1=c.getMethod("replace", char.class,char.class); //第一个参数是将要获取方法名,第二个参数是可变参数,是该方法的形参字节码 //该方法的作用是将字符串中的字符替换掉 str=(String)m1.invoke(str, 'a','b'); //invoke返回一个Object,要向下转型 //将a替换成b System.out.println(str); m=c.getDeclaredMethods(); for(Method ms:m) { System.out.println("暴力获取..."+ms); } } }
package JustTest; import java.lang.reflect.*; class Person { public String name; public int age; private char sex; Person(String name,int age,char sex) { this.name=name; this.age=age; this.sex=sex; } } public class GetField { public static void main(String[] args)throws Exception { Person p=new Person("张三",18,'m'); Class c=Person.class; Field[] fs=c.getFields(); //得到所有字段 for(Field f1:fs) { System.out.println("getFields..."+f1); } Field f=c.getField("name"); //得到Person中的name字段 System.out.println(f.get(p)); //将p对象中的name字段值打印出来 f.set(p,"李四"); //将p对象中的name改成"李四" Field f1=c.getDeclaredField("sex"); //强行指向sex字段 f1.setAccessible(true); //设置访问权限 f1.set(p,'w'); //将私有化的sex修改 System.out.println(f1.getChar(p)); } }