黑马程序员,看Java基础视频笔记:反射
2014-12-15 10:59
232 查看
反射
反射就是把Java中各种成分映射成相应的Java类,它通过字节码文件对象,将类的字段,方法,构造器等映射成相应的类,并进行各自的操作。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的class类显然要提供一系列的方法来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应的实例对象来表示,它们是Field、Method、Contructor、Package等等。简单说:反射技术可以对一个类进行解剖。反射的好处:
反射属于JDk1.5版本之后出现的新特性,它的出现大大的增强了程序的扩展性。反射的基本步骤:
1、获得Class对象,就是获取到指定的名称的字节码文件对象。2、实例化对象,获得类的属性、方法或构造函数。
3、访问属性、调用方法、调用构造函数创建对象。
获取class类对象的三种方式:
1、通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。2、每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。
前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成。
3、使用的Class类中的方法,静态的forName方法。指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。
// 1. 根据给定的类名来获得 用于类加载 String classname = "cn.itcast.reflect.Person";// 来自配置文件 Class clazz = Class.forName(classname);// 此对象代表Person.class // 2. 如果拿到了对象,不知道是什么类型 用于获得对象的类型 Object obj = new Person(); Class clazz1 = obj.getClass();// 获得对象具体的类型 // 3. 如果是明确地获得某个类的Class对象 用于传参 Class clazz2 = Person.class;
反射的用法:
1)、我们要获得java类的各个组成部分,首先需要获得类的Class对象,获得Class对象的三种方式:Class.forName(classname) 用于做类加载
obj.getClass() 用于获得对象的类型
类名.class 用于获得指定的类型,传参用
2)、反射类的成员方法:Method类
Class clazz = Person.class;
Method method = clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});
method.invoke();
3)、反射类的构造函数:Constructor类
Constructor类代表某个类中的一个构造方法。
Constructor con = clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...})
con.newInstance(params...)
4)、反射类的属性,也称成员变量:Field类
Field类代表某个类中的一个成员变量。getField只能提供获取到可见的值,而getDeclaredField只要声明过的,都可以获取到。
Field field = clazz.getField(fieldName);
field.setAccessible(true);
field.setObject(value);
暴力反射
暴力反射可以获取私有变量,使用setAccessible方法,它就好比有两扇门上面的两把锁,我有第一把锁的钥匙,但是没有第二把锁的钥匙,我要进第二个门怎么办?这时候只能用工具把锁强行拆掉,我才能进去。而这个工具就是setAccessible(),类里面的私有变量,通过普通的getField反射无法获得,只有通过getDeclaredField()获得,然后利用setAccessible方法访问,这个获取和访问的过程就是暴力访问。Field fieldX = ReflectPoint.class.getDeclaredField("x"); fieldX.setAccessible(true);
创建指定类的对象:
创建对象的两种方式(其实就是对象在进行实例化时的初始化方式):
1,调用空参数的构造函数:使用了Class类中的newInstance()方法。2,调用带参数的构造函数:先要获取指定参数列表的构造函数对象,然后通过该构造函数的对象的newInstance(实际参数) 进行对象的初始化。
注意:
第二种方式,必须要先明确具体的构造函数的参数类型,不便于扩展。所以一般情况下,被反射的类,内部通常都会提供一个公有的空参数的构造函数。//第一种方式创建对象:该实例化对象的方法调用就是指定类中的空参数构造函数,给创建对象进行初始化。当指定类中没有空参数构造函数时, Object obj = clazz.newInstance();
//第二种方式创建对象:既然类中没有空参数的构造函数,那么只有获取指定参数的构造函数,用该函数来进行实例化。 public static void method_2() throws Exception { <pre name="code" class="java"> //获取一个带参数的构造器。Class clazz = Class.forName("cn.itcast.bean.Person"); Constructor constructor = clazz.getConstructor(String.class,int.class); //想要对对象进行初始化,使用构造器的方法newInstance(); Object obj = constructor.newInstance("zhagnsan",30);
//获取所有构造器。 Constructor[] constructors = clazz.getConstructors();//只包含公共的 constructors = clazz.getDeclaredConstructors();//包含私有的 for(Constructor con : constructors) { System.out.println(con); } }
反射指定类中的方法:
//获取类中所有的方法。 public static void method_1() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); Method[] methods = clazz.getMethods();//获取的是该类中的公有方法和父类中的公有方法。 methods = clazz.getDeclaredMethods();//获取本类中的方法,包含私有方法。 for(Method method : methods) { System.out.println(method); } }
//获取指定方法; public static void method_2() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); //获取指定名称的方法。 Method method = clazz.getMethod("show", int.class,String.class); //想要运行指定方法,当然是方法对象最清楚,为了让方法运行,调用方法对象的invoke方法即可,但是方法运行必须要明确所属的对象和具体的实际参数。 Object obj = clazz.newInstance(); method.invoke(obj, 39,"hehehe");//执行一个方法 }
//想要运行私有方法。 public static void method_3() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); //想要获取私有方法。必须用getDeclearMethod(); Method method = clazz.getDeclaredMethod("method", null); // 私有方法不能直接访问,因为权限不够。非要访问,可以通过暴力的方式。 method.setAccessible(true);//一般很少用,因为私有就是隐藏起来,所以尽量不要访问。 }
//反射静态方法。 public static void method_4() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); Method method = clazz.getMethod("function",null); method.invoke(null,null); }
反射的小特点:
Java的泛型是通过编译器实现的,如果我们使用反射,就可以跳过JVM的编译过程,这样就可以不受泛型的限制,往集合中存储一些超出泛型范围的对象。如,以下是,往泛型限定为Integer的集合中存入String数据,使用反射可以做到:
public static void fanshes() throws Exception{
ArrayList<Integer> list = new ArrayList<Integer>();
Class clazz = list.getClass();
Method method = clazz.getMethod("add",Object.class);
System.out.println(method.getName());
method.invoke(list, "zhangsan");
method.invoke(list, 13);
System.out.println(list);
}
类加载器
常用的三种类加载器
1、bootstrap class loader,是顶层类加载器,用于加载JDK的核心类,是有本地语言写的,没有名字。2、extension class loader ,用于加载jre/lib/ext目录下的类。
3、application class loader,用于加载自己写的类。
自定义类加载器
要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名字,返回对应的Class对象的引用。程序加载的过程
首先是bootstrap class loader把其他的class loader加载进内存,然后其他的class loader再加载其他的class。这三个class loader 之间不是继承关系,而是树形层次关系。在application class loader中有一个引用指向:extesion class loader ,这个引用是parent,所以可以通过getParent()方法获得这个引用指向的class loader的对象。继承是类与类之间的关系,而在这里是对象与对象之间的关系。加载类的过程
加载一个类的过程是:首先 application class loader找它的parent class loader,看看上一层的class loader是不是已经加载了该类,如果已经加载了它就不会再加载一遍。优势:安全性好当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载、连接、初始化三个步骤来对该类进行初始化,如果没有意外,JVM将会连续完成这个三个步骤,所以有时也把这三个步骤统称为类加载或类初始化。在类初始化阶段会对静态属性进行初始化。
类加载器的委托机制
当一个类加载器要加载一个类时,该类加载器不会马上加载这个类,而是会调用它的父类加载器,如果父类加载器还有父类就继续向上调用直到动态代理
JVM在运行期间会动态加载类的字节码,这些动态生成的通常被用作目标类的代理类,即动态代理类,动态代理类需要实现一个或多个接口,如果目标类没有实现接口,想要为目标类创建动态代理,就要使用CGLIB库,使用CGLIB库就可以动态创建一个类的子类,子类可以被当做一个类的动态代理类。内省
JavaBean
JavaBean是一个特殊的Java类,这个类中的方法的名称符合某种特定的规则内省
JDK中提供了对JavaBean进行操作的一些API,这套API就成为内省。反射与内省的区别
反射可以操作各种不同的java类,内省只是通过反射来操作JavaBean类。JavaBean类里面操作的都是成员变量,都是通过setXXX和getXXX方法来获取成员变量,这样的类用内省来操作会更简单。相关文章推荐
- 黑马程序员_毕向东_Java基础视频教程学习笔记(八)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(二)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(十九)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(二十)
- 黑马程序员--Java基础加强学习笔记之Class类、反射(Reflect)
- 黑马程序员——Java基础视频笔记(三)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(十)
- 黑马程序员_java基础笔记(11)...反射
- 黑马程序员_java基础笔记(11)...反射
- 黑马程序员_毕向东_Java基础视频教程学习笔记(十八)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(三)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(十六)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(十三)
- 黑马程序员——Java基础视频笔记(一)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(五)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(十一)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(十四)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(十五)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(六)
- 黑马程序员_毕向东_Java基础视频教程第十八天-IO流---学习笔记