类加载器
Java代码编译运行的时候是由下面的加载器将字节码文件加载进内存,各个加载器分工不同
名称 | 加载的项目 |
---|---|
Bootstrap ClassLoader 根类加载器 | 负责加载核心类,比如String,在 Jre/lib/rt.jar中 |
Extension ClassLoader 扩展类加载器 | 负责加载Java扩展的类 Jre/lib/ext中 |
System ClassLoader 系统类加载器 | 负责加载自己写的类 |
反射机制
当一个类被加载进内存后,都会相应的有一个字节码文件(里面有类的信息)对象,通过反射机制我们可以知道这个类的属性和方法,并且可以调用他们.
1.获取字节码文件对象的3中方式
1.Object类中的getClass()方法
2.类名调用静态方法
3.通过一个类的全路径,就可以获取到该类的字节码文件对象(常用,可以通过全路径写配置文件)
package com.jingfei.csdn;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException {
//方法一
Student student = new Student();
Class clazz1 = student.getClass();
//方法二
Class clazz2 = Student.class;
//方法三
Class clazz3 = Class.forName("com.jingfei.csdn.Student");//包名加上类名
}
}
class Student{
}
2.获取到字节码文件对象后,就可以用类中的 构造方法,成员变量,成员方法
1.获取构造方法对象,调用静态方法能得出对象
Constructor类
公有的用以下两个
getConstructors()//获取全部
getConstructor()//获取单个,若有参数,要填写 类型.class
私有公有全部的用以下两个
getDeclaredConstructors()//获取全部构造
getDeclaredConstructor()//获取单个构造(公有私有都可以) 若有参数,要填写 类型.class
私有的要获取类的对象时候要取消语法检测
dc.setAccessible(true);//取消语法检测,才可以
package com.jingfei.csdn;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class Demo {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("com.jingfei.csdn.Student");//包名加上类名
Constructor[] constructor = clazz.getConstructors();//获取该类的公有的构造方法对象,获取不到私有
for (Constructor constructor1 : constructor) {
System.out.println(constructor1);
}
System.out.println("-------------------------------------");
Constructor[] gds = clazz.getDeclaredConstructors();//获取所有的构造方法对象,包括私有
for (Constructor gd : gds) {
System.out.println(gd);
}
System.out.println("---------------------------------------");
Constructor c1 = clazz.getConstructor();//获取空参的构造方法对象
Constructor c2 = clazz.getConstructor(String.class);//获取一个参数String的构造对象
Constructor c3 = clazz.getConstructor(String.class,int.class);//获取两个参数的构造对象
Object s1 = c1.newInstance();
Object s2 = c2.newInstance("李四");
Object s3 = c3.newInstance("张三", 20);//这个方法是获取类的对象.相当与你new的对象一样.
//现在要获取私有的构造方法
Constructor dc = clazz.getDeclaredConstructor(String.class, double.class);//获取私有的构造方法对象
dc.setAccessible(true);//取消语法检测,才可以
Object s4 = dc.newInstance("王五", 10000);
}
}
class Student{
public Student() {
System.out.println("我是空参构造");
}
public Student(String name) {
System.out.println("我是一个参数("+name+")的有参构造");
}
public Student(String name,int age) {
System.out.println("我是两个参数("+name+"="+age+")的有参构造");
}
private Student(String name,double money) {
//私有构造
System.out.println("我是私有的两个参数("+name+"-->"+money+")的有参构造");
}
}
2.获取成员变量对象,并设值
Field类
得到公共的public成员变量
getFields()
getField(“name”)
得到任意的成员变量(包括私有的)
getDeclaredFields()
getDeclaredField(“money”)
设置值和获取值
name.set(s1,“Bob”);//参一是你要设置给那个对象,参二是要设置的值
name.get(s1)//获取对象对应的值
给私有的设置值,和获取值时候需要,取消语法检测 money.setAccessible(true);
package com.jingfei.csdn;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Demo {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("com.jingfei.csdn.Student");//包名加上类名
Constructor[] constructor = clazz.getConstructors();//获取该类的公有的构造方法对象,获取不到私有
for (Constructor constructor1 : constructor) {
System.out.println(constructor1);
}
System.out.println("-------------------------------------");
Constructor[] gds = clazz.getDeclaredConstructors();//获取所有的构造方法对象,包括私有
for (Constructor gd : gds) {
System.out.println(gd);
}
System.out.println("---------------------------------------");
Constructor c1 = clazz.getConstructor();//获取空参的构造方法对象
Constructor c2 = clazz.getConstructor(String.class);//获取一个参数String的构造对象
Constructor c3 = clazz.getConstructor(String.class,int.class);//获取两个参数的构造对象
Object s1 = c1.newInstance();
Object s2 = c2.newInstance("李四");
Object s3 = c3.newInstance("张三", 20);//这个方法是获取类的对象.相当与你new的对象一样.
//现在要获取私有的构造方法
Constructor dc = clazz.getDeclaredConstructor(String.class, double.class);//获取私有的构造方法对象
dc.setAccessible(true);//取消语法检测,才可以
Object s4 = dc.newInstance("王五", 10000);
System.out.println("----------------------------------------");
Field[] declaredFields = clazz.getDeclaredFields();//获取所有的成员变量对象
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("-----------------------------------------");
Field[] fields = clazz.getFields();//只能获取公共的public的成员变量对象
for (Field field : fields) {
System.out.println(field);
}
Field name = clazz.getField("name");//获取单个成员变量对象,需要写成员变量名
System.out.println(name);
Field money = clazz.getDeclaredField("money");//获取单个任意权限成员变量对象
System.out.println(money);
name.set(s1,"Bob");
System.out.println(name.get(s1));
money.setAccessible(true);
money.set(s1,999);
System.out.println(money.get(s1));
}
}
class Student{
public String name;
int age;
private double money;
public Student() {
System.out.println("我是空参构造");
}
public Student(String name) {
this.name=name;
System.out.println("我是一个参数("+name+")的有参构造");
}
public Student(String name,int age) {
this.name=name;
this.age=age;
System.out.println("我是两个参数("+name+"="+age+")的有参构造");
}
private Student(String name,double money) {
//私有构造
this.name=name;
this.money=money;
System.out.println("我是私有的两个参数("+name+"-->"+money+")的有参构造");
}
}
3.成员方法对象,并执行
和上面的用法一样
clazz.getMethods()
clazz.getMethod()
getDeclaredMethods()
getDeclaredMethod()
调用方法的时候,用获取的成员方法对象,调用invoke()方法即可(这个方法很重要)
package com.jingfei.csdn;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("com.jingfei.csdn.Student");//包名加上类名
Constructor[] constructor = clazz.getConstructors();//获取该类的公有的构造方法对象,获取不到私有
for (Constructor constructor1 : constructor) {
System.out.println(constructor1);
}
System.out.println("-------------------------------------");
Constructor[] gds = clazz.getDeclaredConstructors();//获取所有的构造方法对象,包括私有
for (Constructor gd : gds) {
System.out.println(gd);
}
System.out.println("---------------------------------------");
Constructor c1 = clazz.getConstructor();//获取空参的构造方法对象
Constructor c2 = clazz.getConstructor(String.class);//获取一个参数String的构造对象
Constructor c3 = clazz.getConstructor(String.class,int.class);//获取两个参数的构造对象
Object s1 = c1.newInstance();
Object s2 = c2.newInstance("李四");
Object s3 = c3.newInstance("张三", 20);//这个方法是获取类的对象.相当与你new的对象一样.
//现在要获取私有的构造方法
Constructor dc = clazz.getDeclaredConstructor(String.class, double.class);//获取私有的构造方法对象
dc.setAccessible(true);//取消语法检测,才可以
Object s4 = dc.newInstance("王五", 10000);
System.out.println("----------------------------------------");
//获取成员变量
Field[] declaredFields = clazz.getDeclaredFields();//获取所有的成员变量对象
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("-----------------------------------------");
Field[] fields = clazz.getFields();//只能获取公共的public的成员变量对象
for (Field field : fields) {
System.out.println(field);
}
Field name = clazz.getField("name");//获取单个成员变量对象,需要写成员变量名
System.out.println(name);
Field money = clazz.getDeclaredField("money");//获取单个任意权限成员变量对象
System.out.println(money);
name.set(s1,"Bob");
System.out.println(name.get(s1));
money.setAccessible(true);
money.set(s1,999);
System.out.println(money.get(s1));
System.out.println("******************************************");
//获取方法,用法类似
Method[] methods = clazz.getMethods();//获取所有公共的(public)方法,包括父类的方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("-----------------------------------------------");
Method[] declaredMethods = clazz.getDeclaredMethods();//只获取自己的所有的方法,不包括父类的
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
Method sleep = clazz.getMethod("sleep");//获取单个公共的方法对象.参数写方法名
System.out.println(sleep);
Method eat = clazz.getDeclaredMethod("eat");
System.out.println(eat);
Method earn = clazz.getDeclaredMethod("earn", int.class);//有参数要写上 数据类型.class
System.out.println("----------------------------------------------");
//让方法执行
Object fanc1 = sleep.invoke(s2);
Object invoke = eat.invoke(s4);
earn.setAccessible(true);//私有方法必须取消语法检测 ,否则报错
Object invoke1 = earn.invoke(s3, 100);
}
}
class Student{
public String name;
int age;
private double money;
public Student() {
System.out.println("我是空参构造");
}
public Student(String name) {
this.name=name;
System.out.println("我是一个参数("+name+")的有参构造");
}
public Student(String name,int age) {
this.name=name;
this.age=age;
System.out.println("我是两个参数("+name+"="+age+")的有参构造");
}
private Student(String name,double money) {
//私有构造
this.name=name;
this.money=money;
System.out.println("我是私有的两个参数("+name+"-->"+money+")的有参构造");
}
public void sleep(){
System.out.println("我是公共的sleep方法");
}
void eat(){
System.out.println("我是缺省的eat方法");
}
private void earn(int money){
System.out.println("我是私有的earn方法,我赚了"+money+"万元!");
}
}
案例1:
可以利用反射,读取配置文件中的全路径,不至于来回改代码,比如今天老板让你写一个Student类,明天又说Student不好,又想要一个Teacher类,后天又说还是用之前的Student类吧,就这样来回折腾,可以不用爱以前的代码上改动,写一个配置文件,两个代码用反射来回改全路径即可.
可以用属性集合Properties,可读可写.
案例2:
集合中如果规定了泛型是不可以存泛型之外的类型的数据,但,泛型只在编译期有效,在运行期就擦出了,所以依据这个特性利用反射就可以在运行期间存别的数据类型的数据.
案例3:
动态代理,根据反射的特性,对一个代码进行动态代理,比如你的代码的核心是取钱,而你在你核心代码取钱之前应该要经过身份验证,在取钱之后,要提醒顾客取走卡片,这样就可以用动态代理,在你代码运行前先经过一个代理身份验证,代码运行后,在来一个取卡操作.
会用到如下代码:(改天再写)
Proxy.newProxyInstance(clazz.getClass().getClassLoader(), clazz.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
谢谢!