关于一些反射的基本认识吧

反射

框架设计的灵魂

## 什么是框架?

 

半成品软件
可以在框架的基础上进行软件的开发,简化编码

其实如果自己学框架并不需要框架,但如果以后要自己写框架,则需要对反射理解特别深!

 

反射的概念

将类的各个组成部分封装为其他对象,这就是反射机制

先说一说java代码运行的三个步骤

### 1,编码阶段

这个时候还是硬盘上,没有进入虚拟机

 

名字叫Junit.java的文件的代码如下:

public class Junit {    
    //属性
    private String name;
    private String a1;
​
    //构造方法
    public Junit(String name, String a1) {
        this.name = name;
        this.a1 = a1;
    }
    public Junit() {
    }
​
    //普通方法   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
 }

 

然后通过javac编译后

变成Junit.class的二进制字节码文件,

 private String name;
 private String a1;
public Junit(String name, String a1) {
        this.name = name;
        this.a1 = a1;
    }
public Junit() {
    }
 public String getName() {
        return name;
    }
 public void setName(String name) {
        this.name = name;
    }

 

就会分为三个部分

 

然后进入第二阶段

2,将字节码文件加载进内存

使用的是类加载器

对应的java里面的一个对象,叫作ClassLoader

在java里面有一个Class类(名字叫Class的类)

可以用来描述字节码文件的共同的行为!

 

在上面我把字节码文件写成了三个部分,这三个部分就是字节码文件的三个共同部分

1,三个成员变量(类里面的属性)

2,构造方法

3,成员方法

在Class类里面,把成员变量用:Field数组描述 fields

构造方法用:Constructor数组描述 constructors

成员方法:Method数组描述 methods

 

3,创建对象运行阶段

 

反射的好处

1,可以在程序运行过程中,可以操作这些对象

2,可以解耦,降低程序的耦合性,提高程序的可扩展性

 

获取Class对象(字节码对象)的方式

有三种方式,分别对象java代码的三个阶段

1,Class.forName("全类名")
全类名就是包名加类名

将字节码文件加载进内存,生成Class对象

Class c1=Class.forName("com.java1201.xiawu.ceshi.Ren");
因为使用的是全类名,所以需要用字符串,一般多用于配置文件。

将类名定义在配置文件中,通过读取配置文件,然后用反射创建字节码对象。

避免重复使用!

 

2,类名.class 类默认的class属性
通过类名属性获取Class对象

Class c2 = Ren.class;
多用于参数的传递

 

3,对象.getclass()
通过方法获取Class对象

 Class c3=new Ren().getClass();
多用于对象调取字节码文件

 

通过这三种方式获取的字节码对象都是一个

        Class c1=Class.forName("com.java1201.xiawu.ceshi.Ren");
         Class c2 = Ren.class;
         Class c3=new Ren().getClass();
         System.out.println(c1==c2&&c2==c3);
         
 控制台运行结果:
    ture

 

 

Class对象(字节码对象)的使用

 1,获取成员变量们
​
```
方法:
    获取public修饰和父类继承来的成员变量:getFields()  返回值 Field[]
    获取指定public修饰和父类继承来的成员变量:getFiled(String name) 返回值 Field
    
    获取所有的成员变量:getDeclaredFields()  返回值 Field[]
    获取指定的成员变量:getDeclaredField(String name)  返回值 Field
    
    如果找不到指定的成员变量会抛出一个空异常
```

 



 2,获取构造方法们
​
其实和上面成员变量的方法差不多
​
```
方法:
    获取public修饰和父类继承来的构造方法:getConstructors()  返回值 Constructor<?>[]
    获取指定public修饰和父类继承来的构造方法:getConstructor(String name) 返回值 Constructor<?>
    
    获取所有的构造方法:getDeclaredConstructors()  返回值 Constructor<?>[]
    获取指定的构造方法:getDeclaredConstructor(String name)  返回值 Constructor<?>
    
    如果找不到指定的成员变量会抛出一个空异常
```

 



 3,获取成员方法们
​
```
方法:
    获取public修饰和父类继承来的成员方法:getMethod 返回值 Constructor<?>[]
    获取指定public修饰和父类继承来的成员方法:getMethods(String name, Class<?>... parameterTypes) 返回值 Method
    
    获取所有的成员方法:getDeclaredMethods()  返回值 Method[]
    获取指定的成员方法:getDeclaredMethod(String name,Class<?>... parameterTypes)  返回值 Method
```

 




4,获取类名
​
•   获取类名: getName  返回值 String
​
•   获取包名: getPackage() 返回值 Package

 



 Class c2 = Ren.class;
Field f=c2.getField("a2"); //获取指定的声明的属性对象

Ren r=(Ren) c2.getDeclaredConstructor().newInstance(); //获取一个操作对象,这里是用了获取字节码对象无参构造的一个方法,用来创建新的对象

赋值成员变量:set(Object obj, Object value) ,  前面这个obj是对象,后面的是需要赋入的值
        f.set(r,"zp");    //给,r对象,的f属性,赋值"zp"
获取成员变量的值
        f.get(r);       //获取,r对象的f属性值,
        
调用无参成员方法:invoke(Object obj, Object... args)   返回值:Object
​
         Method m1=c2.getMethod("getNme") //获取指定的声明的成员对象
         m1.invoke(r);
调用有参且只有一个参数的成员方法:
        Method m2=c2.getMethod("setNme",方法参数类型.Class);  //大基本类型的话,要用对应的包装类型
        m1.invoke(r,值);
调用多个参数的成员方法:
        Method m3=c2.getMethod("add",方法参数类型.Class,方法参数类型.Class…………)  //有几个参数写几个
        m1.invoke(r,值,值…………);
        
 构造方法那个和成员方法类似,

 

 
上面的方法,对私有属性都是没办法操作的
想操作私有犯法或属性,可以用暴力反射
使用方法:
获取的对象.setAccessible(true);
这个获取的对象指的是Method,Field这些

 

 
posted @ 2022-12-01 17:58  牛杂刻师傅  阅读(32)  评论(0)    收藏  举报