类加载机制和反射
jdk:包含javac编译器,以及一些开发java的小工具
jre: jvm+基本库
jvm:类加载器(讲javac编译后的.class文件以二进制读入内存)
java文件通过编译器变成了.class文件,接下来类加载器又将这些.class文件加载到JVM内存中。并为之生成对应的Class对象,直接使用java.exe命令来运行某个主类,其中类装载器的作用其实就是类的加载
//=========================================================================
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.
## 要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象
方式一: 通过Object类中的getClass()方法 new Person().getClass();
方式二:通过 类名.class 获取到字节码文件对象(任意数据类型都具备一个class静态属性) Class c2 = Person.class;
方式三: 通过Class类中的方法(将类名作为字符串传递给Class类中的静态方法forName即可)。
Class c3 = Class.forName("Person"); //扩展性强
## 在反射机制中,把类中的成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示,可通过Class类中提供的方法获取相对应的构造方法、成员变量,成员方法对象。
构造方法使用类Constructor表示,成员属性使用类 Field表示,成员方法实用类Method表示,
AccessibleObject 类是 Field、Method 和 Constructor 对象的父类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力-- public void setAccessible(boolean flag) throws SecurityException 参数值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。参数值为 false 则指示反射的对象应该实施 Java 语言访问检查,我们编写的代码默认为false: 解释,就是我们要突破私有方法的限制就要暴力反射,setAccessible(true);
//1,获取到Class对象
Class c = Class.forName("cn.gllm.Person");//包名.类名
// 2.1 Class类中提供的方法获取指定的构造方法对象
构造方法对象 ------------
获取指定的构造方法 获取指定的public修饰的构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes)
获取指定的构造方法,包含私有的
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
获取所有的构造方法
public Constructor<?>[] getConstructors() 获取所有的public 修饰的构造方法
public Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法,包含私有的
获取了制定的构造方法对象就可以获取对象()
public T newInstance(Object... initargs)
###eg:
Constructor con = c.getConstructor(String.class, int.class, String.class); //获取该对象制定的构造器对象
Object obj = con.newInstance("小明", 22, "哈尔滨"); //调用构造对象的newinstance()方法创建对象
如果获取的是私有的构造方法
Constructor con = c.getConstructor(String.class, int.class, String.class);
con.setAccessible(true);// 暴力反射 取消 Java 语言访问检查 (con的获取方法是declared构造方法)
Object obj = con.newInstance("小明", 22, "哈尔滨");
//2.2 Class类中提供的方法获取成员变量对象
成员变量对象---------------------
获取指定的成员变量
public Field getField(String name) 获取public修饰的成员变量
public Field getDeclaredField(String name) 获取任意的成员变量,包含私有
获取所有的成员变量
public Field[] getFields() 获取所有public修饰的成员变量
public Field[] getDeclaredFields() 获取司所有的成员变量,包含私有
对成员变量赋值\获取值操作
public void set(Object obj, Object value) 赋值
public Object get(Object obj) 获取值
###eg:
Field ageField = c.getField("age");
Object age = ageField.get(obj); //获取值 (obj可通过反射获得构造方法类调用newInstance生成对象
ageField.set(obj, 23); //赋值
如果属性私有,获取的方法与构造方法相同
//2.3 Class类中提供的方法获取成员方法对象
成员方法对象---------------------
获取指定方法
public Method getMethod(String name, Class<?>... parameterTypes) 获取指定的public方法 public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 获取指定的任意方法,包含私有的
获取所有的方法
public Method[] getMethods() 获取本类与父类中所有public 修饰的方法
public Method[] getDeclaredMethods() 获取本类中所有的方法,包含私有的
执行方法 (获得的方法对象调用invoke去执行相对应得方法 ) 私有的方法同私有的构造方法
public Object invoke(Object obj, Object... args)
###eg:
Class c = Class.forName("cn.gllm.Person");
Constructor con = c.getConstructor(String.class, int.class, String.class);
Object obj = con.newInstance("小明", 23, "哈尔滨");
Method m4 = c.getMethod("method4", String.class);
Object result = m4.invoke(obj, "itcast");
//======================================================================================
泛型擦除:其实程序编译后产生的.class文件中是没有泛型约束的,这种现象我们称为泛型的擦除
ArrayList<Integer> list = new ArrayList<Integer>(); //添加元素到集合 list.add(new Integer(30)); list.add(new Integer("12345")); list.add(123); //list.add("哈哈");//因为有泛型类型的约束 System.out.println(list);
//通过反射技术,实现添加任意类型的元素 //1, 获取字节码文件对象 //Class c = list.getClass(); //Class c = ArrayList.class; Class c = Class.forName("java.util.ArrayList");
//2, 找到add()方法 // public boolean add(E e) Method addMethod = c.getMethod("add", Object.class);
//3, 执行add()方法 addMethod.invoke(list, "哈哈");// list.add("哈哈"); System.out.println(list); } } |
//========================================================================================
反射配置文件
- 通过反射配置文件,运行配置文件中指定类的对应方法
读取Peoperties.txt文件中的数据,通过反射技术,来完成Person对象的创建
Peoperties.txt文件内容如下:
className=cn.itcast_01_Reflect.Person
methodName=method5
// 通过Properties集合从文件中读取数据 Properties prop = new Properties(); // 读取文件中的数据到集合中 prop.load(new FileInputStream("properties.txt")); // 获取键所对应的值 String className = prop.getProperty("className"); System.out.println(className);
// 1,获取Person.class 字节码文件对象 Class c = Class.forName(className); // 2,获取构造方法 // public Person(String name, int age, String address) Constructor con = c.getConstructor(String.class, int.class, String.class);
// 3,创建对象 Object obj = con.newInstance("小明", 20, "中国"); System.out.println(obj);
// 4,获取指定的方法 // private void method5(){} String methodName = prop.getProperty("methodName"); Method m5 = c.getDeclaredMethod(methodName, null); // 5,开启暴力访问 m5.setAccessible(true); // 6,执行找到的方法 m5.invoke(obj, null); |