一、
内省:Introspector(对javaBean进行操作)-->JavaBean:特殊的java类
JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。
这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?
JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,至于你把它存到哪个变量上,用管吗?
如果方法名为getId,中文意思即为获取id,至于你从哪个变量上取,用管吗?去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。
setId()的属性名?id
isLast()的属性名?last
setCPU的属性名是什么??CPU
getUPS的属性名是什么??UPS
总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。
一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当JavaBean用肯定需要带来一些额外的好处,我们才会去了解和应用JavaBean!好处如下:
在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作,别人都这么用和要求这么做,那你就没什么挑选的余地!
JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来访问私有的x,怎么做,有一定难度吧?用内省这套api操作JavaBean比用普通类的方式更方便。
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">public class IntroSpectorTest { /** * @param args * @throws IntrospectionException */ public static void main(String[] args) throws Exception { // TODO Auto-generated method stub ReflectPoint pt1=new ReflectPoint(4,5); String propertyName="x"; //"x"-->"X"-->"getX"-->MethodGetX--> /*get方法*/ Object retVal = getProperty(pt1, propertyName); System.out.println(retVal); /*Set方法 */ /*为了让Refact中的抽象成方法功能识别当中的参数,将传入的值7拿出来*/ Object value=7; setProperties(pt1, propertyName, value); System.out.println(pt1.getX()); } //以下两方法是右键-Refact-Extract Method的抽取方法功能自动生成的。 private static void setProperties(ReflectPoint pt1, String propertyName, Object value) throws IntrospectionException, IllegalAccessException, InvocationTargetException { //PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性 //构造方法接收两个参数:属性名,类的字节码。 PropertyDescriptor pd2=new PropertyDescriptor(propertyName,pt1.getClass());//属性名,哪个类 Method methodSetX=pd2.getWriteMethod();//得到x的读方法 methodSetX.invoke(pt1,value);//调用x的get方法。 } private static Object getProperty(Object pt1, String propertyName) throws IntrospectionException, IllegalAccessException, InvocationTargetException { /* PropertyDescriptor pd=new PropertyDescriptor(propertyName,pt1.getClass());//属性名,哪个类 //PropertyDescriptor:属性描述类 Method methodGetX=pd.getReadMethod();//得到x的读方法 Object retVal=methodGetX.invoke(pt1);//调用x的get方法。 */ /*另方法:较复杂*/ /*Introspector 类为通过工具学习有关受目标 Java Bean 支持的属性、事件和方法的知识提供了一个标准方法。 * * Introspector.getBeanInfo(Class<?> beanClass) 在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件 */ BeanInfo beanInfo=Introspector.getBeanInfo(pt1.getClass());//内省Introspector方式,查看JavaBean属性 PropertyDescriptor[] pds=beanInfo.getPropertyDescriptors(); Object retVal=null; for(PropertyDescriptor pd:pds) { if(pd.getName().equals(propertyName)) { Method methodGetX=pd.getReadMethod(); retVal=methodGetX.invoke(pt1); break; } } return retVal; } }</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">System.out.println(BeanUtils.getProperty(pt1, "x")); BeanUtils.setProperty(pt1, "x", "9");//注意9是字符串形式 System.out.println(pt1.getX()); BeanUtils.setProperty(pt1, "birthday.time", 111);//在类中有个birthday属性,在birthday //属性中有个time属性,该工具的方法支持级联操作,直接操作time System.out.println(BeanUtils.getProperty(pt1,"birthday.time")); /* BeanUtils工具包里还提供了JavaBean与map的对应关系: JavaBean-->map 方法:describe(java.lang.Object bean) map-->JavaBean 方法:Populate(java.lang.Object bean,java.util.Map properties) //java7新特性 Map map={name:"zxx",age:18}; BeanUtils.setProperty(map,"name","lhm");//用BeanUtils工具设置map */ //PropertyUtils工具操作JavaBean PropertyUtils.setProperty(pt1, "x", 9);//9是int型 System.out.println(PropertyUtils.getProperty(pt1, "x")); </span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">@SuppressWarnings("deprecation")//禁止警告过时 public static void main(String[] args) { // TODO Auto-generated method stub System.runFinalizersOnExit(true); //该方法已过时,加上以上注解,编译器就不提示过时了 } @Deprecated//说明以下方法已过时 public static void sayHello() { System.out.print("hi,传智播客"); } @Override//此注解告诉编译器你在覆盖方法,当你出错时,编译器就会告诉你 public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ReflectPoint other = (ReflectPoint) obj; if (x != other.x) return false; if (y != other.y) return false; return true; } </span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">//注解类 @Retention(RetentionPolicy.RUNTIME)//元注解,注解类的注解,让该自定义注解保持到运行时 public @interface ItcastAnnotation { } //带有注解类的注解 @ItcastAnnotation public class AnnotationTest { //对应用了注解类的类进行反射操作 @ItcastAnnotation public class AnnotationTest { public static void main(String[] args) { //对应用了注解类的类进行反射操作 if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)) { ItcastAnnotation annotation=(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class); System.out.println(annotation); } } </span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">@Retention(RetentionPolicy.RUNTIME)//元注解,注解类的注解 @Target({ElementType.METHOD,ElementType.TYPE}) public @interface ItcastAnnotation { String color() default "blue";//注解的属性。类似一个方法,返回的是String类型 String value(); int[] arrayAttr() default{2,3,4};//数组类型 的属性 EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.GREEN;//枚举类型的属性。 } //加注解的注解类 @ItcastAnnotation(color="red",value="abc",arrayAttr={1,2,3}) public class AnnotationTest { @ItcastAnnotation("xyz")//当注解类中只有一个需要初始化的属性时,括号内不需要写属性名称。 public static void main(String[] args) { if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)) { ItcastAnnotation annotation=(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class); System.out.println(annotation.color()); System.out.println(annotation.value()); System.out.println(annotation.arrayAttr().length); System.out.println(annotation.lamp().nextLamp()); } } </span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">import java.lang.reflect.Constructor; import java.util.ArrayList; public class GenericTest { /** * @param args */ public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub ArrayList collection1=new ArrayList(); collection1.add(1); collection1.add(1L); collection1.add("abc"); // int i=(Integer)collection1.get(1); //取出的数据不能进行Integer转换,报错,所以考虑到用泛型 //集合中用到了泛型 ArrayList<String> collection2=new ArrayList<String>(); //collection2.add(1); //collection2.add(1L); collection2.add("abc"); String element=collection2.get(0); //在反射中也用到了泛型 Constructor<String> constructor1=String.class.getConstructor(StringBuffer.class);//泛型指定是谁的构造方法 String str2=(String)constructor1.newInstance(new StringBuffer("abc")); System.out.println(str2.charAt(2));//c } } </span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">//集合中用到了泛型 ArrayList<String> collection2=new ArrayList<String>(); //collection2.add(1); //collection2.add(1L); collection2.add("abc"); String element=collection2.get(0); //以下证明泛型只在编译时有用 ArrayList<Integer> collection3=new ArrayList<Integer>(); System.out.println(collection3.getClass()==collection2.getClass()); //返回结果为true,说明在运行时,collection2与collection3的字节码是一样的,即泛型只在编译时有用。 //那么就可以用反射的方式绕过泛型这一特点,使只接收Integer类型的集合,接收字符串 collection3.getClass().getMethod("add", Object.class).invoke(collection3,"abc"); System.out.println(collection3.get(0)); </span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">错误方式: public static void printCollection(Collection<Object> cols) { for(Object obj:cols) { System.out.println(obj); } /* cols.add("string");//没错 cols = new HashSet<Date>();//会报告错误!*/ } 正确方式: public static void printCollection(Collection<?> cols) { for(Object obj:cols) { System.out.println(obj); } //cols.add("string");//错误,因为传递过来的不一定是String cols.size();//没错,此方法与类型参数没有关系 cols = new HashSet<Date>(); }</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">public static void printCollection(Collection<?> collection) { //collection.add(1);错,因为不知道传过来的集合是什么类型,所以不能存值进去 System.out.println(collection.size()); for(Object obj :collection) { System.out.println(obj); } }</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">HashMap<String,Integer> maps=new HashMap<String,Integer>(); maps.put("ljx", 23); maps.put("zxz", 24); maps.put("xyk", 24); Set<Map.Entry<String,Integer>> entrySet=maps.entrySet(); for(Map.Entry<String,Integer> entry:entrySet) { System.out.println(entry.getKey()+"::"+entry.getValue()); } </span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">//示例1: public static void main(String[] args) { add(3,5);//只有引用类型才能作为泛型方法的实际参数. //此处进行了自动装箱拆箱功能,将int型变为Integer型 Number x1=add(3.5,3);//int float型的父类是Number Object x2=add(3,"abc");//int 字符串的父类是Object型 } private static <T> T add(T x,T y){//<T>:表示该方法声明了一个泛型,相当于告诉编译器T是什么!add前的T是add方法的返回类型 return null; } 示例2: 注意:只有引用类型才能作为泛型方法的实际参数 //自定义泛型方法 swap(new String[]{"abc","xyz","ljx"},1,2); //swap(new int[]{1,2,3},1,2);报错,只有引用类型才能作为泛型方法的实际参数,int型不是引用类型 } private static <T> void swap(T[]a,int i,int j){ T temp=a[i]; a[i]=a[j]; a[j]=temp; } </span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">//1.编写泛型方法,自动将Objec类型的对象转换成其他类型。 private static <T> T autoConvert(Object obj) { return (T)obj; } Object obj="abc"; String x3=autoConvert(obj);//要求String类型的,antoConvert就返回String类型的数据 //2.定义一个方法,可以将任意类型的数组中的所有元素填充为相应的类型的某个对象。 private static <T>void fillArray(T[]a,T obj) { for(int i=0;i<a.length;i++) { a[i]=obj; } } //3.采用自定义泛型方法打印出任意参数化类型的集合中的所有内容。 public static<T>void printCollection3(Collection<T> collection) { for(Object obj:collection) { System.out.println(obj); } } //4.定义一个方法,把任意参数类型的集合中的数据安全的复制到 相应类型的数组中。 public static <T>void copy1(Collection<T> dest,T[]src) { } //定义一个方法,把任意参数类型的数组 的数据安全的复制到 相应类型的数组中。 public static <T>void copy2(T[] dest,T[]src) { } copy1(new Vector<String>(),new String[10]); copy2(new Date[10],new String[10]); /copy1(new Vector<Date>(),new String[10]);/ //此处会报错,因为泛型具有传递性,在new Vector<Date>时,泛型认为是Date型, //泛型为Date型,那么在调用copy1方法时,T就认为是Date类型,当传进String类型时,就会出错。</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;color:#333333;">Vector<Date> v1=new Vector<Date>(); //怎么获得上式中v1实际装载的数据的类型呢?因为泛型编译阶段就消失了,显然不能在运行是直接获得 //可把要求的参数类型放在一个方法中,通过反射获得泛型的实际类型参数,因为方法字节码提供了一个得到参数类型的方法。 public static void applyVector(Vector<Date> v1) { } 然后通过以下方法: Method applyMethod=GenericTest.class.getMethod("applyVector", Vector.class); Type[] types=applyMethod.getGenericParameterTypes();//该方法可获得指定方法的参数类型 ParameterizedType pType=(ParameterizedType)types[0];//ParameterizedType是参数类型 System.out.println(pType.getRawType());//结果:Vector,getRawType()得到原始类型 System.out.println(pType.getActualTypeArguments()[0]);//,getActualTypeArguments得到实际化类型,因为可能有多个,如HashMap<T,E>,是个数组 public static void applyVector(Vector<Date> v1) { }</span>
|
System classLoader--> AppClassLoader-------->CLASSPATH指定的所有jar或目录 ||
:MyClassLoader ItcastClassLoader-->指定的特殊目录public class ClassLoaderTest { public static void main(String[] args) { // TODO Auto-generated method stub System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName()); //类加载器:sun.misc.Launcher$AppClassLoader System.out.println(System.class.getClassLoader()); //System类的加载器不是通天的类加载器,是BootStrap(不是一个类,而是在虚拟机内核里的),所以该行的返回值是null ClassLoader loader=ClassLoaderTest.class.getClassLoader(); while(loader!=null) { System.out.println(loader.getClass().getName()); loader=loader.getParent(); } System.out.println(loader); } }
//加密解密类: public class MyClassLoader extends ClassLoader { public static void main(String[] args) throws Exception { //对srcPath路径的类进行加密,输出到destDir String srcPath=args[0]; String destDir=args[1]; FileInputStream fis=new FileInputStream(srcPath); String destFileName=srcPath.substring(srcPath.lastIndexOf("\\")+1); String destPath=destDir+"\\"+destFileName; FileOutputStream fos=new FileOutputStream(destPath); cypher(fis,fos); fis.close(); fos.close(); } //加密算法,将输入流异或0xff后,写到输出流中。 private static void cypher(InputStream ips,OutputStream ops) throws IOException { int b=-1; while((b=ips.read())!=-1) { ops.write(b^0xff); } } private String classDir; @Override protected Class<?> findClass(String name) throws ClassNotFoundException { //解密方法:加载加密方法中生成的加密文件,解密后输出。 String classFileName=classDir+"\\"+name+".class"; try { FileInputStream fis=new FileInputStream(classFileName); ByteArrayOutputStream bos=new ByteArrayOutputStream(); cypher(fis, bos); fis.close(); byte[] bytes=bos.toByteArray(); return defineClass(bytes,0,bytes.length); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return super.findClass(name); } public MyClassLoader(String classDir) { this.classDir=classDir; } } //测试类: public class ClassLoaderTest { public static void main(String[] args) throws Exception { Class clazz=new MyClassLoader("itcastlib").loadClass("ClassLoaderAttachment"); Date d1=(Date)clazz.newInstance(); /*ClassLoaderAttachment d1=(Date)clazz.newInstance(); 不能写成这样,因为此时ClassLoaderAttachment是加密后乱码的文件, 编译器加载时会出错,应改成他的父类(在写该类时应该继承父类)就可以了。 */ System.out.println(d1); } }