这是传智张孝祥老师Java高新技术的授课笔记
我认为讲的很棒,授课传送门以下:
Java高新技术html
public class Test { public static void main(String[] args) { WeekDay day1=WeekDay.FRI; System.out.println(day1.name()); System.out.println(day1.ordinal()); System.out.println(WeekDay.valueOf("SUN")); } } enum WeekDay{ SUN,MON,TUE,WED,THU,FRI,SAT; }
public class Test { public static void main(String[] args) { WeekDay day1=WeekDay.FRI; System.out.println(day1.name()); System.out.println(day1.ordinal()); System.out.println(WeekDay.valueOf("SUN")); } } enum WeekDay{ SUN(1),MON,TUE,WED,THU,FRI,SAT; private WeekDay(){//枚举类的静态变量在枚举被加载的时候就会建立,而且只能用私有修饰 System.out.println("none parameter"); } private WeekDay(int i){ System.out.println("parameter:"+i); } }
public class Test { public static void main(String[] args) { } } enum TrafficLamp{ RED(30) { @Override TrafficLamp nextLamp() { return GREEN; } },GREEN(45) { @Override TrafficLamp nextLamp() { return YELLOW; } },YELLOW(5) { @Override TrafficLamp nextLamp() { return RED; } }; abstract TrafficLamp nextLamp(); private int time; private TrafficLamp(int time){ this.time=time; } }
在Java中,每一个class都有一个相应的Class对象。也就是说,当咱们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。
得到class对象的方法有三种java
Class c1=Date.class; Class c2=new Date().getClass(); Class c3=Class.forName("java.util.Date"); System.out.println(c1==c2); System.out.println(c1==c3);
public boolean isPrimitive()断定指定的 Class 对象是否表示一个基本类型。
有九种预约义的 Class 对象,表示八个基本类型和 void。这些类对象由 Java 虚拟机建立,与其表示的基本类型同名,即 boolean、byte、char、short、int、long、float 和 double。 这些对象仅能经过下列声明为 public static final 的变量访问,也是使此方法返回 true 的仅有的几个 Class 对象。spring
public class Test { public static void main(String[] args) throws ClassNotFoundException { Class c1=Date.class; Class c2=int.class; Class c3=Integer.class; Class c4=Integer.TYPE; System.out.println(c1.isPrimitive()); System.out.println(c2.isPrimitive()); System.out.println(c3.isPrimitive()); System.out.println(c4.isPrimitive()); System.out.println(c2==c3); System.out.println(c2==c4); Class c5=int[].class; System.out.println(c5.isPrimitive()); System.out.println(c5.isArray()); } }
反射就是把类中的各类成分映射成相应的类,好比把“方法”映射成Method类,把“成员变量”映射成Field类等等apache
2.1 构造方法的反射应用bootstrap
public class Test { public static void main(String[] args) throws Exception{ Constructor constructor1=String.class.getConstructor(StringBuffer.class);//要是用类型 String str2=(String)constructor1.newInstance(new StringBuffer("abc"));//要使用以前类型相同的对象 System.out.println(str2); String str2=(String)Class.forName("java.lang.String").newInstance();//使用默认的构造方法 } }
2.2 成员变量的反射应用数组
“人有身高这一属性”与“我有身高这一属性不一样”,也与“个人身高是XXX”不一样安全
public class Test { public static void main(String[] args) throws Exception{ Person me=new Person(180,140); Field height_field=Person.class.getField("height"); //height_field指的是取得了Person这个类所具备的一个属性,即身高这样一个属性,并非取得的某我的的实际身高 System.out.println(height_field.get(me)); Field weight_field=Person.class.getDeclaredField("weight"); weight_field.setAccessible(true); System.out.println(weight_field.get(me)); } } class Person{ public int height; private int weight; public Person(int height, int weight) { super(); this.height = height; this.weight = weight; } }
修改某一对象中的成员变量举例:app
import java.lang.reflect.Field; public class Test { public static void main(String[] args) throws Exception{ ReflectPoint pt1=new ReflectPoint(3,5); Field[] fields=ReflectPoint.class.getFields(); for (Field field : fields) { if(field.getType()==String.class){ String oldValue=(String)field.get(pt1); String newValue=oldValue.replace("b", "a"); field.set(pt1, newValue); } } System.out.println(pt1); } } class ReflectPoint{ public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; } private int x; public int y; public String str1="ball"; public String str2="basketball"; public String str3="itcast"; @Override public String toString() { return "ReflectPoint [x=" + x + ", y=" + y + ", str1=" + str1 + ", str2=" + str2 + ", str3=" + str3 + "]"; } }
2.3 成员方法的反射框架
基本应用
“人有跳的能力”与“我有跳的能力”不同ide
public class Test { public static void main(String[] args) throws Exception{ Method methodCharAt=String.class.getMethod("charAt", int.class);//后面指的是传入的参数 //一样,这取得的是String类的这样一个方法,是一种属性,而不是某个对象的成员方法 System.out.println(methodCharAt.invoke("abcde", 1)); //someMethod.invoke(null,parameter)指的是调用的静态方法 } }
应用:
目标:写一个程序,这个程序可以根据用户提供的类名,去调用类方法
import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws Exception{ // TestArguments.main(new String[]{"111","222","333"}); String startingClassName=args[0]; Method mainMethod=Class.forName(startingClassName).getMethod("main", String[].class); mainMethod.invoke(null, (Object)new String[]{"111","222","333"}); /* 若是没有类型转换会出现problems * Type String[] of the last argument to method invoke(Object, Object...) * doesn't exactly match the vararg parameter type. Cast to Object[] to confirm the non-varargs invocation, * or pass individual arguments of type Object for a varargs invocation. */ } } class TestArguments{ public static void main(String[] args) { for (String string : args) { System.out.println(string); } } }
要修改run configuration
2.4 数组与Object的关系及其反射类型
维度与类型同时相同时,获得的class即相同
public class Test { public static void main(String[] args) throws Exception{ int[] a0=new int[3]; int[] a1=new int[3]; int[] a2=new int[4]; System.out.println(a0.getClass()==a1.getClass()); System.out.println(a1.getClass()==a2.getClass()); System.out.println(a1.getClass().getName()); } }
2.5 数组的反射应用
举例
public class Test { public static void main(String[] args) throws Exception{ printObject(new String[]{"a","b","c"}); printObject("xyz"); } private static void printObject(Object obj) { Class c=obj.getClass(); if(c.isArray()){ int len=Array.getLength(obj); for(int i=0;i<len;i++){ System.out.println(Array.get(obj, i)); } }else{ System.out.println(obj); } } }
2.6 ArrayList_HashSet的比较及Hashcode分析
先比较hashcode若是hashcode相同,则运行equels方法,二者同时相等时,则认定为相同对象,若是以后修改了参与运算hashcode的成员变量,则会形成内存溢出,以下例子中remove会失效
import java.util.HashSet; public class Test { public static void main(String[] args) throws Exception{ HashSet<TestArguments> set=new HashSet<>(); TestArguments t1=new TestArguments(3); TestArguments t2=new TestArguments(3); set.add(t1); set.add(t2); System.out.println(set.size()); t1.x=456; set.remove(t1); System.out.println(set.size()); } } class TestArguments{ int x; public TestArguments(int x) { super(); this.x = x; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + x; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TestArguments other = (TestArguments) obj; if (x != other.x) return false; return true; } }
框架
如今使用别人写的类的时候,有两种使用方式,一种是用户去使用别人的类(工具),另外一种是别人的类去调用用户写的类(框架)。再打个比方:好比我作房子卖给用户居住,由用户本身安装门窗和空调,我制做的房子就是框架,用户须要使用个人框架,把门窗插入进我提供的框架之中,即用户的门窗被房子调用,这就是框架。
框架要解决的核心问题
在写框架的时候并不知道用户要写的类名,因此框架中不能直接new某个类的实例对象,所以只能经过反射来作
代码举例
import java.io.FileInputStream; import java.io.InputStream; import java.util.Collection; import java.util.Properties; public class Test { public static void main(String[] args) throws Exception{ InputStream ips=new FileInputStream("config.properties"); Properties props=new Properties(); props.load(ips); ips.close(); String className=props.getProperty("className"); @SuppressWarnings("unchecked") Collection<ReflectPoint> collection=(Collection<ReflectPoint>)Class.forName(className).newInstance(); ReflectPoint pt1=new ReflectPoint(3,3); ReflectPoint pt2=new ReflectPoint(5,5); ReflectPoint pt3=new ReflectPoint(3,3); collection.add(pt1); collection.add(pt2); collection.add(pt3); System.out.println(collection.size()); } }
config.properties文件内容为
className=java.util.ArrayList
3.1 管理配置文件的方式
import java.io.FileInputStream; import java.io.InputStream; import java.util.Collection; import java.util.Properties; public class Test { public static void main(String[] args) throws Exception{ // InputStream ips=new FileInputStream("config.properties"); //如下的配置文件路径应该与该类的Java文件放在同一目录 // InputStream ips=ReflectPoint.class.getResourceAsStream("config.properties"); InputStream ips=ReflectPoint.class.getClassLoader().getResourceAsStream("zheteng/config.properties"); Properties props=new Properties();//此方法首先搜索资源的父类加载器;若是父类加载器为 null,则搜索的路径就是虚拟机的内置类加载器的路径。 props.load(ips); ips.close(); String className=props.getProperty("className"); @SuppressWarnings("unchecked") Collection<ReflectPoint> collection=(Collection<ReflectPoint>)Class.forName(className).newInstance(); ReflectPoint pt1=new ReflectPoint(3,3); ReflectPoint pt2=new ReflectPoint(5,5); ReflectPoint pt3=new ReflectPoint(3,3); collection.add(pt1); collection.add(pt2); collection.add(pt3); System.out.println(collection.size()); } } class ReflectPoint{ public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; } private int x; public int y; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + x; result = prime * result + y; return result; } @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; } }
JavaBean是特殊的Java类,使用Java语言书写,而且遵照JavaBean API规范。
接下来给出的是JavaBean与其它Java类相比而言独一无二的特征:
提供一个默认的无参构造函数。
须要被序列化而且实现了Serializable接口。
可能有一系列可读写属性。
可能有一系列的"getter"或"setter"方法。
Java bean 是个什么概念? - 回答做者: 杨博 通俗易懂
我认为,JavaBean的存在就是为了让类中的属性能更方便地被处理和提取
4.1 JavaBean的简单操做
import java.beans.PropertyDescriptor; import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws Exception { ReflectPoint pt1 = new ReflectPoint(3, 5); String propertyName = "x"; PropertyDescriptor pd = new PropertyDescriptor(propertyName, ReflectPoint.class); Method methodGetX = pd.getReadMethod(); Object retVal = methodGetX.invoke(pt1); System.out.println(retVal); Method methodSetX = pd.getWriteMethod(); methodSetX.invoke(pt1, 7); System.out.println(pt1.getX()); } } class ReflectPoint { public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; } private int x; private int y; public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } }
4.2 BeanUtils工具包操做JavaBean
须要BeanUtils与common.logging包
举例1:
import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.PropertyUtils; public class Test { public static void main(String[] args) throws Exception { ReflectPoint pt1 = new ReflectPoint(3, 5); System.out.println(BeanUtils.getProperty(pt1, "x")); System.out.println(BeanUtils.getProperty(pt1, "x").getClass().getName()); BeanUtils.setProperty(pt1, "x", "9");//以string的形式对javabean进行操做 System.out.println(pt1.getX()); BeanUtils.setProperty(pt1, "birthday.time", 111); System.out.println(BeanUtils.getProperty(pt1, "birthday.time")); PropertyUtils.setProperty(pt1, "x", 9);//以属性自己的类型的形式对javabean进行操做 System.out.println(PropertyUtils.getProperty(pt1, "x").getClass().getName()); } }
其中ReflectPoint为
import java.util.Date; public class ReflectPoint { public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; this.birthday = new Date(); } private int x; private int y; private Date birthday; public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
1.1 @Deprecated
public class AnnotationTest { public static void main(String[] args) { sayHello(); } @Deprecated public static void sayHello(){ System.out.println("hello!SF.GG!"); } }
1.2 @Override
@Override public String toString() { return "AnnotationTest []"; }
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @MyAnnotation public class AnnotationTest { public static void main(String[] args) { sayHello(); if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){ MyAnnotation myannotation=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class); System.out.println(myannotation); } } @Deprecated public static void sayHello(){ System.out.println("hello!SF.GG!"); } } @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD,ElementType.TYPE}) @interface MyAnnotation{ }
看起来注解就是为了方便为自定义的类打上一些标签的做用
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @MyAnnotation(color = "red", value = "abc", arrayValue = 1,annotationAttr=@MetaAnnotation("flx")) public class AnnotationTest { @MyAnnotation("xyz") // 当只有一个value属性须要赋值的时候,能够不用写value public static void main(String[] args) { sayHello(); if (AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation myannotation = (MyAnnotation) AnnotationTest.class.getAnnotation(MyAnnotation.class); System.out.println(myannotation.color()); System.out.println(myannotation.value()); System.out.println(myannotation.arrayValue().length); System.out.println(myannotation.trafficLamp().next()); System.out.println(myannotation.annotationAttr().value()); } } @Deprecated public static void sayHello() { System.out.println("hello!SF.GG!"); } } @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.TYPE }) @interface MyAnnotation { String color() default "blue"; String value(); int[] arrayValue() default { 3, 4, 4 }; Lamp trafficLamp() default Lamp.RED; MetaAnnotation annotationAttr() default @MetaAnnotation("lhm"); } @interface MetaAnnotation { String value(); } enum Lamp { RED, YELLOW, GREEN; Lamp next() { if (this.equals(RED)) { return GREEN; } if (this.equals(GREEN)) { return YELLOW; } else { return RED; } } }
import java.lang.reflect.Constructor; import java.util.ArrayList; public class Test { public static void main(String[] args) throws Exception { ArrayList<Object> collection1=new ArrayList<>(); collection1.add(1); collection1.add(1L); collection1.add("abc"); int i=(Integer) collection1.get(0); System.out.println(collection1.get(0) instanceof Integer); Constructor<String> constructer1=String.class.getConstructor(String.class); String str=constructer1.newInstance("abc"); System.out.println(str); } }
2.1.泛型是给编译器使用的,能够在限定集合中输入类型,让编译器挡住源程序中的非法输入,编译器编译生成的字节码会去掉方形的类型信息的,以下所示
import java.util.ArrayList; public class Test { public static void main(String[] args) throws Exception { ArrayList<String> collection2 = new ArrayList<>(); ArrayList<Integer> collection3 = new ArrayList<>(); System.out.println(collection2.getClass() == collection3.getClass()); } }
也所以,以下代码并非重载,是错误的,由于运行时会去泛型信息
public static void applyVector(Vector<Date> v1){ } public static void applyVector(Vector<String> v1){ }
就是说泛型只是给编译器看的,运行的时候就没有泛型信息了,也所以能够根据这种原理,以反射的原理获得集合再调用add方法,好比往上面collection3里添加String
import java.util.ArrayList; public class Test { public static void main(String[] args) throws Exception { ArrayList<String> collection2 = new ArrayList<>(); ArrayList<Integer> collection3 = new ArrayList<>(); System.out.println(collection2.getClass() == collection3.getClass()); // collection3.add("abc"); // 报错 collection3.getClass().getMethod("add", Object.class).invoke(collection3, 1); collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc"); System.out.println(collection3); } }
2.2 语法规定
ArrayList<E>称为泛型类型,E称为类型变量或类型参数,<>作typeof
参数化类型不考虑类型参数的继承关系,下面两个都是错误的
ArrayList<String> c=new ArrayList<Object>(); ArrayList<Object> b=new ArrayList<String>();
参数化和原始类型的兼容性,下面例子中C只能装string,而b能够加object,其实b那种写法和ArrayList b=new ArrayList()是同样的,由于泛型只是给编译器看的
ArrayList<String> c=new ArrayList(); c.add("asdf"); System.out.println(c.get(0).getClass()); ArrayList b=new ArrayList<String>(); b.add(456); b.add("asdf"); System.out.println(b.get(0).getClass()); System.out.println(b.get(1).getClass());
下面不报错的
ArrayList b=new ArrayList<String>(); ArrayList<Object> d=b;
2.3 泛型通配符
好比如今要打印一个类型参数是任意类型的集合,以下写法就是不对的
import java.util.ArrayList; import java.util.Collection; public class Test { public static void main(String[] args) throws Exception { ArrayList<String> collection2 = new ArrayList<>(); ArrayList<Integer> collection3 = new ArrayList<>(); System.out.println(collection3); printCollection(collection3);//编译器不经过,由于以前说过,泛型类型并不存在类型参数的继承关系 } public static void printCollection(Collection<Object> collection){ } }
这就须要通配符了
import java.util.ArrayList; import java.util.Collection; public class Test { public static void main(String[] args) throws Exception { ArrayList<String> collection2 = new ArrayList<>(); ArrayList<Integer> collection3 = new ArrayList<>(); System.out.println(collection3); printCollection(collection3);//编译器不经过,由于以前说过,泛型类型并不存在类型参数的继承关系 } public static void printCollection(Collection<?> collection){ // collection.add(123); // 会报错,由于使用了通配符,所以不能调用与类型参数相关的方法 // 参数(int)不适用于Collection <capture#1-of?>类型的add(capture#1-of?)方法, collection.size();//这就没错,由于size方法与类型参数没有关系 for (Object object : collection) { System.out.println(object); } } }
使用?通配符能够引用各类参数类型,其主要做用是引用,而不是写入
通配符也有拓展功能
限定上边界
? extends Number要求传入的必须是Number的子类
限定下边界
? super Integer要求传入的必须是Integer的父类
3.1 泛型方法
public class Test { public static void main(String[] args) throws Exception { //结果就是两者的交集 Number num=add(3,51.0); Integer inte=add(3,51); Object o=add(3,"123"); swap(new String[]{"aaa","bbb","ccc"},1,2); // swap(new int[]{123,456,789},1,2);//泛型变量只能是引用对象,int[]已是一个基本类型的数组,它并不能完成自动装箱 } private static <T> T add(T x,T y){ return null; } private static <T> void swap(T[] a,int i,int j){ T temp=a[i]; a[i]=a[j]; a[j]=temp; } private static <T extends Exception> void sayHello() throws T{ try{ }catch(Exception e){//必须明确是哪一个异常,不能catch T throw (T)e; } } }
3.2 在类上定义泛型
就是为了保障类中的泛型可以统一,为此能够在类上定义泛型
public class Test { public static void main(String[] args) throws Exception { GenericDao<String> dao=new GenericDao<>(); dao.add("123"); } } class GenericDao<T>{ public void add(T x){ } public T getByID(int id){ return null; } public void delete(T obj){ } }
3.3 经过反射得到泛型的实际类型参数
以前说过,泛型是给编译器看的,所以假若有一个变量Vector<String> v1,仅仅从v1这个变量,是无法知道这个Vector里的泛型究竟是什么的,所以经过其余一种方法得到,
import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Date; import java.util.Vector; public class Test { public static void main(String[] args) throws Exception { Method applyMethod=Test.class.getMethod("applyVector", Vector.class); Type[] types=applyMethod.getGenericParameterTypes(); /* * 按照声明顺序返回 Type 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型的。若是底层方法不带参数,则返回长度为 0 的数组。 * 若是形参类型是参数化类型,则为其返回的Type对象必须实际反映源代码中使用的实际类型参数。 * 若是形参类型是类型变量或参数化类型,则建立它。不然将解析它。 */ ParameterizedType ptype=(ParameterizedType)types[0]; System.out.println(ptype.getRawType()); /* * 返回 Type 对象,表示声明此类型的类或接口。 */ System.out.println(ptype.getActualTypeArguments()[0]); /* * 返回表示此类型实际类型参数的 Type 对象的数组。 */ } public static void applyVector(Vector<Date> v1){ } }
要使用这个类,就要把.class文件加载进虚拟机,而后进行处理,就须要类加载器,Java虚拟机中能够安装多个类加载器,系统默认三个主要加载器,每一个加载器都加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader
类加载器自己也是一个Java类,所以也须要被加载,所以一个特殊的加载器,即BootStrap,它不是一个Java类
而Java虚拟机中全部类加载器采用具备父子关系的树形结构进行组织,在实例化每一个类加载器对象以前,须要指定一个父极类加载器对象
public class Test { public static void main(String[] args) throws Exception { System.out.println(Test.class.getClassLoader().getClass()); System.out.println(System.class.getClassLoader()); // null,说明这是又bootstrap类加载器加载的 ClassLoader loader=Test.class.getClassLoader(); while(loader!=null){ System.out.println(loader.getClass()); loader=loader.getParent(); } } }
(太困了扛不住了)
首先搞一个类的加密器,将类文件进行二进制简单加密,用生成的类文件覆盖掉本来的类文件后,再次运行程序,发现类加载错误
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; public class MyClassLoader { public static void main(String[] args) throws Exception { String srcPath = "bin/zheteng/ClassLoaderAttachment.class"; String destPath = "ClassLoaderAttachment.class"; FileInputStream fis = new FileInputStream(srcPath); FileOutputStream fos = new FileOutputStream(destPath); cypher(fis,fos); fis.close(); fos.close(); System.out.println(new ClassLoaderAttachment().toString()); } private static void cypher(InputStream ips, OutputStream ops) throws Exception { int b = -1; while ((b = ips.read()) != -1) { ops.write(b ^ 0xff); } } } class ClassLoaderAttachment extends Date { /** * */ private static final long serialVersionUID = -1118939564631068343L; public String toString(){ return "hello,world"; } }
下面再搞一个解密的类加载器
import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; public class MyClassLoader extends ClassLoader { public static void main(String[] args) throws Exception { String srcPath = "bin/zheteng/ClassLoaderAttachment.class"; String destPath = "ClassLoaderAttachment.class"; FileInputStream fis = new FileInputStream(srcPath); FileOutputStream fos = new FileOutputStream(destPath); cypher(fis, fos); fis.close(); fos.close(); System.out.println(new ClassLoaderAttachment()); Class d1 = new MyClassLoader().loadClass("ClassLoaderAttachment.class"); Date d = (Date) d1.newInstance(); System.out.println(d.toString()); } private static void cypher(InputStream ips, OutputStream ops) throws Exception { int b = -1; while ((b = ips.read()) != -1) { ops.write(b ^ 0xff); } } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String classFileNmae = name; try { System.out.println(name); FileInputStream fis = new FileInputStream(classFileNmae); 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() { } }
此次的attachment必须定义为public类不然上面的反射会异常访问权限报错
import java.util.Date; public class ClassLoaderAttachment extends Date { /** * */ private static final long serialVersionUID = -1118939564631068343L; public String toString(){ return "hello,worldxx"; } }
其实我以为这块讲的我没太听明白,之后看thingking in java的时候再补上吧
1.1 代理
要为已存在的具备相同接口的目标类的各个方法添加一套系统功能,如异常处理,日志记录等,如
class x{ A void sayHello{ syso:hello; } B }
如今想在AB两点记录时间,测试运行时间,并且没有程序的源代码,该如何处理
须要定义一个 新的代理类
XProxy { void sayHello{ starttime syso:hello endtime } }
至关于用这个代理来运行这个程序,以完成相应的目的,这就是代理的做用。代理类的每一个方法调用目标类的相同方法,并在调用方法时加上系统功能额代码
若是采用工行模式和配置文件的方式进行管理,则不须要修改客户端程序,在配置文件中修改,来配置使用目标类仍是代理类,就很方便
1.2 AOP
安全,事务,日志等功能贯穿到不少模块中,因此是交叉业务
能够运用代理的方法,来将交叉功能与实际功能区分开
1.3 动态代理技术
要为系统中的各个接口的实现类添加代理功能,会须要太多的代理类,所有采用静态代理的方式(就像AOP图中的从method到func)就很是麻烦,所以须要动态代理类
JVM能够在运行期动态生成出类的字节码,这种类会用来作动态代理功能 。JVM生成的动态类必须实现至少一个接口,因此JVM生成的动态类只能用做具备相同接口的目标类的代理。但若是这个目标类没有接口呢,那JVM就不能生成这个类的动态类了。
这就须要CGLIB库能够动态生成一个类的子类,一个类的子类也能够用做该类的代理,因此要为一个没实现接口的目标类生成动态代理类,则须要CGLIB库
代理类的各个方法除了要调用目标的相应方法和对外返回目标方法返回结果外,还能够在以下四个位置添加各类功能:
调用目标方法前
调用目标方法后
调用目标方法先后
在处理目标方法异常的catch块中
2.1 首先来看看动态类的名字,构造方法和其余方法
import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Collection; public class Test { public static void main(String[] args) throws Exception { Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);// 生成的动态类要为其指定类加载器与接口 System.out.println(clazzProxy1.getName()); Constructor[] constructors = clazzProxy1.getConstructors(); System.out.println("--------------------begin constructors list"); for (Constructor constructor : constructors) { String name = constructor.getName(); StringBuilder sBuilder=new StringBuilder(name); sBuilder.append("("); Class[] clazzParams=constructor.getParameterTypes(); for (Class clazzParam : clazzParams) { sBuilder.append(clazzParam.getName()).append(","); } sBuilder.append(")"); System.out.println(sBuilder); } Method[] methods = clazzProxy1.getMethods(); System.out.println("---------------------begin methods list"); for (Method method : methods) { String name = method.getName(); StringBuilder sBuilder=new StringBuilder(name); sBuilder.append("("); Class[] clazzParams=method.getParameterTypes(); for (Class clazzParam : clazzParams) { sBuilder.append(clazzParam.getName()).append(","); } sBuilder.append(")"); System.out.println(sBuilder); } } }
2.2 再来生成一个这个类的实例对象,三种方法
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Collection; public class Test { public static void main(String[] args) throws Exception { Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); // 生成的动态类要为其指定类加载器与接口,通常使用接口所用的加载器 System.out.println(clazzProxy1.getName()); Constructor[] constructors = clazzProxy1.getConstructors(); System.out.println("--------------------begin constructors list"); for (Constructor constructor : constructors) { String name = constructor.getName(); StringBuilder sBuilder=new StringBuilder(name); sBuilder.append("("); Class[] clazzParams=constructor.getParameterTypes(); for (Class clazzParam : clazzParams) { sBuilder.append(clazzParam.getName()).append(","); } sBuilder.append(")"); System.out.println(sBuilder); } Method[] methods = clazzProxy1.getMethods(); System.out.println("---------------------begin methods list"); for (Method method : methods) { String name = method.getName(); StringBuilder sBuilder=new StringBuilder(name); sBuilder.append("("); Class[] clazzParams=method.getParameterTypes(); for (Class clazzParam : clazzParams) { sBuilder.append(clazzParam.getName()).append(","); } sBuilder.append(")"); System.out.println(sBuilder); } System.out.println("---------------------begin create instance"); Constructor constructor=clazzProxy1.getConstructor(InvocationHandler.class); class MyInvocationHandler1 implements InvocationHandler{ @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { // TODO Auto-generated method stub return null; } } Collection proxy1=(Collection)constructor.newInstance(new MyInvocationHandler1()); //建立的就是collection的子类 System.out.println(proxy1); System.out.println(proxy1.toString());//说明proxy1并非个空指针 Collection proxy2=(Collection)constructor.newInstance(new InvocationHandler(){ @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { return null; } }); Collection proxy3=(Collection)Proxy.newProxyInstance(Collection.class.getClassLoader(), new Class[]{ Collection.class }, new InvocationHandler() { @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { return null; } }); } }
2.3 来看看InvocationHandler有什么用
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collection; public class Test { public static void main(String[] args) throws Exception { Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); // 生成的动态类要为其指定类加载器与接口,通常使用接口所用的加载器 System.out.println(clazzProxy1.getName()); Constructor[] constructors = clazzProxy1.getConstructors(); System.out.println("--------------------begin constructors list"); for (Constructor constructor : constructors) { String name = constructor.getName(); StringBuilder sBuilder=new StringBuilder(name); sBuilder.append("("); Class[] clazzParams=constructor.getParameterTypes(); for (Class clazzParam : clazzParams) { sBuilder.append(clazzParam.getName()).append(","); } sBuilder.append(")"); System.out.println(sBuilder); } Method[] methods = clazzProxy1.getMethods(); System.out.println("---------------------begin methods list"); for (Method method : methods) { String name = method.getName(); StringBuilder sBuilder=new StringBuilder(name); sBuilder.append("("); Class[] clazzParams=method.getParameterTypes(); for (Class clazzParam : clazzParams) { sBuilder.append(clazzParam.getName()).append(","); } sBuilder.append(")"); System.out.println(sBuilder); } System.out.println("---------------------begin create instance"); Constructor constructor=clazzProxy1.getConstructor(InvocationHandler.class); class MyInvocationHandler1 implements InvocationHandler{ @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { // TODO Auto-generated method stub return null; } } Collection proxy1=(Collection)constructor.newInstance(new MyInvocationHandler1()); //建立的就是collection的子类 System.out.println(proxy1); System.out.println(proxy1.toString());//说明proxy1并非个空指针 Collection proxy2=(Collection)constructor.newInstance(new InvocationHandler(){ @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { return null; } }); Collection proxy3=(Collection)Proxy.newProxyInstance(Collection.class.getClassLoader(), new Class[]{ Collection.class }, new InvocationHandler() { ArrayList target=new ArrayList(); @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { long beginTime=System.currentTimeMillis(); Object reVal=paramMethod.invoke(target, paramArrayOfObject); long endTime=System.currentTimeMillis(); System.out.println(paramMethod.getName()+" running time of "+(endTime-beginTime)); return reVal; } }); proxy3.add("zzz"); proxy3.add("dddd"); proxy3.add("yyyy"); /* * 在调用这个方法的时候,他都会找InvocationHandler的invoke方法 */ System.out.println(proxy3.size()); } }
实现原理解释
构造方法中接受了一个InvocationHandler对象,在新建动态类实例对象以后,该对象调用一个方法的时候,好比上面调用了add方法,这个对象会实际是调用了proxy3的invoke方法,大概就像下面这样
boolean add(Object paramE){ return handler.invoke(this,this.getClass().getMethod("add", paramE.getClass()),paramE) }
注意,oject方法中只将hashcode,tostring,equal下发使用
在实际状况中,应该将须要被处理(或者说添加功能)的对象与要添加的功能与动态代理类分开,这样在应用的时候,只须要传入对象与功能,就能够实现动态代理,而不须要为每一个要添加的功能单独写一个动态代理类,把上面的例子改一下,结果以下:
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collection; public class Test { public static void main(String[] args) throws Exception { Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); // 生成的动态类要为其指定类加载器与接口,通常使用接口所用的加载器 System.out.println(clazzProxy1.getName()); Constructor[] constructors = clazzProxy1.getConstructors(); System.out.println("--------------------begin constructors list"); for (Constructor constructor : constructors) { String name = constructor.getName(); StringBuilder sBuilder=new StringBuilder(name); sBuilder.append("("); Class[] clazzParams=constructor.getParameterTypes(); for (Class clazzParam : clazzParams) { sBuilder.append(clazzParam.getName()).append(","); } sBuilder.append(")"); System.out.println(sBuilder); } Method[] methods = clazzProxy1.getMethods(); System.out.println("---------------------begin methods list"); for (Method method : methods) { String name = method.getName(); StringBuilder sBuilder=new StringBuilder(name); sBuilder.append("("); Class[] clazzParams=method.getParameterTypes(); for (Class clazzParam : clazzParams) { sBuilder.append(clazzParam.getName()).append(","); } sBuilder.append(")"); System.out.println(sBuilder); } System.out.println("---------------------begin create instance"); Constructor constructor=clazzProxy1.getConstructor(InvocationHandler.class); class MyInvocationHandler1 implements InvocationHandler{ @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { // TODO Auto-generated method stub return null; } } Collection proxy1=(Collection)constructor.newInstance(new MyInvocationHandler1()); //建立的就是collection的子类 System.out.println(proxy1); System.out.println(proxy1.toString());//说明proxy1并非个空指针 Collection proxy2=(Collection)constructor.newInstance(new InvocationHandler(){ @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { return null; } }); ArrayList target=new ArrayList(); Collection proxy3=(Collection)getProxy(target,new MyAdvice()); proxy3.add("zzz"); proxy3.add("dddd"); proxy3.add("yyyy"); /* * 在调用这个方法的时候,他都会找InvocationHandler的invoke方法 */ System.out.println(proxy3.size()); System.out.println(proxy3); } private static Object getProxy(Object target,Advice advisor) { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { advisor.beforeMethod(paramMethod); Object reVal=paramMethod.invoke(target, paramArrayOfObject); advisor.afterMethod(paramMethod); return reVal; } }); } } interface Advice{ void beforeMethod(Method method); void afterMethod(Method method); } class MyAdvice implements Advice{ long beginTime=0; @Override public void afterMethod(Method method) { System.out.println("结束"); long endTime=System.currentTimeMillis(); System.out.println(method.getName()+" running time of "+(endTime-beginTime)); } @Override public void beforeMethod(Method method) { System.out.println("开始"); beginTime=System.currentTimeMillis(); } }
这样,若是我想给A对象添加一个α功能,那就传个A和实现了α功能的advisor类就能够了,改明儿要是想把α功能换成β功能,直接将参数换成一个新的实现了β功能的advisor类就能够了,不用再去从新写一个InvocationHandler。代码分离,易于维护。
2.4 实现相似spring的可配置AOP框架
需求:若是传入的是普通类,则返回普通类实例对象,若是传入的是须要代理的类,则返回代理类的动态代理对象,经过修改配置文件来进行切换
package zheteng; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class BeanFactory { Properties props=new Properties(); public BeanFactory(InputStream ips) { try { props.load(ips); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public Object getBean(String name){ String className=props.getProperty(name); Object bean=null; try { Class clazz=Class.forName(className); bean=clazz.newInstance(); if(bean instanceof ProxyFactoryBean){ ProxyFactoryBean proxyFactoryBean=(ProxyFactoryBean)bean; Advice advisor=(Advice) Class.forName(props.getProperty(name+".advice")).newInstance(); Object target=Class.forName(props.getProperty(name+".target")).newInstance(); proxyFactoryBean.setAdvisor(advisor); proxyFactoryBean.setTarget(target); Object proxy=proxyFactoryBean.getProxy(); return proxy; } } catch (Exception e) { e.printStackTrace(); } return bean; } }
package zheteng; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactoryBean { private Advice advisor; private Object target; public Advice getAdvisor() { return advisor; } public void setAdvisor(Advice advisor) { this.advisor = advisor; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public Object getProxy() { // TODO Auto-generated method stub Object proxy3=Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { advisor.beforeMethod(paramMethod); Object reVal=paramMethod.invoke(target, paramArrayOfObject); advisor.afterMethod(paramMethod); return reVal; } }); return proxy3; } } interface Advice{ void beforeMethod(Method method); void afterMethod(Method method); } class MyAdvice implements Advice{ long beginTime=0; @Override public void afterMethod(Method method) { System.out.println("结束"); long endTime=System.currentTimeMillis(); System.out.println(method.getName()+" running time of "+(endTime-beginTime)); } @Override public void beforeMethod(Method method) { System.out.println("开始"); beginTime=System.currentTimeMillis(); } }
package zheteng; import java.io.InputStream; public class AopFrameworkTest { public static void main(String[] args) { // TODO Auto-generated method stub InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties"); System.out.println(ips); Object bean = new BeanFactory(ips).getBean("xxx"); System.out.println(bean.getClass()); } }
#xxx=java.util.ArrayList xxx=zheteng.ProxyFactoryBean xxx.advice=zheteng.MyAdvice xxx.target=java.util.ArrayList