JAVA-Reflect

文章结构

  1. Class类的使用
  2. 方法的反射
  3. 成员变量的反射
  4. 构造函数的反射
  5. Java类加载机制

Class类

面向对象的世界里,万物皆对象!

类也是对象,类是java.lang.Class类的实例对象。

Class类的实例对象的表示

任何一个类都是Class的实例对象,此实例有三种表达方式。

直接上伪代码:

// Ufan0这个类就是一个实例对象
Ufan0 ufan0 = new Ufan0();

/*
* Class类的实例对象的三种表达方式
* c1 == c2 == c3
*/

// 第一种 -> 任何一个类都有一个隐含的静态成员变量class
Class c1 = Ufan0.class;

// 第二种 -> 已知该类的对象通过getClass()方法
Class c2 = ufan0.getClass;

/* 官网指出:c1、c2表示 Ufan0 类的类类型(class type)。
* 万物皆对象,
* 类也是对象,为Class类的实例对象,
* 这个对象称为该类的类类型(class type)。
*/

// 第三种
Class c3 = null;
try {
c3 = Class.forName("com.*.Ufan0"); // 需要有无参数的构造方法
}catch(ClassNotFoundException e) {
e.printStackTrace();
}

// 可以通过类的类类型创建该类的对象实例
try {
Ufan0 ufan0 = (Ufan0)c1.newInstance();
}catch(InstantiationException e) {
e.printStackTrace();
}catch(IllegalAccessException e) {
e.printStackTrace();
}

Java动态加载类

Class.forName("类的全称")

  • 不仅表示了类的类类型,还代表了动态加载类;
  • 编译时刻加载类是静态加载类,运行时刻加载类是动态加载类

直接上代码实例:

  1. 静态加载类

    /*
    * Office.java
    */
    class Office {
    /* 此代码无法成功编译,因为Excel类不存在,导致Word类也用不到。
    * new 创建对象是静态加载类,在编译时刻就需要加载所有写到的类。
    * 通过动态加载类可解决此问题。
    */
    public static void main(String[] args) {

    if("Word".equals(args[0])) {
    Word w = new Word();
    w.start();
    }
    if("Excel".equals(args[0])) {
    Excel e = new Excel();
    e.start();
    }
    }
    }
    /*
    * Word.java
    */
    class Word() {
    public Static void start() {
    System.out.println("Word -> Start! ");
    }
    }
  2. 动态加载类

    /*
    * OfficeBetter.java
    * 后期甚至都不用重新编译
    */
    class OfficeBetter {
    public static void main(String[] args) {
    try{
    // 动态加载类,在运行时刻加载
    Class c = Class.forName(args[0]);
    //通过类类型,创建该类对象
    OfficeAble oa = c.newInstance();
    }catch(Exception e){
    e.printStackTrace;
    }
    }
    }
    /*
    * OfficeAble.java
    */
    interface OfficeAble {
    public void start();
    }
    /*
    * Word.java
    */
    class Word implements OfficeAble {
    public void start() {
    System.out.println("Word -> Start! ");
    }
    }

Java获取方法信息

基本数据类型,以及甚至void都存在类类型。

/*
* ClassDemo2.java
*/

public class ClassDemo {
public static void main(String[] args) {
Class c1 = int.class; // int的类类型
Class c2 = String.class; // String类的类类型
Class c3 = double.class; // double的类类型
Class c4 = Double.class; // Double的类类型
Class c5 = void.class; // void的类类型

// 打印完整的类名称
System.out.println(c1.getName());
System.out.println(c2.getName());
System.out.println(c3.getName());
System.out.println(c4.getName());
System.out.println(c5.getName());

// 打印不包含包名的类名称
System.out.println(c1.getSimpleName());
System.out.println(c2.getSimpleName());
System.out.println(c3.getSimpleName());
System.out.println(c4.getSimpleName());
System.out.println(c5.getSimpleName());

}
}

打印类的信息

包括类的成员函数、成员变量

/*
* ClassUtil.java
*/

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Solution {
/**
* 打印对象的成员变量信息
* obj 该对象所属类的信息
*/
public static void printClassMessage(Object obj) {
// 获取类的信息,首先要拿到类的类类型
Class c = obj.getClass(); // 传递的是哪个子类的对象,c就是该子类的类类型
//获取类的名称
System.out.println("类的名称是:" + c.getName());

/*
* Method类,方法对象
* 一个成员方法就是一个Method对象
* getMethods()方法获取的是所有是public的函数,包括父类继承而来的
* getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
*/
Method[] ms = c.getMethods(); // c.getDeclaredMethods()
for (Method m : ms) {
// 得到方法的返回值类型的类类型
Class returnType = m.getReturnType();
System.out.print(returnType.getName() + "");
// 得到方法的名称
System.out.print(m.getName() + "(");
// 获取参数类型 -> 得到参数列表的类型的类类型
Class[] paramTypes = m.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
printFieldMessage(c);

}
}

/**
* 打印对象的成员方法信息
* obj 该对象所属类的信息
*/
static void printFieldMessage(Object obj) {
Class c = obj.getClass();
/*
* 成员变量也是对象
* java.lang.reflect.Field
* Field类封装了关于成员变量的操作
* getFields()方法获取的是所有的public的成员变量的信息
* getDeclaredFields获取的是该类自己声明的成员变量的信息
*
*/
Field[] fs = c.getDeclaredFields();
for (Field field : fs) {
// 得到成员变量的类型的类类型
Class fieldType = field.getType();
String typeName = fieldType.getName();
// 得到成员变量的名称
String fieldName = field.getName();
System.out.println(typeName + " " + fieldName);
}
}

/**
* 打印对象的构造函数信息
* obj 该对象所属类的信息
*/
public static void printConMessage(Object obj) {
Class c = obj.getClass();
/*
* 构造函数也是对象
* java.lang.Constructor中封装了构造函数信息
* getConstructors()获取所有的public的构造函数
* getDeclaredConstructors()得到所有的构造函数
*/
Constructor[] cs = c.getDeclaredConstructors();
for (Constructor constructor : cs) {
System.out.print(constructor.getName() + "(");
// 获取构造函数的参数列表 -> 得到的是参数列表的类类型
Class[] paramTypes = constructor.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
}
}
/* 
* Test.java
*/

public class Test {
public static void main(String[] args) {
String s = "Hello, imooc! ";
// 非静态类中静态成员方法调用:https://blog.csdn.net/huyuyang6688/article/details/26224679
ClassUtil.printClassMessage(s);
ClassUtil.printFieldMessage(s);
ClassUtil.printConMessage(s);
}
}

方法的反射

基本步骤:

  1. 先获取方法所在类的类类型
  2. 得到方法 -> getMethod()
  3. 使用方法 -> invoke()
/*
* Solution.java
*/

class Solution {
void test(String s1, String s2) {
System.out.println(s1 + s2);
}
}
/*
* Test.java
*/

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 得到方法所在类的类类型
Class s = Solution.class;

/*
* 获取方法 名称和参数列表决定
* getMethod()获取的是public的方法
* getDelcareMethod()获取的是自己声明的方法
*/
/*
* Method method = s.getMethod("test",new Class[]{String.class,String.class});
* method.invoke(new Solution(),new Class[]{"Hello ","World! "});
* IDEA 建议下面的写法
*/
Method method = s.getMethod("test",String.class,String.class);
method.invoke(new Solution(),"Hello ","World! ");
}
}

集合泛型的本质

前导:

编译之后集合的泛型是去泛型化的

泛型是用来防止错误输入,只在编译阶段有效,绕过编译则无效

反射的操作都是编译之后的操作

利用方法的反射将整形元素添加到String类型集合中:

/*
* Test.java
*/

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Test{
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ArrayList list0 = new ArrayList();
ArrayList<String> list1 = new ArrayList<String>();

/*
* 下面的语句return True
* 编译之后集合的泛型是去泛型化的
* 泛型是用来防止错误输入,只在编译阶段有效
* 绕过编译则无效
*/
System.out.println(list0.getClass()==list1.getClass());

/*
* 反射的操作都是编译之后的操作
* 下面的操作成功在list1追加了整形元素
*/
Method method = list0.getClass().getMethod("add",Object.class);
method.invoke(list1,100);
//return [100]
System.out.println(list1);
}
}

现在博客写得这么起劲,还有好几本书都到了…..

事实证明想谈恋爱都是不够充实,闲得慌。

0%