1.反射机制是什么
Reflection(反射)是被视为动态语言的关键,反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
2.反射机制能做什么
反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理。
3.反射的优缺点
优点:
(1)能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。 (2)与Java动态编译相结合,可以实现无比强大的功能 缺点: (1)使用反射的性能较低 (2)使用反射相对来说不安全 (3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性4.Class类
在Object类中定义了以下的方法,此方法将被所有子类继承:
public final Class getClass()
以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称。
对照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。 Class本身也是一个类 Class 对象只能由系统建立对象 一个类在 JVM 中只会有一个Class实例 一个Class对象对应的是一个加载到JVM中的一个.class文件 每个类的实例都会记得自己是由哪个 Class 实例所生成 通过Class可以完整地得到一个类中的完整结构
5.ClassLoader
类加载器是用来把类(class)装载进内存的。JVM 规范定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined classloader)。 JVM在运行时会产生3个类加载器组成的初始化加载器层次结构,如下图所示:
// 1.获取一个系统类加载器 ClassLoader loader1 = ClassLoader.getSystemClassLoader(); System.out.println(loader1);// 2.获取系统类加载器的父类加载器,即扩展类加载器 ClassLoader loader2 = loader1.getParent(); System.out.println(loader2);// 3.获取扩展类加载器的父类加载器,即引导类加载器 ClassLoader loader3 = loader2.getParent(); System.out.println(loader3);// 4.测试当前类由哪个类加载器进行加载 Class clazz1 = Person.class; ClassLoader loader4 = clazz1.getClassLoader(); System.out.println(loader4);// 5.测试String类由哪个类加载器进行加载 String className = "java.lang.String"; Class clazz2 = Class.forName(className); ClassLoader loader5 = clazz2.getClassLoader(); System.out.println(loader5);// 6.关于类加载器的一个主要方法:getResourceAsStream(String str):获取类路径下的指定文件的输入流 ClassLoader loader = this.getClass().getClassLoader(); InputStream is = loader.getResourceAsStream("com\\ciyo\\java\\jdbc.properties"); // 法二: // FileInputStream is = new FileInputStream(new // File("jdbc.properties")); Properties pros = new Properties(); pros.load(is); String name = pros.getProperty("user"); System.out.println(name); String password = pros.getProperty("password"); System.out.println(password);
输出结果:
sun.misc.Launcher$AppClassLoader@18b4aac2sun.misc.Launcher$ExtClassLoader@50cbc42fnullsun.misc.Launcher$AppClassLoader@18b4aac2nullroot123abc
6.实例化Class类对象
//1.调用运行时类本身的.class属性 Class clazz1 = Person.class; System.out.println(clazz1.getName()); //2.通过运行时类的对象获取 Person p = new Person(); Class clazz2 = p.getClass(); System.out.println(clazz2.getName()); //3.通过Class的静态方法获取.通过此方式,体会一下,反射的动态性。 String className = "com.ciyo.java.Person"; Class clazz3 = Class.forName(className); System.out.println(clazz3.getName()); //4.(了解)通过类的加载器 ClassLoader classLoader = this.getClass().getClassLoader(); Class clazz4 = classLoader.loadClass(className); System.out.println(clazz4.getName()); System.out.println(clazz1 == clazz2);// true System.out.println(clazz1 == clazz3);// true System.out.println(clazz1 == clazz4);// true
输出结果:
com.ciyo.java.Personcom.ciyo.java.Personcom.ciyo.java.Personcom.ciyo.java.Persontruetruetrue
7.反射机制实例化一个类的对象
方法一:调用Class对象的newInstance()方法
要求:1)类必须有一个无参数的构造器。 2)类的构造器的访问权限需要足够。方法二:通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器,生成Constructor的实例方法三:通过Class类的getConstructors获取所有构造方法,生成Constructor的实例import java.lang.reflect.Constructor;public class TestReflect { public static void main(String[] args) throws Exception { Class class1 = null; class1 = Class.forName("com.ciyo.java.User"); // 第一种:调用Class对象的newInstance()方法 User user = (User) class1.newInstance(); user.setAge(20); user.setName("Rollen"); System.out.println(user); // 结果 User [age=20, name=Rollen] // 第二种方法:获取指定的构造函数 使用构造函数赋值 Constructor con = class1.getDeclaredConstructor(int.class, String.class); //调用setAccessible(true)方法,将可访问private的构造方法。 con.setAccessible(true); user = (User) con.newInstance(30, "FillKer"); System.out.println(user); // 结果 User [age=30, name=FillKer] // 第三种方法:取得全部的构造函数 使用构造函数赋值 Constructor cons[] = class1.getConstructors(); // 查看每个构造方法需要的参数 for (int i = 0; i < cons.length; i++) { Class clazzs[] = cons[i].getParameterTypes(); System.out.print("cons[" + i + "] ("); for (int j = 0; j < clazzs.length; j++) { if (j == clazzs.length - 1) System.out.print(clazzs[j].getName()); else System.out.print(clazzs[j].getName() + ","); } System.out.println(")"); } // 结果 // cons[0] (int,java.lang.String) // cons[1] (java.lang.String) // cons[2] () user = (User) cons[0].newInstance(20, "Rollen"); System.out.println(user); // 结果 User [age=20, name=Rollen] user = (User) cons[1].newInstance("Rollen"); System.out.println(user); // 结果 User [age=0, name=Rollen] }}class User { private int age; private String name; public User() { super(); } public User(String name) { super(); this.name = name; } public User(int age, String name) { super(); this.age = age; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User [age=" + age + ", name=" + name + "]"; }}
8.获取某个类的全部方法
// 1.获取运行时类的方法 注解 权限修饰符 返回值类型 方法名 形参列表 异常 Class clazz = Person.class; // 1.getMethods():获取运行时类及其父类中所有的声明为public的方法 Method[] m1 = clazz.getMethods(); // 2.getDeclaredMethods():获取运行时类本身声明的所有的方法 Method[] m2 = clazz.getDeclaredMethods(); for (Method m : m2) { // 1.注解 Annotation[] ann = m.getAnnotations(); // 2.权限修饰符(public,private...) String modifier = Modifier.toString(m.getModifiers()); // 3.返回值类型 Class returnType = m.getReturnType(); // 4.方法名 String methodName = m.getName(); // 5.形参列表 Class[] params = m.getParameterTypes(); // 6.异常类型 Class[] exps = m.getExceptionTypes(); for (int i = 0; i < exps.length; i++) { System.out.println(exps[i].getName()); } } // 调用运行时类中指定的方法 // getMethod(String methodName,Class ... params):获取运行时类中声明为public的指定的方法 Method m3 = clazz.getMethod("show"); Person p = (Person) clazz.newInstance(); // 调用指定的方法:Object invoke(Object obj,Object ... obj) Object returnVal = m3.invoke(p);// 我是一个人! // getDeclaredMethod(String methodName,Class ... // params):获取运行时类中声明了的指定的方法 Method m4 = clazz.getDeclaredMethod("display", String.class, Integer.class); //调用setAccessible(true)方法,将可访问private的方法。 m4.setAccessible(true); Object value = m4.invoke(p, "CHN", 10);// 我的国籍是:CHN
import static java.lang.annotation.ElementType.CONSTRUCTOR;import static java.lang.annotation.ElementType.FIELD;import static java.lang.annotation.ElementType.LOCAL_VARIABLE;import static java.lang.annotation.ElementType.METHOD;import static java.lang.annotation.ElementType.PARAMETER;import static java.lang.annotation.ElementType.TYPE;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotation { String value();}
import java.io.Serializable;public interface MyInterface extends Serializable{}
public class Creature{ public double weight; public void breath(){ System.out.println("呼吸!"); }}
@MyAnnotation(value = "person")public class Person extends Creatureimplements Comparable, MyInterface { public String name; private int age; int id; // 创建类时,尽量保留一个空参的构造器。 Person() { super(); } public Person(String name) { super(); this.name = name; } private Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } @MyAnnotation(value = "abc123") public void show() { System.out.println("我是一个人!"); } private Integer display(String nation, Integer i) throws Exception { System.out.println("我的国籍是:" + nation); return i; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } @Override public int compareTo(Object o) { // TODO Auto-generated method stub return 0; } public static void info() { System.out.println("中国人!"); } class Bird { }}
9.获取某个类的全部属性
Class clazz = Person.class; // 1.getFields():只能获取到运行时类中及其父类中声明为public的属性 Field[] fields = clazz.getFields(); // 2.getDeclaredFields():获取运行时类本身声明的所有的属性 Field[] fields1 = clazz.getDeclaredFields(); for (Field f : fields1) { // 1.获取每个属性的权限修饰符 int i = f.getModifiers(); String str1 = Modifier.toString(i); // 2.获取属性的类型 Class type = f.getType(); // 3.获取属性名 String name = f.getName(); } // 1.获取指定的属性 // getField(String fieldName):获取运行时类中声明为public的指定属性名为fieldName的属性 Field name = clazz.getField("name"); // 2.创建运行时类的对象 Person p = (Person) clazz.newInstance(); // 3.将运行时类的指定的属性赋值 name.set(p, "Jerry"); System.out.println(p); // getDeclaredField(String fieldName):获取运行时类中指定的名为fieldName的属性 Field age = clazz.getDeclaredField("age"); // 由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。 age. (true); age.set(p, 10); System.out.println(p);
10.获取一个对象的父类与实现的接口
Class clazz = Person.class; // 1.获取运行时类的父类 Class superClass = clazz.getSuperclass(); System.out.println(superClass); // 2.获取父类的泛型 Type type1 = clazz.getGenericSuperclass(); ParameterizedType param = (ParameterizedType) type1; //获取实际的泛型类型参数数组 Type[] ars = param.getActualTypeArguments(); System.out.println(((Class) ars[0]).getName()); // 3.获取实现的接口 Class[] interfaces = clazz.getInterfaces(); // 4.获取所在的包 Package pack = clazz.getPackage(); // 5.获取注解 Annotation[] anns = clazz.getAnnotations();
通过反射拷贝类对象
例子:
import java.lang.reflect.Field;import java.lang.reflect.Method;public class ReflectTester{ public Object copy(Object object) throws Exception { // 获得对象的类型 Class classType = object.getClass(); System.out.println("Class:" + classType.getName()); // 通过默认构造方法创建一个新的对象 Object objectCopy = classType.getConstructor(new Class[] {}).newInstance(new Object[] {}); // 获得对象的所有属性 Field fields[] = classType.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; String fieldName = field.getName(); String firstLetter = fieldName.substring(0, 1).toUpperCase(); // 获得和属性对应的getXXX()方法的名字 String getMethodName = "get" + firstLetter + fieldName.substring(1); // 获得和属性对应的setXXX()方法的名字 String setMethodName = "set" + firstLetter + fieldName.substring(1); // 获得和属性对应的getXXX()方法 Method getMethod = classType.getMethod(getMethodName, new Class[] {}); // 获得和属性对应的setXXX()方法 Method setMethod = classType.getMethod(setMethodName, new Class[] { field.getType() }); // 调用原对象的getXXX()方法 Object value = getMethod.invoke(object, new Object[] {}); System.out.println(fieldName + ":" + value); // 调用拷贝对象的setXXX()方法 setMethod.invoke(objectCopy, new Object[] { value }); } return objectCopy; } public static void main(String[] args) throws Exception { Customer customer = new Customer("Tom", 21); customer.setId(new Long(1)); Customer customerCopy = (Customer) new ReflectTester().copy(customer); System.out.println("Copy information:" + customerCopy.getId() + " " + customerCopy.getName() + " " + customerCopy.getAge()); }}class Customer{ private Long id; private String name; private int age; public Customer() { } public Customer(String name, int age) { this.name = name; this.age = age; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }}
11.动态代理
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;//动态代理的使用,体会反射是动态语言的关键interface Subject { void action();}// 被代理类class RealSubject implements Subject { public void action() { System.out.println("我是被代理类,记得要执行我哦!么么~~"); }}class MyInvocationHandler implements InvocationHandler { Object obj;// 实现了接口的被代理类的对象的声明 // ①给被代理的对象实例化②返回一个代理类的对象 public Object blind(Object obj) { this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this); } //当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //method方法的返回值时returnVal Object returnVal = method.invoke(obj, args); return returnVal; }}public class TestProxy { public static void main(String[] args) { //1.被代理类的对象 RealSubject real = new RealSubject(); //2.创建一个实现了InvacationHandler接口的类的对象 MyInvocationHandler handler = new MyInvocationHandler(); //3.调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象。 Object obj = handler.blind(real); Subject sub = (Subject)obj;//此时sub就是代理类的对象 sub.action();//转到对InvacationHandler接口的实现类的invoke()方法的调用 }}
12.马士兵老师动态代理实现代码
(1)首先创建一个接口
package com.alan.proxy.dynamic1; public interface Flyable { void fly() ; }
(2)创建这个接口的一个实现类
package com.alan.proxy.dynamic1; public class Plane implements Flyable{ @Override public void fly() { System.out.println("Plane is Flying...."); } }
(3)创建一个动态的代理类
package com.alan.proxy.dynamic1; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; public class Proxy { public static Object newInstance(Class intefc, InvocationHandler h) throws Exception { String rt = "\r\t" ; String methodStr = "" ; // 首先实现这个接口的所有方法 Method[] methods = intefc.getMethods(); for (Method m : methods) { methodStr += "@Override"+rt+ "public void "+m.getName()+"(){"+rt+ " try{"+rt+ " Method md = "+intefc.getName()+".class.getMethod(\""+m.getName()+"\");" + rt + " h.invoke(this,md);" +rt+ " }catch(Exception ex){}" +rt+ "}" ; } String clazzStr = "package com.alan.proxy.dynamic1;"+rt+ "import java.lang.reflect.Method;"+rt+ "public class $Proxy1 implements "+intefc.getName()+"{"+rt+ " public $Proxy1(InvocationHandler h){"+rt+ " this.h=h;"+rt+ " }"+rt+ "private com.alan.proxy.dynamic1.InvocationHandler h ;"+rt+ methodStr +rt+ "}"; //写入到一个java文件里面 File file = new File("D:/workspace/JAVA_Pattern/src/com/alan/proxy/dynamic1/$Proxy1.java") ; FileWriter writer = null ; try { writer = new FileWriter(file); writer.write(clazzStr) ; writer.flush() ; } catch (IOException e) { e.printStackTrace(); }finally{ try { if(writer !=null){ writer.close() ; } } catch (IOException e) { e.printStackTrace(); } } //将这个Java文件加载到内存,并返回一个Object对象 URL[] urls = new URL[] {new URL("file:/" + "D:/workspace/JAVA_Pattern/src/")}; URLClassLoader ul = new URLClassLoader(urls); Class c = ul.loadClass("com.alan.proxy.dynamic1.$Proxy1"); System.out.println(c); //返回一个代理对象 Constructor ctr = c.getConstructor(InvocationHandler.class); Object m = ctr.newInstance(h); return m; } }
(4)创建一个代理的处理器接口
package com.alan.proxy.dynamic1; import java.lang.reflect.Method; public interface InvocationHandler { void invoke(Object o, Method m) ; }
(5)创建这个处理器的一个实现类
package com.alan.proxy.dynamic1; import java.lang.reflect.Method; public class CheckInvocationHandler implements InvocationHandler{ private Object target ; public CheckInvocationHandler(Object target){ this.target = target ; } @Override public void invoke(Object o, Method m) { try { //调用被代理对象的方法 System.out.println("飞行器 起飞前检查......"); m.invoke(target) ; System.out.println("飞行器起飞后 检查........"); }catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
(6)创建一个类
package com.alan.proxy.dynamic1; public class Client { public static void main(String[] args) { try { Flyable o = (Flyable)Proxy.newInstance(Flyable.class, new CheckInvocationHandler(new Plane())) ; o.fly() ; } catch (Exception e) { e.printStackTrace(); } } }
运行的结果:
class com.alan.proxy.dynamic1.$Proxy1 飞行器 起飞前检查...... Plane is Flying.... 飞行器起飞后 检查........
总结:
Proxy的主要功能是:动态的创建某个接口的代理类,通过调用处理器的处理方法来实现对某个接口的代理。
XXXInvocationHandler:实现对某个被代理对象的处理。