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

----------    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");
   }
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值