Java-反射浅谈

这篇文章就是简简单单的介绍反射是什么、怎么用,面向初学者,老鸟勿喷。不涉及深层的原理。因为我不懂。

1.嘛是反射?

我在自己学习反射的时候,看到了一个说法很有意思——

有反就有正。我们先来看看“正射”是什么:

我们先定义一个Apple类,定义构造函数和属性:

class Apple
{
    private int age;
    public String name;

    public void setName(String name)
    {
        this.name = name;
    }

    private Apple()
    {
    }

    public Apple(int age, String name)
    {
        this.name = name;
        this.age = age;
    }

    public int getAge()
    {
        return age;
    }

    private void setAge(int age)
    {
        this.age = age;
    }

    
}

  然后在main函数中:

public static void main(String[] args)
{
    Apple apple = new Apple(12, "青苹果");
}

这种我们最常用的建立对象的方式就是“正射”。来看看我们是怎么定义了这个对象的:

1.我们知道有一个类叫做Apple。

2.我们至少知道这个类的一个构造函数——至少要传入一个int一个String。

我们事先知道了这个类和这个类的信息来创建对象,就是“正”。反射,就是在不知道这个类的具体信息的前提下,来创建对象、获取类的方法属性等等。一个是睁着眼一个是闭着眼,这么说你总能听明白了吧。

2.怎么使用反射?

我们既然想操作一个类,就至少得知道他是谁吧,也就是说我们得获取一个“类对象”。

类对象,用来创建其他对象的对象。

这里我们有三种方式来创建类对象:

1.Class cls=Class.forName(String string):其中参数是类的全路径名。我们知道一个类的全路径名时可以用这种方式。

class ReflectDemo
{
    public static void main(String[] args)
    {
        try
        {
            Class cls = Class.forName("Practice.Apple");
        } catch (ClassNotFoundException e)//这个方法会抛出ClassNotFoundException,找不到你指定的类就会异常。
        {
            e.printStackTrace();
        }
    }
}

2.xxx.class 适合编译之前就知道class的情况。

class ReflectDemo
{
    public static void main(String[] args)
    {
        Class cls = Apple.class;
    }
}

3.使用对象的getClass()方法。

class ReflectDemo
{
    Apple apple = new Apple();
    Class cls = apple.getClass();
}

三种方式各有各的使用场景。

好了,我们现在已经拿到了这个类的类对象,下一步我们就可以用反射建立这个类的对象了。

建立类对象有两种方式:

1.使用类对象的.newInstance()方法来获取一个使用无参的构造函数初始化的对象。

try
{
    Class cls = Class.forName("Practice.Apple");
    Apple apple = (Apple) cls.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e)
//newInstance()抛出InstantiationException(如果此 Class 表示一个抽象类、接口、数组
// 类、基本类型或 void; 或者该类没有 null 构造方法)
//与IllegalAccessException(如果该类或其 null 构造方法是不可访问的)
{
    e.printStackTrace();
}

我装的是java11,newInstance()似乎是被要废弃了?

2.通过Constructor对象的newInstance()方法。这个方式我们可以指定构造方法。

public static void main(String[] args)
{
    try
    {
        Class cls = Class.forName("Practice.Apple");
        Constructor constructor = cls.getConstructor(int.class,String.class);
        Apple apple = (Apple) constructor.newInstance(13, "毒苹果");
    } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e)
        //getConstructor()会抛出NoSuchMethodException。
        //newInstance()抛出InstantiationException,IllegalAccessException,
        //InvocationTargetException(当被调用的方法的内部抛出了异常而没有被捕获时,将由此异常接收)
    {
        e.printStackTrace();
    }
}

 在getConstructor时我们要指定参数类型。注意是class类型

对象有了,我们现在需要调用对象的属性or方法时怎么调用呢?

1.获取对象的属性

Field[] fields = cls.getFields();//cls是我们的类对象
for (Field field : fields)
{
    System.out.println(field);
}

getFields可以获取到所有除private的属性。若获取指定属性可以使用getField(String name)。

获取所有包括private的属性我们可以使用getDeclaredFields()。

2.获取对象的方法

Method[] methods = cls.getMethods();
for (Method method : methods)
{
    System.out.println(method);
}

道理同上,getDeclaredMethods()可以获取所有方法。

有了这些,我们就可以对对象进行操作了。

3.执行对象的方法

Method method = cls.getMethod("setAge", int.class);
method.invoke(apple,10);
System.out.println(apple.getAge());

分析代码:

首先我们指定了方法名来获取指定的方法(第一个参数是方法名,第二个是方法的参数的所属类。这里注意,若参数为int型的,要么写int.class,要么写Integer。Integer.class是不行的。)

接着我们调用方法的invoke(invoke,执行之意)。第一个参数是我们想在哪个对象上调用方法,第二个是参数值。(若方法为私有方法,我们虽然可以获取到但是不能执行。若想执行,则需要在执行前调用method.setAccessible(true))

 

 有了以上的知识,你就已经了解了最基本的反射知识并且能灵活使用反射了。其他的我以后补充。希望能帮助到初学者理解。

 

posted @ 2019-03-31 21:15  康先森  阅读(214)  评论(0编辑  收藏  举报