java笔记-反射

一、类的加载

1.概述

​ 当程序需要使用某个类时,如果类还未被加载到内存中,系统会通过加载、连接、初始化散步来实现对 这个类进行初始化

加载 
	就是指将class文件读入内存,并为之创建一个Class对象。
	任何类被使用时系统都会建立一个Class对象。
连接
	验证 :	是否有正确的内部结构,并和其他类协调一致
	准备 :	负责为类的静态成员分配内存,并设置默认初始化值
	解析:	把类中的符号引用转换为直接引用
初始化		就是我们以前讲过的初始化步骤

2.类的加载时机

​ a.创建类的实例

​ b.访问类的静态变量,或为静态变量赋值

​ c.调用静态方法

​ d.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

​ e.初始化某个类的子类

​ f.直接使用java.exe命令来运行某个主类

3.类加载器的概述和分类

A:类加载器的概述

​ 负责将.class文件加载到内在中,并为之生成对应的Class对象。

B:类加载器的分类

​ 1.Bootstrap ClassLoader 根类加载器
​ 2.Extension ClassLoader 扩展类加载器
​ 3.Sysetm ClassLoader 系统类加载器

C:类加载器的作用

1.Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载
比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

2.Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载。
在JDK中JRE的lib目录下ext目录

3.Sysetm ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

二、反射

1.反射概述

​ JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
​ 对于任意一个对象,都能够调用它的任意一个方法和属性;
​ 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

​ 通过一个类的字节码文件对象(Class)反着去剖析这个类的构成

2.获取一个类的字节码文件对象的方式

1.通过Object类的getClass()方法
Student s = new Student();
//Class 类的实例表示正在运行的java应用程序中的类和接口
Class sc = s.getClass();

2.任何一个类都有一个.class属性,通过这个属性就可以获取到该类的字节码文件对象
Class<Student> scl = Student.Class;
sc==scl;//true

3.Class.forName();
全路径:一个类带有包名   全类名
ctrl+alt+空格(强制提示)
Class<?> tc = Class.forName("java.lang.Thread");



3.类的构成

​ 构造方法:Constructor

​ 成员变量: Field

​ 成员方法: Method

4.通过反射获取构造方法并创建该类对象

​ 构造方法:Constructor

A.通过反射获取构造方法
getConstructors();

getDeclaredConstructors();

getConstructor();//可变参数 需要构造方法参数类型的字节码文件作为参数(如String.class) 无参就是获取无参构造 无法获取私有构造

getDeclaredConstructor();//可获取私有构造

B.通过反射获取构造方法并创建该类对象
Student s = new Student();
Class sc = s.getClass();

1.无参构造   构造方法对象中的newInstance()  创建该类对象
Object o = sc.getConstructor().newInstance();
Student s = (Student)sc.getConstructor().newInstance();

2.有参构造
Constructor<?> c = sc.getDeclaredConstructor(String.class,int.class);
c.setAccessible(true);//取消权限检查  可以使用私有构造方法
Object o = c.newInstance("lisi",25);
Student s = (Student)c.newInstance("lisi",25);



反射方式获取一个类的对象:

获取 该类字节码对象(3种方式)》字节码对象 获取 构造方法对象》构造方法对象 取消 权限检查==》构造方法对象 创建 该类对象

如果指向用空参构造创建一个类的对象,那么反射的方式有两种

1.Dog.class.getDeclaredConstructor().newInstance();

2.Dog.class.newInstance();

5、通过反射获取成员变量并赋值

Field 字段类型/成员变量类型

A.通过反射获取成员变量
Class<Student> sc = Student.class;

Field[] fs = sc.getFields();//获取所有公共成员变量对象的数组

Field[] dfs = sc.getDeclaredFields();//获取所有成员变量对象的数组  包括私有

Field n = sc.getField("name");//获取单个公共成员变量对象

Field n = sc.getDeclaredField("money");//获取单个成员变量对象  包括私有

B.通过反射获取成员变量并赋值
Class<Student> sc = Student.class;
Field n = sc.getField("name");//成员变量名称

Constructor<> scc = sc.getConstructor();
scc.setAccessible(true);
Student s = scc.newInstance();

n.setAccessible(true);
n.set(s,"张三");//需要一个该类对象和成员变量值 给哪个对象的那个成员变量赋值
Object o = n.get(s);//需要set()方法的该类对象s  返回该成员变量对象
System.out.println(o);//打印对象  即是设置的成员变量的值

通过反射方法设置成员变量的值:

获取该类字节码对象==》字节码对象 获取 成员变量对象 ==》成员变量对象设置具体该类对象的成员变量值

6、通过反射获取成员方法并使用

Method 成员方法对象

A.通过反射获取成员方法
Class<Student> sc = Student.class;

Constructor<Student> scc = sc.getDeclaredConstructor();
scc.setAccessible(true);
Student s = scc.newInstance();

Method[] ms = sc.getMethods();//获取所有公共成员方法对象,包括父类的公共方法

Method[] dms = sc.getDeclaredMethods();//获取所有的私有成员方法对象,不包括父类

sc.getMethod();//需要成员方法名和成员方法参数类型的class类型(可变参数)
Method show = sc.getMethod("show",String.class,int.class);

sc.getDeclaredMethod();


B.通过反射获取成员方法并使用
Class<Student> sc = Student.class;

Constructor<Student> scc = sc.getDeclaredConstructor();
scc.setAccessible(true);
Student s = scc.newInstance();

Method show = sc.getDeclaredMethod("show");

show.invoke(s);//参1:类对象 参2(可变参数):成员方法需要的具体参数

Method sho = sc.getDeclaredMethod("sho",String.class,int.class);
sho.invoke(s,"张三"23);

Method how = sc.getDeclaredMethod("how"double.class);
how.setAccessible(true);
Object o = how.invoke(s,3.2);//有返回值的成员方法  会返回该方法返回值
System.out.println(o);//该方法返回值


反射机制读取配置文件

//peizhi.properties
classname=org.westos.demo.Dog
methodname=sleep

//Dog类
public class Dog {
    public void eat() {
        System.out.println("狗吃骨头");
    }

    public void sleep() {
        System.out.println("狗睡觉");
    }
}

//读取配置文件
Properties properties = new Properties();
properties.load(new FileReader("peizhi.properties"));

Class<?> classname = Class.forName(properties.getProperty("classname"));
Object o = classname.getDeclaredConstructor().newInstance();

Method eat = classname.getMethod(properties.getProperty("methodname"));
eat.invoke(o);


反射机制越过泛型检查

// 我给你ArrayList<Integer> 的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
        ArrayList<Integer> list = new ArrayList<>();
        list.add(100);
        //list.add("abc");  报错
        //泛型:泛型只在编译期,运行期就擦除了。
        Class<? extends ArrayList> aClass = list.getClass();
        //获取add方法对象
        Method add = aClass.getDeclaredMethod("add", Object.class);
        add.invoke(list,"abc");
        System.out.println(list);



反射

动态代理:在不修改某个类的情况下对该类中的方法进行增强的一种手段

A:动态代理概述
代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。
举例:春季回家买票让人代买
动态代理:在程序运行过程中产生的这个对象
而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,必须要有接口,没有接口使用cglib 可以代理
通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。
我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象
	public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
最终会调用InvocationHandler的方法
	InvocationHandler Object invoke(Object proxy,Method method,Object[] args)

被代理对象(目标对象)

代理对象==运行期生成

动态生成代理人的类   Proxy java.lang.reflect

static Object newProxyInstance(Classloader loader,Class<?>[]interfaces,InvocationHandler h);  //返回一个指定接口的代理类实例

	1.Classloader loader类加载器,负责加载代理对象的字节码文件,根被代理对象使用的是同一个类加载器,固定写法   被代理对象.getClass().getClassLoader()
	2.Class<?>[]interfaces	被代理对象实现的所有接口的class数组   固定写法   被代理对象.getClass().getInterfaces()
	3.InvocationHandler h		用于提供增强的代码	new InvocationHandler(){增强代码}
	new InvocationHandler(){
        @Override
            /**proxy 代理对象
             * method 方法对象
             * args 方法上的参数数组
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //System.out.println("权限校验");
                //Object invoke = method.invoke(userDao);
                //System.out.println("记录日志");
                Object invoke=null;
                if(method.getName().equals("update")){
                    System.out.println("权限校验");
                    invoke= method.invoke(userDao);
                    System.out.println("记录日志");
                }

               return invoke;
            }
    }	


Proxy.newProxyInstance();


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值