黑马程序员--Java反射
2015-08-29 17:49
501 查看
——- android培训、java培训、期待与您交流! ———-
1.加载
将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
2.连接
验证是否有正确的内部结构,并和其他类协调一致
准备负责为类的静态成员分配内存,并设置默认初始化值。
解析将类的二进制数据中的符号引用替换为直接引用
3.初始化
就是通过构造方法进行初始化
类的加载需要加载器,加载器有三种
Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载,例如System,String等。在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录
System ClassLoader系统类加载器
负责在JVM启动时加载来自Java命令的class文件,以及classpath环境变量所指定的jar包和类路径。
Java的反射机制就是说在程序状态中,对于任何一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象,而解剖使用的就是Class类中的方法,所有先要获取到每一个字节码文件对应的Class类型的对象。
简单来说反射就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
使用反射首先必须得到class文件对象,其实也就是得到Class类的对象。
数据类型的静态属性class
Class类中的静态方法:public static Class forName(String className),参数需要传入.class文件的绝对路径
获取构造方法并使用
获取私有构造方法并使用
有参无返和有参有返方法
定义一个接口
创建实现类
Proxy类中有一个方法可以创建动态代理对象
public static Object newProxyInstance(ClassLoader loader,Class
创建新的代理对象
——- android培训、java培训、期待与您交流! ———-
反射
就是通过class文件对象,使用该文件中的成员变量,构造方法,成员方法。加载
想要使用反射,首先得了解类的加载,类的加载总共分三步:1.加载
将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
2.连接
验证是否有正确的内部结构,并和其他类协调一致
准备负责为类的静态成员分配内存,并设置默认初始化值。
解析将类的二进制数据中的符号引用替换为直接引用
3.初始化
就是通过构造方法进行初始化
类的加载需要加载器,加载器有三种
Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载,例如System,String等。在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录
System ClassLoader系统类加载器
负责在JVM启动时加载来自Java命令的class文件,以及classpath环境变量所指定的jar包和类路径。
Java的反射机制就是说在程序状态中,对于任何一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象,而解剖使用的就是Class类中的方法,所有先要获取到每一个字节码文件对应的Class类型的对象。
简单来说反射就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
使用反射首先必须得到class文件对象,其实也就是得到Class类的对象。
获取class文件对象的方式
Object类的getClass()方法,返回是一个Class类。数据类型的静态属性class
Class类中的静态方法:public static Class forName(String className),参数需要传入.class文件的绝对路径
public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException { // 方式1 Person p = new Person(); Class c = p.getClass(); Person p2 = new Person(); Class c2 = p2.getClass(); System.out.println(p == p2);// false System.out.println(c == c2);// true // 方式2 Class c3 = Person.class; System.out.println(c == c3); // 方式3 Class c4 = Class.forName("com.java_01.Person"); System.out.println(c == c4); } }
反射的演示
首先定义一个Person类public class Person { private String name; int age; public String address; public Person() { } private Person(String name) { this.name = name; } Person(String name, int age) { this.name = name; this.age = age; } public Person(String name, int age, String address) { this.name = name; this.age = age; this.address = address; } public void show() { System.out.println("show"); } public void method(String s) { System.out.println("method " + s); } public String getString(String s, int i) { return s + "---" + i; } private void function() { System.out.println("function"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", address=" + address + "]"; } }
获取构造方法
import java.lang.reflect.Constructor; import com.java_01.Person; public class ReflectDemo { public static void main(String[] args) throws Exception { // 获取字节码文件对象 Class c = Class.forName("com.java_01.Person"); // 获取构造方法 // public Constructor[] getConstructors():所有公共构造方法 // public Constructor[] getDeclaredConstructors():所有构造方法 // Constructor[] cons = c.getDeclaredConstructors(); // for (Constructor con : cons) { // System.out.println(con); // } // 获取单个构造方法 // public Constructor<T> getConstructor(Class<?>... parameterTypes) // 参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象 Constructor con = c.getConstructor();// 返回的是构造方法对象 // Person p = new Person(); // System.out.println(p); // public T newInstance(Object... initargs) // 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。 Object obj = con.newInstance(); System.out.println(obj); } }
获取构造方法并使用
import java.lang.reflect.Constructor; public class ReflectDemo2 { public static void main(String[] args) throws Exception { // 获取字节码文件对象 Class c = Class.forName("com.java_01.Person"); // 获取带参构造方法对象 // public Constructor<T> getConstructor(Class<?>... parameterTypes) Constructor con = c.getConstructor(String.class, int.class, String.class); // 通过带参构造方法对象创建对象 // public T newInstance(Object... initargs) Object obj = con.newInstance("李延旭", 21, "北京"); System.out.println(obj); } }
获取私有构造方法并使用
import java.lang.reflect.Constructor; public class ReflectDemo3 { public static void main(String[] args) throws Exception { // 获取字节码文件对象 Class c = Class.forName("com.java_01.Person"); Constructor con = c.getDeclaredConstructor(String.class); // 暴力访问 con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。 Object obj = con.newInstance("李延旭"); System.out.println(obj); } }
反射获取成员变量并使用
import java.lang.reflect.Constructor; import java.lang.reflect.Field; public class ReflectDemo { public static void main(String[] args) throws Exception { // 获取字节码文件对象 Class c = Class.forName("com.java_01.Person"); // 通过无参构造方法创建对象 Constructor con = c.getConstructor(); Object obj = con.newInstance(); System.out.println(obj); // 获取单个的成员变量 // 获取address并对其赋值 Field addressField = c.getField("address"); // public void set(Object obj,Object value) // 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京" System.out.println(obj); // 获取name并对其赋值 // NoSuchFieldException Field nameField = c.getDeclaredField("name"); // IllegalAccessException nameField.setAccessible(true); nameField.set(obj, "李延旭"); System.out.println(obj); // 获取age并对其赋值 Field ageField = c.getDeclaredField("age"); ageField.setAccessible(true); ageField.set(obj, 21); System.out.println(obj); } }
反射获取方法
获取无参无返回值方法并调用import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class MethodDemo { public static void main(String[] args) throws Exception { Class c = Class.forName("com.java_01.Person"); // public Method[] getMethods():获取除了私有修饰的所有方法,包括从父类继承过来的 Method[] methods = c.getMethods(); for (Method m : methods) { System.out.println(m); } System.out.println("-----------------------"); // public Method getMethod(String name,Class<?>... parameterTypes) // 第一个参数是方法名,第二个参数是该方法参数的class类型,没有就不写,或者写null Method m = c.getMethod("show", null); // public Object invoke(Object obj,Object... args) // 第一个参数是要调用方法的对象,第二个参数是该方法的实际参数,没有就不写,或者写null // 创建对象 Constructor con = c.getConstructor(); Object obj = con.newInstance(); // 调用方法 m.invoke(obj, null); } }
有参无返和有参有返方法
import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class MethodDemo2 { public static void main(String[] args) throws Exception { // 获取字节码文件对象 Class c = Class.forName("com.java_01.Person"); // 创建无参对象 Constructor con = c.getConstructor(); Object obj = con.newInstance(); // 获取有参无返回值方法 Method m = c.getMethod("show2", String.class); // 获取有参有返回值方法 Method m2 = c.getMethod("show3", String.class); // 调用方法 m.invoke(obj, "中国"); String s = (String) m2.invoke(obj, "河南"); System.out.println(s); } }
反射越过泛型检查
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; public class ArrayListDemo { public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // 创建集合对象 ArrayList<Integer> array = new ArrayList<Integer>(); // array.add("hello"); // array.add(10); Class c = array.getClass(); // 集合ArrayList的class文件对象 Method m = c.getMethod("add", Object.class); m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello m.invoke(array, "world"); m.invoke(array, "java"); System.out.println(array); } }
动态代理
在Java中java.lang.reflect包中提供了一个Proxy类和InvocationHandler,通过是用这个类和接口就能生成动态代理对象,JDK提供的代理只能针对接口做代理。定义一个接口
public interface StudentDao { public abstract void login(); public abstract void regist(); }
创建实现类
public class StudentDaoImpl implements StudentDao { @Override public void login() { System.out.println("登录功能"); } @Override public void regist() { System.out.println("注册功能"); } }
Proxy类中有一个方法可以创建动态代理对象
public static Object newProxyInstance(ClassLoader loader,Class
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Object target;// 目标对象 public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { // 第一个参数是需要进行代理的对象,第二个参数是对象的方法,第三个参数是对象方法的参数 // 注意:该方法的调用是底层调用,看不到 System.out.println("权限校验"); Object result = method.invoke(target, args); System.out.println("日志记录"); return result;// 返回的就是代理对象 } }
创建新的代理对象
import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { // Student接口的实现类 Student s = new StudentImpl(); // InvocationHandler接口的实现类 MyInvocationHandler mi = new MyInvocationHandler(s); // 因为是对Student接口进行动态代理,所以返回值的类型也是Student接口 Student proxy = (Student) Proxy.newProxyInstance(s.getClass() .getClassLoader(), s.getClass().getInterfaces(), mi); // 调用方法 proxy.login(); proxy.regist(); } }
总结
反射在编写大型程序中很常见的应用,但是不太容易理解。虽然这次讲的内容不太多, 但是有着很强的抽象性,大家要动用自己的抽象思维,获取构造方法,成员变量和成员方法的时候,分清楚各自的返回值以及参数类型。Proxy只支持interface代理,不过后面要学习更强大的代理cglib。——- android培训、java培训、期待与您交流! ———-
相关文章推荐
- 黑马程序员—————Java基础--------IO流(二)
- C 面试题选(一)
- 黑马程序员 反射
- 程序员面试中常见10大算法汇总
- 程序员面试中常见10大算法汇总
- 教你如何迅速秒杀掉:99%的海量数据处理面试题
- 黑马程序员——Java之内部类
- 黑马程序员--Java_IO流(二)
- C#程序员开发WinForm必须知道的 Window 消息大全(转)
- 2015/8/28的面试题
- 剑指Offer面试题:14.链表的倒数第k个节点
- 程序员面试金典1.8:判断翻转子串
- 黑马程序员——java基础——反射的定义及用法
- 程序员面试金典1.7:若M*N矩阵中某个元素为0,则将其所在的行与列清零
- 程序员面试金典1.6:将图像旋转90度。不占用额外内存空间
- 剑指Offer面试题:13.调整数组顺序使奇数位于偶数前面
- 面试题:乱序字符串
- 2014腾讯、百度、阿里面试经验
- 黑马程序员 File&Properties&URL
- 黑马程序员 --- NSString和NSMutableString的用法