2021-09-29 Reflect反射机制详解:

一、反射:

反射是一种动态机制,它允许我们程序运行起来后再确定实例化对象,调用方法和操作属性,可以提高代码的灵活性。

但是反射会带来较慢的运行速度和更多的系统开销,所以不能过度的依赖反射机制。

二、类对象:

java.lang.Class Class类的每一个实例用于表示JVM加载的一个类,并且每个被JVM加载的类都有且只有一个Class的实例与之对应。

通过类对象可以获取到其表示的类的一切信息:类名、方法、属性、构造器等等。 利用反射操作的第一步就是获取要操作的类的类对象。

1、获取一个类的类对象有以下方式:

① [Class] 类名.class --基本类型只有这种获取类对象的方式

EG:Class cls = String.class; Class cls = int.class;

② [Class] Class.forName(String ClassName) --参数为类的完全限定名,即包名.类名

EG:Class cls = Class.forName("java.lang.String);

③ 使用类加载器ClassLoader

2、其他方法:

1、获取类对象表示的名字(完全限定名):[String] getName()

2、获取类名(不包含包名):[String] getSimpleName()

3、获取本类和父类所有的公开方法:[Method数组]getMethods()

4、获取本类所有方法,包括私有方法:[Method数组]getDeclaredMethods()

三、创建对象的方法?

1、使用new关键字直接创建对象

2、使用Object类提供的clone()方法复制对象

3、使用对象流调用readObject()方法反序列化一个对象

4、使用反射的newInstance()方法实例化对象

四、反射Reflect创建对象的方法:

正常创建类的实例化步骤:

        {
            BaoYang baoyang = new BaoYang();
            System.out.println(baoyang);//FYX_Month02_Week02.day03.BaoYang@1b6d3586
        }

使用反射创建类的实例化的步骤:

1、获取实例化的类的对象

     Class cls = Class.forName("FYX_Month02_Week02.day03.BaoYang");

2.1无参、:通过类对象进行实例化 [Object] newInstance() 该方法会实例化当前Class所表示的一个类的实例,但是前提是这个类必须有无参构造器。

Object by1 = cls.newInstance();
//BaoYang by = (BaoYang) cls.newInstance();
System.out.println(by1);//FYX_Month02_Week02.day03.BaoYang@4554617c

2.2、有参:通过类对象获取指定参数列表的构造器

 Constructor c = cls.getConstructor();//啥也不写时候是无参
 c = cls.getConstructor(String.class, int.class);//传参:构造器的参数类型的类对象
 Object by2 = c.newInstance("卷卷", 20);

如果构造器定义的的是可变参数,在传参时应该确定到底传递几个,分别进行传递 例如:构造器(int... a),那么getConstructor(int.class,int.class)

3.1、获取所有构造器,存入Constructor[]:

Constructor[] cs = cls.getConstructors();

3.2、遍历数组,得到每一个构造器

for(Constructor con :cs){
                System.out.println(con);
                //public FYX_Month02_Week02.day03.BaoYang()
                //public FYX_Month02_Week02.day03.BaoYang(java.lang.String,int)
            }

五、使用Reflect的newInstance()访问方法 

1、方法们:

1、[Method] getMethod(String name, Class<?>... parameterTypes):

公开方法:第一个参数为要调用的方法名,第二个参数是可变参数,为该方法参数列表中传入的参数类型对象名。 

如果是无参构造,则第二个参数无需传参,只需要传递一个方法名;如果是有参构造,需要传递参数类型的对象名,比如"sayLove",String.class,int.class 

2、[Method] getDeclaredMethod(String name, Class<?>... parameterTypes):

私有方法:具体用法与getMethod一致,只是针对的权限不同。

3、[Object] invoke(Object obj, Object... args):

第一个参数是对象名,第二个参数是可变参数,为该方法参数列表中传入的参数内容。

如果是无参构造,则第二个参数无需传参,只需要传递一个对象名;  如果是有参构造,需要先传递对象名,再传递参数的内容,比如:by,"抱羊",20

4、[void]setAccessible(boolean flag):

私有方法:强制访问操作,如果直接invoke会抛出IllegalAccessException:非法访问异常;需要在invoke之前设置私有方法的访问权限,true可访问,false不可。

2、具体使用:

1、无参方法:getMethod(方法名).invoke(对象名)

   Method m1 = cls.getMethod("sayLove");
    //调用该方法
   m1.invoke(by);//抱羊:I love 小羊!
   Method m2 = cls.getMethod("sayLike");
   m2.invoke(by);//抱羊:I like 小羊 !

2、有参方法:getMethod(方法名,参数类型如String.class).invoke(对象名,参数内容)

   Method m1 = cls.getMethod("studyCode",String.class);
   m1.invoke(by,"java");//抱羊开始学习:java
   Method m2 = cls.getMethod("studyCode",String.class,int.class);
   m2.invoke(by,"java",1000);//抱羊开始学习:java,一天要写1000行代码!

3、私有方法:getMethod(方法名),setAccessible(权限true),invoke(对象名)

   Method m1 = cls.getDeclaredMethod("sayAge");
   m1.setAccessible(true);
   m1.invoke(by);//抱羊已经20岁了!

六、使用反射操作属性:

1、方法们 :

1、[Field] getField(String name)

 获取非私有属性,括号中放入想要查询的属性的名字

直接使用getFiled方法获取私有属性会抛出NoSuchFieldException找不到该属性异常

2、[Field] getDeclaredField(String name) 

获取私有属性,括号中放入想要查询的属性的名字 

3、[void] setAccessible(true)

设置访问权限  非私有属性默认为false,不设置true则会抛出IllegalAccessException非法访问异常

 4、[void] set(Object obj, Object value)

设置属性值 

5、[Object] get(Object obj)

获取属性值

6、[Field数组] getFields():

获取所有非私有属性

7、[Field数组] getDeclaredFields():

获取所有属性

2、Reflect所有方法的总结:

属性用Field,方法用Method,获取所有加s返回数组;

公开直接写getXXX,私有先setAccessible设置权限,再getDeclaredXXX

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值