《Thinking in Java》学习笔记(六)
1.Class相关知识
Class类可以理解为类的图纸,通过Class类可以分析类的结构、构建出类的实例。
Class.forName("test.TestClass").newInstance()方法要求类test.TestClass必须有一个无参的构造函数,否则会报错。
Class.forName(test.TestClass)会将类test.TestClass加载到JVM中,并完成初始化的工作,类中的静态方法会执行。
Class c = Class.forName(test.TestClass);中Class.forName方法返回的Class有一些常用的方法返回Class的信息,如下:
package rtti; import java.util.ArrayList; import java.util.Arrays; public class ClassInfoTest { public static void main(String[] args) throws InstantiationException, IllegalAccessException { try { /*Class clazz = Class.forName("rtti.BenzCar"); System.out.println("simple name: " + clazz.getSimpleName()); System.out.println("canonical name: " + clazz.getCanonicalName()); System.out.println("isInterface: " + clazz.isInterface()); System.out.println("interfaces: " + Arrays.asList(clazz.getInterfaces())); System.out.println("superclass: " + clazz.getSuperclass());*/ //BenzCar.class与Class.forName("rtti.BenzCar")的不同在于不会直接进行类的初始化,而是等到 // 访问类的静态方法或者成员变量时 Class<? extends BenzCar> clazz = BenzCar.class; System.out.println("test if have load BenzCar class"); BenzCar car = clazz.newInstance(); System.out.println(car.getPrice()); if(car instanceof BenzCar){ System.out.println("car instanceof BenzCar"); } if(car instanceof Car){ System.out.println("car instanceof Car"); } if(clazz.isInstance(car)){ System.out.println("car isInstance BenzCar"); } if(Car.class.isInstance(car)){ System.out.println("car isInstance Car"); } System.out.println(ArrayList.class.isAssignableFrom(Object.class)); //false System.out.println(Object.class.isAssignableFrom(ArrayList.class)); //true } catch (Exception e) { e.printStackTrace(); } } } class Car{} interface product{} class BenzCar extends Car implements product{ static{ System.out.println("Loading BenzCar class"); } double price = 12000d; public double getPrice(){ return price; } }
输出结果为:
test if have load BenzCar class Loading BenzCar class 12000.0 car instanceof BenzCar car instanceof Car car isInstance BenzCar car isInstance Car false true
instanceof和isInstance()方法的作用是完全一致的。
2.反射相关知识
Class类与java.lang.reflect下的各类完成了对反射的支持,主要的类包括Field、Method、Constructor等。
通过反射我们甚至可以调用类的私有方法,构造出一个甚至多个新的单例模式的实例。
package rtti; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; public class ReflectTest { public static void main(String[] args) { Class<?> demo = null; try{ demo = Class.forName("rtti.Person"); // = Person.class, = Person.getClass() }catch (Exception e) { e.printStackTrace(); } Person per1 = null; Person per2 = null; Person per3 = null; //取得全部的构造函数 Constructor<?> cons[] = demo.getConstructors(); try{ per1 = (Person)cons[0].newInstance(); per2 = (Person)cons[1].newInstance("Rollen",20); per3 = Person.class.newInstance(); //Person.class.newInstance("Rollen",20); error }catch(Exception e){ e.printStackTrace(); } System.out.println(per1); System.out.println(per2); System.out.println(per3); System.out.println("interface of which Person Class implements: " + Arrays.asList(Person.class.getInterfaces())); System.out.println("super class of Person Class: " + Person.class.getSuperclass().getSimpleName()); //获取方法 Method[] methods = Person.class.getDeclaredMethods(); //getMethods() will get superclass's method for(Method method:methods){ String modifier = Modifier.toString(method.getModifiers()); String returnType = method.getReturnType().getSimpleName(); String methodName = method.getName(); Class [] excepts = method.getExceptionTypes(); Class [] clazzs = method.getParameterTypes(); StringBuffer params = new StringBuffer(""); for(Class clazz:clazzs){ params.append(clazz.getSimpleName()).append(","); } String param = ""; if(params.length() > 1){ param = params.substring(0, (params.length()-1)); } System.out.println(modifier + " " + returnType + " " + methodName + "(" + param + ")" + " " + (excepts.length == 0 ? "" :"throws " + excepts[0].getSimpleName())); } //获取成员变量 Field [] fields = Person.class.getDeclaredFields(); for(Field field:fields){ String modifier = Modifier.toString(field.getModifiers()); String type = field.getType().getSimpleName(); String name = field.getName(); System.out.println(modifier + " " + type + " " +name); } //通过反射调用private方法 try { Person p = Person.class.newInstance(); //p.getPrivateMethod() error,not visiable Method method = Person.class.getDeclaredMethod("getPrivateMethod",null); method.setAccessible(true); method.invoke(Person.class.newInstance()); } catch (Exception e) { System.out.println(e); } //通过反射给成员变量赋值 try { Field f = Person.class.getDeclaredField("name"); Person p = Person.class.newInstance(); f.setAccessible(true); f.set(p, "xixi"); System.out.println(f.get(p)); } catch (Exception e) { e.printStackTrace(); } System.out.println(Person.class.getClassLoader().getClass().getName()); } } class Person implements Serializable{ private String name; private int age; public Person() { } public Person(String name, int age) { this.age = age; this.name = name; } public void setName(String name) throws IllegalArgumentException { this.name = name; } public String getName() { return name; } public int getAge() { return age; } @Override public String toString(){ return "["+this.name+" "+this.age+"]"; } private void getPrivateMethod(){ System.out.println("this is a private method in Person Class"); } }
输出结果为:
[null 0] [Rollen 20] [null 0] interface of which Person Class implements: [interface java.io.Serializable] super class of Person Class: Object public String toString() public String getName() public void setName(String) throws IllegalArgumentException private void getPrivateMethod() public int getAge() private String name private int age this is a private method in Person Class xixi sun.misc.Launcher$AppClassLoader
需要注意的是,类的Class在JVM中只有一份,我们通过反射将方法的修饰符由private改为了public,后面代码中这个方法的修饰符都将是public。
我们还可以使用反射来实现工厂模式,代码如下:
package rtti; public class UseReflectForFactoryPattern { public static Fruit getCertainFruit(String fruitName){ Fruit f = null; try { f = (Fruit) Class.forName(fruitName).newInstance(); } catch (Exception e) { e.printStackTrace(); } return f; } public static void main(String[] args) { //这里使用的是完整的类型rtti.Apple,实际使用中可能只会知道类名,比如Apple //可以新建properties文件,存储Apple和rtti.Apple的对应关系 Fruit f = getCertainFruit("rtti.Apple"); f.eat(); f = getCertainFruit("rtti.Orange"); f.eat(); } } interface Fruit{public abstract void eat();} class Apple implements Fruit{ @Override public void eat() { System.out.println("eat Apple!"); } } class Orange implements Fruit{ @Override public void eat() { System.out.println("eat Orange!"); } }
3.动态代理基础
Java中的Proxy类和InvocationHandler提供了动态代理的功能,动态代理还是利用了反射,在原Class的基础上重新生成了一个新的Class,从而可以对目标方法做一些操作。
Java的动态代理要求被代理的类必须继承了接口,如果被代理的类没有继承了接口,可以可虑用cglib来完成。
下面是一个Proxy类和InvocationHandler完成动态代理的例子。
package rtti; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JDKRroxy implements InvocationHandler{ private Object obj; public Object bind(Object obj){ this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this); } public static void main(String[] args) { JDKRroxy jr = new JDKRroxy(); test t = (test) jr.bind(new ActiveTest()); //error: ActiveTest at = (ActiveTest) jr.bind(new ActiveTest()); t.testMethod(); } @Override public Object invoke(Object paramObject, Method method, Object[] args) throws Throwable { System.out.println("before method!"); Object temp = method.invoke(this.obj, args); System.out.println("after method!"); return temp; } } interface test{public abstract void testMethod();} //use JDK Proxy must implements interface class ActiveTest implements test{ public void testMethod(){ System.out.println("this is a test method!"); } } //use cglib,see :http://www.cnblogs.com/lnlvinso/p/4240350.html
输出结果为:
before method! this is a test method! after method!