JAVA学习笔记-----反射

来源:互联网 发布:骷髅陷阱升级数据 编辑:程序博客网 时间:2024/05/24 05:58

Class类

世间万物皆对象,包括类也是对象

类也是对象,类是java.lang.Class类的实例对象。任何一个类都是Class类的实例对象,表示方式有三种。

class XXX{}public class Test{    public static void main(String[] args){        XXX x1=new XXX();    }}
  1. Class c1 = XXX.class;
  2. Class c2=xxx.getClass();
  3. Class c3=Class.forName("imooc.reflect.XXX");引号中为全类名(包括包路径)
    这三个Class对象完全等同,c1、c2、c3都代表了X类的“类类型”,一个类只可能是Class类的一个实例对象(故相同)。

通过Class的实例对象,构造具体类的实例对象

要求:该类有无参的构造方法,可通过类类型.newInstance()获取该类的实例。

try{    XXX xxx=c1.newInstance();//需要有无参的构造方法}catch(InstantiationException | IllegalAccessException e){    e.printStackTrace();}

CLass.forName(“类的全称”)

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

    1. new创建对象,是静态加载类,在编译时刻就需要加载所有可能使用到的类。
    2. 通过动态加载类可以解决静态加载的问题,运行时才加载。
      动态加载类代码如下:
try{        Class c=Class.forName(args[0]);//动态加载类,在运行时刻        //通过类类型,创建该类对象        //一般使用父类的引用指向子类的对象        Interface xxx=c.newInstance();}catch(Exception e){    e.printStackTrace();}

基本的数据类型

int、double、String、void等关键字,都存在类类型

Class类的基本API操作

  1. 首先获取该类的类类型。
    class c=obj.getClass();
  2. 类的名称
    c.getName()返回全类名,如:java.lang.String
    c.getSimpleName()返回简单类名,如:String
  3. 方法列表
    有两种方式获取:
    1.Method[] ms=c.getMethods() 获取所有的public方法,包括父类继承而来的
    2.Method[] ms=c.getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限(public/protected/defalut/private)
  4. 方法返回值
    Class returnType = ms[i].getReturnType();
    得到该方法的返回值类型的类类型。
  5. 方法参数列表
    Class[] paramTypes = ms[i].getParameterTypes();
    得到的是参数列表的类型的类类型。
  6. 获取成员变量
    1. Field[] fs=c.getFields();获取的是所有的public的成员变量的信息,包括继承的
    2. Field[] fs = c.getDeclaredFields(); 获取的是自己声明的成员变量的信息,不问访问权限
 for (Field field : fs) {      // 得到成员变量的类型的类类型      Class fieldType = field.getType();      // 获取该成员变量类型的类类型名称      String typeName = fieldType.getName();      // 得到成员变量的名称      String filedName = field.getName();      System.out.println(typeName + " " + filedName);    }
  1. 获取构造函数
    构造函数也是对象,java.lang.Constructror中封装了构造函数的信息。获取构造函数同样有两种方法。
    1. Constructor[] cs = c.getConstructors()获取所有的public的构造函数
    2. Constructor[] cs = c.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(")");}

方法的反射

1)如何获取某个方法
方法的名称和方法的参数列表才能唯一决定某个方法。
2)方法反射的操作
method.invoke(对象,参数列表)
先看代码:

public class MethodDemo1 {  public static void main(String[] args) {    // 1.获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型    A a = new A();    Class c = a.getClass();    /*     * 2.获取方法 名称和参数列表来决定      * getMethod获取的是public的方法      * getDeclaredMethod获取的是自己声明的方法     */    try {      // Method m = c.getDeclaredMethod("print", new Class[] {int.class,int.class});      Method m = c.getDeclaredMethod("print", int.class, int.class);      // 3. 方法的反射操作      // a.print(10, 20)方法的反射操作,使用m对象来进行方法调用,和a1.print调用的效果相同      // 方法如果没有返回值返回null,有返回值返回具体的返回值      // 效果等同:Object o = m.invoke(a, new Object[] { 10, 20 });      Object o = m.invoke(a, 10, 20);      System.out.println("===============================");      Method m1 = c.getMethod("print", String.class, String.class);      // 用方法进行反射操作      m1.invoke(a, "hello", "world");      System.out.println("===============================");      // 没有参数就可以不传参数,或者是new Class[]{}      // 效果等同:Method m2=c.getMethod("print", new Class[] {});      Method m2 = c.getMethod("print");      // 用方法进行反射操作      // 效果等同:m2.invoke(a, new Class[] {});      m2.invoke(a);    } catch (Exception e) {      e.printStackTrace();    }  }}class A {  public void print() {    System.out.println("hello world");  }  public void print(int a, int b) {    System.out.println(a + b);  }  public void print(String a, String b) {    System.out.println(a.toUpperCase() + b.toLowerCase());  }}

步骤1:获取该类的类类型。

A a = new A();Class c = a.getClass();

步骤2:获取该类的某个方法,通过调用c.get(Declared)Method(方法名字符串,参数类类型列表)。
参数类类型列表有两种方式:
①数组的形式传入参数的类类型:Method m = c.getDeclaredMethod("print", new Class[] {int.class,int.class});
②可变参数的形式传入参数的类类型:Method m = c.getDeclaredMethod("print", int.class,int.class);

步骤3:方法的反射操作
Object o = m.invoke(a, 10, 20);
效果等同于:a.print(10,20);
说明:Object o用来接收返回值,若没有返回值则返回null。

通过反射了解集合的泛型

反射的操作都是编译后的操作。泛型是在编译阶段起作用,防止集合中添加错误类型的数据。但是反射的操作可以绕过泛型而向集合中添加非指定的数据。
先看代码:

  public static void main(String[] args) {    ArrayList list = new ArrayList();    ArrayList<String> list1 = new ArrayList<String>();    list1.add("hello");    Class c1 = list.getClass();    Class c2 = list1.getClass();    System.out.println(c1 == c2);    //反射的操作都是编译之后的操作    /*     *c1==c2结果返回true,说明编译之后集合的泛型时候去泛型化的,     *JAVA中集合的泛型,是防止错误输入的,只在编译阶段有效,     *绕过编译就无效了     *验证:我们可以通过方法的反射来操作,绕过编译     * */    try {      Method m=c2.getMethod("add", Object.class);      m.invoke(list1, 100);// 绕过编译操作就绕过了泛型      System.out.println(list1.size());      System.out.println(list1);     /* for (String string : list1) {        System.out.println(string);      }*/    } catch (Exception e) {      e.printStackTrace();    }  }
原创粉丝点击