今天看啥  ›  专栏  ›  Iam_Bling

Java-反射

Iam_Bling  · 简书  ·  · 2018-12-03 09:39

Class类的使用

Class类比较特殊,也比较难理解一些,所有类都是它的实例对象。我们用代码来理解一下:

public class ClassDemo {
    public static void main(String[] args){
        Person person = new Person();
    }
}
class Person{}

普通的person是Person类的实例对象,同时Person这个类也是Class类的一个实例对象。当然Class类的实例对象不是new出来,它有三种表示方式,我们来看一下:

第一种:

在知道类名的情况下,调用该类的隐式的静态成员变量class

Class c1 = Person.class;
第二种:

在知道实例对象名的情况下调用对象的getClass()方法。

Class c2 = person.getClass();

可以这么说,c1、c2表示了Person类的类类型

第三种:

通过class类的forName()方法创建,但是需要捕获异常。

Class c3 = null;
try {
    c3 = Class.forName("Person");
}catch (ClassNotFoundException e){
    e.printStackTrace();
}

最后打印可以看到三种方法创建的对象是完全相等的。

System.out.println(c1 == c2 && c2 == c3); //true

我们也完全可以通过类的类类型创建该类的实例对象,调用类类型的newInstance()方法,这里需要做一下类型强转,而且需要捕获两个异常。
先给Person类中添加一个方法,用来测试

class Person{
    public void show(){
        System.out.println("通过类类型也可以创建实例对象鸭");
    }
}

创建出实例对象后调用show()方法,可以看到正常打印。

try {
    Person person1 = (Person) c1.newInstance();
    person1.show();
}catch (InstantiationException e){
    e.printStackTrace();
}catch (IllegalAccessException e){
    e.printStackTrace();
}

Class类还提供了一堆获取成员信息的方法,可以看文档进行了解。(成员方法、变量、构造方法)

动态加载类

之前我们 通过new关键字创建对象属于静态加载,在编译时就要加载所有的类,如果一个有问题就会影响整个程序。那么能不能再调用到的时候再去加载类呢?答案是肯定的,这就是我们要说的动态加载。

不使用动态加载的例子:

if("Man".equals(args[0])){
    Man man = new Man();
}
if("Woman".equals(args[0])){
    Woman woman = new Woman();
}

这里args[0]是一个命令行参数,动态传递进来的,这段代码就要求两个类都得存在,如果有一个不存在即使用不到这个类也会影响整个程序。我们用动态加载可以很好的避免这一点:

try{
    Class c = Class.forName(args[0]);
    Person person = (Person)c.newInstance();
}

这里我们不知道传递进来的是什么类型的,在强转类型时怎么办呢?在创建所有要用到的类(比如Man类实现Person接口)的时候统一实现Person接口即可(泛型)。这样只有用到才会调用此类。

方法反射

先写一个简单的反射了解一下:

class Person{
    public void show(){
        System.out.println("无参方法");
    }
    public void show(int a, int b){
        System.out.println(a+b);
    }
}

Person person = new Person();
Class c = person.getClass();
try {
    // Method method = c.getMethod("show", new Class[]{int.class, int.class});
    Method method = c.getMethod("show", int.class, int.class);
    method.invoke(person, 2, 3);
    Method method1 = c.getMethod("show");
    method1.invoke(person);
}catch (Exception e){
    e.printStackTrace();
}
  1. 先通过前面说过的三种方法获取到类的类类型,这里就是c。

  2. 通过getMethod()方法获取到类的方法,第一个参数是方法名,后面的参数可以是一个参数数组(注释掉部分),也可以直接把参数全部写出来(没有参数可以不写,也可以写空数组)。

  3. 使用方法对象的invoke方法来调用该类的方法,第一个参数是类的实例对象,后面参数和getMethod()写法一样。

  4. 可以看到两个方法都被执行了。




原文地址:访问原文地址
快照地址: 访问文章快照