Java基础 | Reflex

1.反射概述

  1. 反射机制是在运行状态中,被视为动态语言的关键
  2. 对于任意类或对象,都能够获取他们的内部成员
  3. 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
  4. 通过class文件对象,去使用该文件中的属性 构造器 方法等一切成员变量

反射示例图

反射提供的功能

1.1创建对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//获取指定对象赋给Class类
Class file = ReData.class;

//1.调用指定的构造器创建对象
Constructor gzq = file.getConstructor(String.class, int.class);
Object obj = gzq.newInstance("Haryy", 28);
ReData rfd = (ReData)obj;
System.out.println(rfd);

//2.调用指定的属性
Field age = file.getDeclaredField("age");
//设置为true时,可调用私有的类的成员;
age.set(rfd,10);
System.out.println(rfd);

//3.调用指定的方法
Method info = file.getDeclaredMethod("info");
info.invoke(rfd);

//4.通过反射调用私有方法
Method secretInfo = file.getDeclaredMethod("secretInfo", String.class);
secretInfo.setAccessible(true);
secretInfo.invoke(rfd,"中国人中国魂儿.");

1.2反射与封装

正常情况下new对象的方式即可当不确定new哪个对象的时候,就使用反射

一个类若私有了某个成员,说明这个成员是封装写好的直接调用即可

但若需要必须使用反射来进行更改,故反射和封装不存在冲突

1.3类的加载机制

  1. 程序经过javac.exe后 会生产一或多个.class文件
  2. 使用java.exe进行对其中某一个解释运行,相当于
  3. 把某个字节码文件加载到内存中,这个过程就为类的加载机制
  4. 加载到内存中的类,称为运行时类,此时它就作为Class的一个实例
  5. Class的实例就对应着一个运行时类
  6. 加载到内存中的运行时类,会缓存一定时间
  7. 此时就可以通过不同方式来获取此运行时类

1.4四种创建方式

方式一 调用运行时类的属性.class

1
2
Class c1 = ReData.class;
System.out.println(c1);

方式二 通过运行时类对象,调用getClass()

1
2
3
ReData reData = new ReData();
Class<? extends ReData> c2 = reData.getClass();
System.out.println(c2);

方式三 使用Class类的forName()

1
2
3
4
5
Class<?> c3 = Class.forName("ReData");
System.out.println(c3);

System.out.println(c1 == c2);
System.out.println(c1 == c3);

方式四 使用类的加载器

1
2
3
4
ClassLoader cloader = 此类类名称.class.getClassLoader();
Class<?> c4 = cloader.loadClass("ReData");
System.out.println("系统加载器"+cloader);
System.out.println(c1 == c4);

1.5动态性理解

  • 有时候我们造对象是不确定的
  • 此时就可以通过反射的动态性在运行时候可以根据某些条件改变自身结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public void DyTest() throws Exception {
for (int i = 0 ;i<100;i++) {
//2.获取0-2随机数
int num = new Random().nextInt(3);
String locate = "";
switch (num){
case 0:
locate ="java.util.Date";
break;
case 1:
locate ="java.lang.Object";
break;
case 2:
locate ="Test.Calculator";
break;
}
//3.此时我们造的对象是不确定的
//(通过动态性就可以很好的解决这个问题)
Object obj = getInstance(locate);
System.out.println(obj);
}
}
//1.指定一个具体的实例使用反射创建
public Object getInstance(String classpath) throws Exception{
Class<?> cls = Class.forName(classpath);
return cls.newInstance();
}

2.成员获取

2.1构造器

1
2
3
4
5
6
7
8
9
10
11
12
Class clz = ReData.class;
//获取运行时类所有public构造器(不包括父类)
Constructor[] cons = clz.getConstructors();
for (Constructor constructor : cons){
System.out.println(constructor);
}

//获取运行时类所有权限构造器(不包括父类)
Constructor[] dcs = clz.getDeclaredConstructors();
for (Constructor constructor1 : dcs){
System.out.println(constructor1);
}

2.2属性方法

属性

1
2
3
4
5
6
7
8
9
10
11
//获取当前运行时类及父类public的属性
Class<ReData> dt = ReData.class;
Field[] fields = dt.getFields();
for (Field f : fields){
System.out.println(f);
}
//当前运行时类的所有属性(无父类属性)
Field[] dfs = dt.getDeclaredFields();
for (Field f1 : dfs){
System.out.println(f1);
}

方法

1
2
3
4
5
6
7
8
9
10
11
12
//可获取运行时类及父类的public方法
Class ct = ReData.class;
Method[] methods = ct.getMethods();
for (Method m : methods){
System.out.println(m);
}

//获取运行时类所有权限的方法(不包括父类)
Method[] methods1 = ct.getDeclaredMethods();
for (Method m1 : methods1){
System.out.println(m1);
}

2.3接口泛型(重点)

1.获取运行时类的父类

1
2
3
4
5
6
7
//不带泛型
Class clz = ReData.class;
Class scs = clz.getSuperclass();
System.out.println(scs);
//带泛型
Type gsc = clz.getGenericSuperclass();
System.out.println(gsc);

2.获取运行时类带泛型的父类的泛型

1
2
3
4
5
ParameterizedType paramType = (ParameterizedType)gsc;
Type[] type = paramType.getActualTypeArguments();
System.out.println(type[0].getTypeName());
//对type强转为Class类型 调用getName方法
System.out.println(((Class)type[0]).getName());

3.获取运行时类的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void InterfaceTest() throws Exception{
//1.获取运行时类的接口
Class clz = Class.forName("re_basic.ReData");
Class[] interfaces = clz.getInterfaces();
System.out.println(interfaces[0].getName());

Type[] gifs = clz.getGenericInterfaces();
System.out.println(gifs[0].getTypeName());

//2.获取运行时类父类实现的接口
Class[] fathers = clz.getSuperclass().getInterfaces();
for (Class c : fathers){
System.out.println(c);
}
}

2.4动态代理

  • 动态代理是在程序运行时根据需要动态的去创建目标类的代理对象
  • 主要用于调试,远程方法调用
  • 相对于静态代理,抽象类或接口中所声明的方法,都被转移到调用处理器一个集中的方法进行处理,可以更灵活的管理多个方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    public class DynimProxy {
    public static void main(String[] args) {
    //被代理类对象
    SuperMan superMan = new SuperMan();
    //代理类对象
    Human human = (Human)ProxyFactory.getProxyInstance(superMan);
    System.out.println(human.getBelief());
    human.eat("美国M9牛排");
    }
    }

    interface Human{
    String getBelief();
    void eat(String food);
    }

    //被代理类
    class SuperMan implements Human{

    @Override
    public String getBelief() {
    return "相信世界";
    }

    @Override
    public void eat(String food) {
    System.out.println("我喜欢吃"+food);
    }
    }

    class ProxyFactory{
    //1.调用此方法返回一个代理类对象
    public static Object getProxyInstance(Object obj){
    MyIHR ihr = new MyIHR();
    ihr.bind(obj);

    return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), ihr);
    }
    }
    class MyIHR implements InvocationHandler{
    private Object obj;
    public void bind(Object obj){
    this.obj = obj;
    }
    //通过代理类对象调用方法a时,就会自动盗用如下invoke()
    //把被代理类要执行的方法a就声明在invoke()里
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    //此method即为代理对象调用的方法,也作为被代理对象要调用的方法
    //obj:被代理类的对象
    Object returnValue = method.invoke(obj, args);
    return returnValue;
    }
    }

Java基础 | Reflex
http://example.com/2022/06/20/Java初级部分/SEImprove/Reflex/
Author
John Doe
Posted on
June 20, 2022
Licensed under