---------- android培训、java培训、期待与您交流! ----------
1、反射
(1)概述:反射就是将java的各种成分映射成相应的java类。在源程序中不确定要调用哪个类、构造方法、成员变量的时候就通过反射来获得。
(2)用Constructor类获取某类的构造函数。例如:用反射获得String s = new String("aaaa");实例
//String s = new String("aaaa") //获取字节码,如果清楚知道是什么类型可以加泛型,可以避免强转 Class<String> clazz = String.class; //用Constructor获得构造函数(String.class)这个参数决定获取的是什么构造函数 Constructor<String> cst = clazz.getConstructor(String.class); //获取对象,最后打印 String str = cst.newInstance("aaaa"); System.out.println(str);
例如:用反射获得String s = new String(new StringBuffer("abcd");实例
//String s = new String(new StringBuffer("abcd"); //下面可以这么简写,获取带StringBuffer的构造函数 Constructor cst =String.class.getConstructor(StringBuffer.class);
//没带泛型,需要强转 String str =(String)cst.newInstance(new StringBuffer("abcd"));
例如:存储String的所有构造方法(Method和Field同样可以采取此操作)
//把String类的构造方法以数组的形式存储,可以展示有什么构造方法 Constructor[] cst2 = String.class.getConstructors(); for(int x=0; x<cst2.length;x++) System.out.println(cst2[x]);(3)用Method类来获取方法,并用invoke调用。
例如:str为上例的String对象,用反射的形式调用str.charAt(1)
//str.charAt(1)反射的形式调用函数 //通过getclass()字节码再获取方法,("charAt", int.class)第一个参数是要获得的方法名字,第二个是要传递的参数类型,没参数用null表示。 Method mt = str.getClass().getMethod("charAt", int.class); //invke调用方法(str, 1)第一个参数是在什么对象上面的方法,如果这个参数为null则是在调用静态方法,第二个就是要传递的实际参数 System.out.println(mt.invoke(str, 1));(4)用Field类获取成员变量
例如:获取Math.PI的数值
//获取Math.PI的数值 //获得字节码,再从字节码中获得("PI")这里为获取成员变量的名字 Field field = Math.class.getField("PI"); //最后就打印该值,(Math.class)这里是在什么对象上的值 System.out.println(field.get(Math.class));
(5)反射实例编写一个类,增加一个实例方法,和一些属性。并使用反射手段创建该类的对象, 并调用该对象中的方法,并替换字符串属性中的所有k字母为q。public class ReflectTest {
public static void main(String[] args) throws Exception { //创建一个测试类的对象传递进去替换函数 swap(new ReflectTestClass()); } //替换和显示 public static void swap(Object obj) throws Exception { //获取字节码 Class clazz = obj.getClass(); //获取所有的方法。 Method[] mets = clazz.getMethods(); //获取指定的方法 Method met = clazz.getMethod(mets[0].getName(), null); //调用指定方法 met.invoke(obj, null); //获取所有的成员变量,并对他遍历 Field[] fields = clazz.getFields(); for(Field field : fields) { //判断成员变量是否字符串属性 if(field.getType()==String.class) { //获取字符串属性值 String oldValue = (String)field.get(obj); //替换这些值为指定的值 String newValue = oldValue.replace('k', 'q'); //最后设置这些成员属性的值,并显示 field.set(obj, newValue); System.out.println(field.get(obj)); } } } }
//辅助测试的类,定义一下的属性 public class ReflectTestClass { public String str1 = "kiss" , str2 = "kugoo" , str3 = "www" ; public double d =1.1; public void show() { System.out.println("This is ReflectClass"); } }
2、内省JavaBean
(1)JavaBeab是特殊的Java类,类中的方法以set哦get打头的类。可以将JavaBean当作普通的类来操作,而不可以将普通类当作JavaBean操作。一个类当作JavaBean使用时,可以根据方法的名字推断出Java的属性名。去掉get或set剩下的部分就是属性的名。剩下部分的第二个字母是小写,则第一个字母就是要变成小写。剩下部分的第二个字母是大写则第一个字母则是大写。例如:getSum 属性名为 sum ,getSSum 属性名为 SSum。(2) 存在一个JavaBean,它包含以下几种可能的属性: 1:boolean/Boolean 2:int/Integer 3:String 4:double/Double 属性名未知,现在要给这些属性设置默认值,以下是要求的默认值: String类型的默认值为字符串 www.itheima.com int/Integer类型的默认值为100 boolean/Boolean类型的默认值为true double/Double的默认值为0.01D. 只需要设置带有getXxx/isXxx/setXxx方法的属性,非JavaBean属性不设置,请用代码实public class javaBeanTest {
public static void main(String[] args) throws Exception { //获取测试类的字节码 Class clazz = Class.forName("exam.javaBeanElement"); //通过字节码获取对象 Object bean = clazz.newInstance(); //内省测试类,获取javaBean的属性信息 BeanInfo info = Introspector.getBeanInfo(clazz); //获取把javaBean属性数组 PropertyDescriptor[] pds = info.getPropertyDescriptors(); //for迭代每个具体的属性 for(PropertyDescriptor pd : pds) { //获取属性名 Object name = pd.getName(); //获取属性类型 Object type = pd.getPropertyType(); //获取get方法 Method getMethod = pd.getReadMethod(); //获取set方法 Method setMethod = pd.getWriteMethod(); //因为测试类是一个本类所以要去除它 if(!"class".equals(name)) { //调用修改前的属性 if(getMethod!=null) System.out.println("修改前:"+getMethod.invoke(bean, null)); //修改各种属性 if(type==String.class) setMethod.invoke(bean, "www.itcast.com"); else if(type==boolean.class) setMethod.invoke(bean, true); else if (type==double.class) setMethod.invoke(bean, 0.01d); else if(type==int.class) setMethod.invoke(bean, 100); //调用修改后的属性 if(getMethod!=null) System.out.println("修改后:"+getMethod.invoke(bean, null)); } } } }
//测试的类 class javaBeanElement { private boolean flag; private int x; private String str; private char[] ch; private long l; private double d; public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public int getX() { return x; } public void setX(int x) { this.x = x; } public String getStr() { return str; } public void setStr(String str) { this.str = str; } public double getD() { return d; } public void setD(double d) { this.d = d; } public void show(long l) { this.l = l; System.out.println("http://www.itcast.com"); } }
3、类加载器
(1)类加载器就是加载类的工具,Jvm运行的时候需要加载class文件,在内存中字节码。加载class,并生成字节码文件的过程是由类加载器完成的。因为类加载器也是java类,任何类都是需要类加载器加载的,所以一定有一个不是java类的加载器,BootStrap,Jvm还内置了2个类加载器,ExtClassLoader和AppClassLoader,他们是由BootStrap加载。
BootStrap:加载的是 java包,javax包,这些系统级的包,在JRE/lib/rt.jar包内。
ExtClassLoader则JRE/lib/ext/*.jar,这里是加载该目录下的所有jar包。
如果要手动编写System类的话就必须自己编写一个类加载器,不要委托机制才可以加载到。
(2)类加载器的委托机制
类加载器加载线程中的第一个类,如果这个类中还有其他类的话,则用这个类加载器加载其他的类。就是A类中引用了B类,那么加载AB类的加载器都是同一个。每个类加载器加载类的时候都会委托给上级加载,当上级没有加载到这个类的话就返回给原加载器,如果还是加载不到就会报异常ClassnotFoundException。
4、代理
(1)面向方面的编程AOP(Aspect Oriented Program)
系统中可能存在交叉业务需要切入到系统中的一方面,如:
安全 事务 日志 StudentService ---|----------|------------|------------- CourseService ----|----------|------------|------------- MiscService ------|----------|------------|-------------
面向方面的编程的目标就是要是交叉的业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码运行起来的效果是一样的,如:
------------------------------------------------------切面 func1 func2 func3 { { { .... .... ...... } } } ------------------------------------------------------切面 使用代理技术正好解决这样的问题,代理是实现AOP功能的核心和关键技术。
(2)Proxy类和InvocationHandler接口提供了生成动态代理的功能
例如:写一个ArrayList类的代理,实现和ArrayList中完全相同的功能,并可以计算每个方法运行的时间
public class Test1 { public static void main(String[] args) { //定义目标类 ArrayList target = new ArrayList(); //传递目标和系统功能到获取代理的函数//这里创建代理的时候必须是目标的父类 List proxyList = (List)getProxy(target,new getSystemRunTime()); //使用返回的代理并计算使用了多少时间 proxyList.add(1); proxyList.remove(0); proxyList.size(); } public static Object getProxy(final Object target,final getSystemRunTime time) { //建立代理 Object proxy = Proxy.newProxyInstance( target.getClass().getClassLoader(), //定义代理类的类加载器 target.getClass().getInterfaces(), //代理类要实现的接口列表 new InvocationHandler() //调用处理程序 { public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { //目标执行前代码 time.beforeCode(); //为了方便观看,设置了sleep Thread.sleep(new Random().nextInt(200)); //调用目标方法 Object obj = method.invoke(target, args); //目标执行后代码 time.afterCode(method); return obj; } }); //返回代理 return proxy; } }
//抽取出来的功能系统模版 abstract interface proxyAdvise { abstract void beforeCode(); abstract void afterCode(Method method); }//功能系统计算程序运行的时间 class getSystemRunTime implements proxyAdvise {private long starttime;public void beforeCode() { //获取目标程序运行前的时间 starttime = System.currentTimeMillis(); }public void afterCode(Method method) { //获取目标程序运行后的时间并显示总共运行了多久 long endtime = System.currentTimeMillis(); System.out.println(method.getName()+"\t"+"method is ran "+"\t"+(endtime-starttime)+" ms"); } }