黑马程序员——高新技术总结

来源:互联网 发布:巨龙之巢网络波动 编辑:程序博客网 时间:2024/06/07 22:38

------- android培训java培训、期待与您交流! ----------

反射

 

Class类

class类是对对象的抽象,而Class是对class的抽象,或者说类是对对象的共性的描述,而Class又是对类的共性的描述,但它本身又是一个类,它的具体实例是内存中某个类的字节码。

得到类的字节码的方式有三种:

  • 对象.getClass()
  • 类名.class
  • Class.forName("完整类名“)

Class.forName()的作用:如果有要获得的字节码存在于内存中就直接返回,如果不存在,则通过类加载器将其 .clas文件加载后返回。

九种预定义的Class实例对象:表示八个基本类型和void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即boolean、byte、char、short、int、long、float 和double。

数组的Class实例对象:类型[ ].class,可以用isArray()方法判断一个Class实例是否为数组。

String str = "abc";  Class cls1 = str.getClass();  Class cls2 = String.class;  Class cls3 = Class.forName("java.lang.String");    System.out.println(cls1 == cls2);  System.out.println(cls1 == cls3);    System.out.println(cls1.isPrimitive());   System.out.println(int.class.isPrimitive());  System.out.println(Integer.class.isPrimitive());  System.out.println(Integer.TYPE.isPrimitive());   System.out.println(int[].class.isArray());  

 

总之,反射就是把java类中的各种成分映射成java类。一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象,得到这些对象后有什么用?怎么用?是学习和应用的要点。

部分反射API

 

Construtcor类

得到某个类的所有构造方法:

Constructor[] constructors=String.class.getConstructors();Constructor[] constructors=String.class.getDeclaredConstructors();//包括私有的得到某个类的某个构造方法:会用到参数类型的Class对象Constructor constructor1 = String.class.getConstructor(StringBuffer.class);

创建实例对象:参数要用获得构造方法时指定的类型。

普通方式:String str = new String(new StringBuffer("abc"));  反射方式:String str1 =(String) constructor1.newInstance(new StringBuffer("abc"));  

Class也提供了newInstance,其内部是利用Constructor的newInstance的无参方法。

Field类

类的成员变量,它的具体实例代表的的是类中某个字段的定义,而非具体的变量。

public class ReflectPoint{     private int x;     public  int y;     public String str1 = "Master";     public String str2 = "Basketball";     public String str3 = "itcast";         public ReflectPoint(int x ,int y){        super();        this.x=x;        this.y = y;     }  }  
对于上边的类ReflectPoint如何获取其字段x,和y的值?
代码如下:
访问public成员变量:
ReflectPoint ref = new ReflectPoint(4,8);  Field fieldY =ref.getClass().getField("y");  System.out.println(fieldY.get(ref));

访问private成员变量:

//暴力反射,用getDeclaredField()取出包括私有在内的所有变量  Field fieldX =ref.getClass().getDeclaredField("x");  //将私有变量设为可访问的   fieldX.setAccessible(true);  System.out.println(fieldX.get(ref));  

 

综合应用案例:将RefectPoint中的所有String成员变量的值中的“a”,替换成“w”

private static void changeStringValue(Object obj) throws Exception {          Field [] fields = obj.getClass().getFields();          for(Field field:fields){              if(field.getType()==String.class){//字节码的比较用==更精确                   String str =(String) field.get(obj);                  String str1 = str.replace('a','w');                  field.set(obj, str1);                                }                        }      }  

 

 

类加载器

 

类加载器特点

  • 类加载器是加载类的工具,它的作用是将硬盘上的.class文件加进内存,并对之进行一些处理。
  • java虚拟机中可安装多个类加载器,系统默认三个主要的类加载器,每个类加载器负责加载特定的类:
    • BootStrap
    • xitClassLoader
    • AppClassLoader
  • 类加载器也是java类,因为其他是java类的类加载器也要被类加载器加载,显然必须有第一个类加载器不是java类, 这正是:BootStrap,它是由C++编写的。
  • java虚拟机中的所有类加载器采用具有  父子关系   的  树形结构  进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象,或者默认采用系统类加载器为其父级类加载器。
System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());  System.out.println(System.class.getClassLoader());

体系结构


    |---Bootstrap ClassLoader   ->JRE/lib/rt.jar
       |---Extension ClassLoader ->JRE/lib/ext/*.jar
          |---ApplicationClassLoader ->ClassPath指定的所有jar或目录。
             |--MyClassLoader ->指定的特殊目录
             |--itcastClassLoader->指定的特殊目录

  ClassLoader loader=ClassLoaderTest.class.getClassLoader();    while(loader!=null){       System.out.println(loader.getClass().getName());       loader=loader.getParent();         }    System.out.println(loader); 


 

委托机制 

委托机制的过程

  • 类加载器的选择:当java虚拟机要加载一个类时,到底派出那个类加载器去加载?
    • 首先当前线程的类加载器去加载线程中的第一个类。
    • 如果类A中引用了B类,java虚拟机将使用类A的加载器来加载类B
    • 还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
  • 类加载器怎样加载:每个类加载器加载类时,又先委托给器上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,不再去找发起者类加载器的儿子,因为没有getChild方法。
        

注意:需要说明一下 Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。

编写自己的类加载器

知识点

  • 自定义的类加载器必须继承ClassLoader。
  • loadClass方法与findClass方法:只需重新findClass方法,就会跳出委托机制。
  • defineClass方法。

编写步骤

  • 编写一个队文件内容进行监督加密的程序
  • 编写一个自己的类加载器,可实现对加密的类进行撞在和解码。
  • 编写一个程序调用类加载器加载类,在源程序中不能用该类定义引用变量,因为编程器无法识别这个类。程序中可以除了使用ClassLoader.load方法外,还可以使用使用设置线程的上下文加载器或者系统加载器,然后再使用Class.forName.

代码部分

要加载的测试类代码

注意:这里最好继承一个类,以便于获取其实例时,定义父类的引用,而不是它自己的引用。

编写自己的类加载器代码

调用自己写的类加载器

Class clazz = new MyClassLoader("itcastlib").loadClass("ClassLoaderAttachments");  Date d = (Date)clazz.newInstance();  System.out.println(d.toString());  


 

 

JavaBean内省与beanutils工具包

JavaBean

JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。

特点

JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。去掉set和get前缀,剩余部分就是属性名。如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。JavaBean必须有一个不带参数的构造方法。

用途

如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。

好处

一个符合JavaBean特点的类可以当作普通类一样进行使用,但如果把它当做JavaBean,那么就可以调用JDK提供的对专门对JavaBean进行操作的API,以实现对一些对普通类来说比较复杂的功能。

对JavaBean的简单内省操作 

用java.beans包中的PropertyDescriptor类把ReflectPoint当做JavaBean进行操作。

public static void setProperty(Object pt1, String propertyName,Object value) throws IntrospectionException,IllegalAccessException, InvocationTargetException {      PropertyDescriptor dp1 = new PropertyDescriptor(propertyName,pt1.getClass());      Method methodSetX = dp1.getWriteMethod();      methodSetX.invoke(pt1,value);  }  
public static Object getProperty(Object pt1, String propertyName) throws IntrospectionException, IllegalAccessException,InvocationTargetException {      PropertyDescriptor dp = new PropertyDescriptor(propertyName,pt1.getClass());      Method methodGetX = dp.getReadMethod();           Object retVal = methodGetX.invoke(pt1);      return retVal;  }  
ReflectPoint pt1 = new ReflectPoint(1,1);  String propertyName = "x";        Object retVal = getProperty(pt1, propertyName);  System.out.println("getX:"+retVal);  Object value = 7;    setProperty(pt1, propertyName, value);        System.out.println("setX:"+pt1.getX());


 

使用BeanInfo类和IntroSpector类查看把ReflectPoint当做一个JavaBean看时,显示的信息,并获取"x"属性的值(即用另一种方式,实现3中getProperty方法)
public static Object getProperty(Object pt1, String propertyName) throws IntrospectionException, IllegalAccessException,InvocationTargetException {      BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());      PropertyDescriptor[] dps = beanInfo.getPropertyDescriptors();      Object retVal = null;             for(PropertyDescriptor dp:dps)      {          if(dp.getName().equals(propertyName)){              retVal = dp.getReadMethod().invoke(pt1);                              break;          }                 }             return retVal;   

BeanUtils工具包

Apache提供的开源的操作JavaBean的工具包,它要和Apache的logging工具包导入到Project中,然后Build Path才可以使用。
里边的BeanUtil和PropertyUtils类使用示例如下:

 

 

 

------- android培训java培训、期待与您交流! ----------