黑马程序员----高新技术02

来源:互联网 发布:联瑞汇桔怎么样 知乎 编辑:程序博客网 时间:2024/04/29 19:53

----------    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加载。
黑马程序员_Java_反射、类加载器、bean、代理(复习中) - longlylong - longlylong
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");   }}