Java反射(java.lang.reflect)

版权声明:本文为博主原创文章,转载请附上博文链接! https://blog.csdn.net/f2764052703/article/details/89311013

什么是Java反射

Java反射是一种可以让我们在代码运行的时候,动态地获取我们想要创建实例的类信息,使用获得到的类的信息来获得一个程序执行时的对象的一种方法,也就是说,使用反射这种方法,我们不需要在代码中指明我们想要创建什么类型的实例,而是让代码自动地去获取我们想要创建的实例的它的类的信息,这样做,我们可以极大程度地降低程序的耦合程度。

反射是一种方法,那么举一反三,我们使用这个思路可以获得类的属性(Field 类),类的方法(Method 类)



反射的原理

在程序运行的时候获取到想要创造实例的类的信息,使用Class类来创建一个对应的实例。避免了使用new关键字,达到在程序运行时动态创建实例的效果。



如何实现反射

1、获得类的信息(获得到的是类的全路径信息)

获取类的信息有三种方法:

  1. 使用class类的forName()方法获取类的信息
  2. 使用实例的getClass()获取类的信息
  3. 通过类名获得类的信息

示例:

package com.page;

public class test {
    public static void main(String[] args) {
    
        // 1、使用Class类中的forName()获得类的信息
        try {
            // forName()返回的是一个Class类型的对象
            Class a = Class.forName("com.page.A");
            System.out.println("这个类是:"+a);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // 2、 使用实例的getClass()获得类的信息
        A a = new A();
        System.out.println("这个类是:"+a.getClass());

        // 3、使用类名获得类的信息
        System.out.println(A.class);
    }
}



2、使用类的信息创建类实例(获得到的是一个对象,在堆中开辟了空间)

使用Class类的newInstance()方法获得一个具体的实例
代码示例:

package fanShe;

public class test1 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Class a= A.class;
        // 这里需要将类型进行强行转换因为newInstance()方法返回的是一个泛型类型
        A a1 = (A) a.newInstance();
        a1.age = 12;
        a1.firset = 13;
        a1.name = "xm99";
        System.out.println(a1);

    }
}

class A{
    int age;
    String name;
    int firset;

    @Override
    public String toString() {
        return "age:"+age+"name:"+name;
    }
}

在使用newInstance()方法获得类实例的时候需要将实例的类型进行强制转换



获得类的信息以后我们都可以干什么

使用reflect(反射)包下面的Field和Method类获得类的属性和方法,并对属性和方法进行操作。

1、获得类的属性(获得的是类属性的全路径)

获得类的信息以后,我们可以通过Class类中的getDeclaredField(String name)getDeclaredFields()getField(String name)getFields() 方法获得类中的属性。

getDeclaredField(String name):可以获得任何权限的一个字段

getDeclaredFields():可以获得任何权限的所有字段数组

getField(String name):可以获得public的一个字段

getFields():可以获得public的所有字段数组

代码示例:

package fanShe;

import java.lang.reflect.Field;

public class test1 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Class a= A.class;
        // 这里需要将类型进行强行转换因为newInstance()方法返回的是一个泛型类型
        Field[] f = a.getFields();
        Field[] f1 = a.getDeclaredFields();
        for (Field fx :f) {
            System.out.println(fx);
        }

        System.out.println("------------------------------");

        for (Field fx:f1 ) {
            System.out.println(fx);
        }

        System.out.println("-------------------------------");

        try {
            Field fs1 = a.getField("age");
            System.out.println(fs1);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        System.out.println("--------------------------------------");

        try {
            Field fs2 = a.getDeclaredField("age");
            System.out.println(fs2);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

    }
}

class A{
    public int age;
    private String name;
    protected int firset;

    @Override
    public String toString() {
        return "age:"+age+"name:"+name;
    }
}



2、获得类的方法

获得类的全路径名以后可以使用Class类中的getDeclaredMethod(String name, Class<?>... parameterTypes)getDeclaredMethods()getMethod(String name, Class<?>... parameterTypes)getMethods()方法来获得类中的方法。

getDeclaredMethod(String name, Class<?>... parameterTypes):返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

getDeclaredMethods():反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

getMethod(String name, Class<?>... parameterTypes):返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

getMethods():返回一个包含所有public方法的 Method 对象的数组,包括从父类和实现的接口中继承过来的那些

代码示例:

package com.page;

import java.lang.reflect.Method;

public class test2 {
    public static void main(String[] args) {
        try {
            Class a = Class.forName("com.page.B");
            Method[] m1 = a.getMethods();
            Method[] m2 = a.getDeclaredMethods();

            for (Method m:m1 ) {
                System.out.println(m);
            }

            System.out.println("-------------------------------------");

            for (Method m:m2 ) {
                System.out.println(m);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class B{
    public void he(){
        System.out.println("hello world");
    }

    protected void he2(){
        System.out.println("hello world this is 2");
    }

    public void he3(){
        System.out.println("this is 3");
    }

    protected void he4(){
        System.out.println("this is 4");
    }

    private void he5(){
        System.out.println("this is 5");
    }
}

执行结果:

D:\install\java\bin\java.exe "-javaagent:D:\install\idea\IntelliJ IDEA 2018.3.5\lib\idea_rt.jar=59990:D:\install\idea\IntelliJ IDEA 2018.3.5\bin" -Dfile.encoding=GBK -classpath D:\install\java\jre\lib\charsets.jar;D:\install\java\jre\lib\deploy.jar;D:\install\java\jre\lib\ext\access-bridge-64.jar;D:\install\java\jre\lib\ext\cldrdata.jar;D:\install\java\jre\lib\ext\dnsns.jar;D:\install\java\jre\lib\ext\jaccess.jar;D:\install\java\jre\lib\ext\jfxrt.jar;D:\install\java\jre\lib\ext\localedata.jar;D:\install\java\jre\lib\ext\nashorn.jar;D:\install\java\jre\lib\ext\sunec.jar;D:\install\java\jre\lib\ext\sunjce_provider.jar;D:\install\java\jre\lib\ext\sunmscapi.jar;D:\install\java\jre\lib\ext\sunpkcs11.jar;D:\install\java\jre\lib\ext\zipfs.jar;D:\install\java\jre\lib\javaws.jar;D:\install\java\jre\lib\jce.jar;D:\install\java\jre\lib\jfr.jar;D:\install\java\jre\lib\jfxswt.jar;D:\install\java\jre\lib\jsse.jar;D:\install\java\jre\lib\management-agent.jar;D:\install\java\jre\lib\plugin.jar;D:\install\java\jre\lib\resources.jar;D:\install\java\jre\lib\rt.jar;D:\demo\javaBase\out\production\javaBase com.page.test2
public void com.page.B.he()
public void com.page.B.he3()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
-------------------------------------
public void com.page.B.he()
protected void com.page.B.he4()
protected void com.page.B.he2()
private void com.page.B.he5()
public void com.page.B.he3()

Process finished with exit code 0



执行类的方法

使用Method类的invoke(Object obj, Object... args)方法执行类的方法。
代码示例:

package com.page;

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

public class test2 {
    public static void main(String[] args) {
        try {
            Class a = Class.forName("com.page.B");
            
            // 这里传入的方法参数,只需要写入方法名,不需要加括号
            Method m = a.getMethod("he");
            try {
                // invoke函数需要一个Object对象作为参数,如果没有参数,则需要传入null
                Object i = m.invoke(null);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

class B{
    public static void he(){
        System.out.println("hello world");
    }
}

划重点啦!!!
invoke()使用应当小心的地方:
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。

如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。

如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。

如果底层方法是实例方法,则使用动态方法查找来调用它,这一点记录在 Java Language Specification, Second Edition 的第 15.12.4.4 节中;在发生基于目标对象的运行时类型的重写时更应该这样做。

如果底层方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。

如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素不 被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。

猜你喜欢

转载自blog.csdn.net/f2764052703/article/details/89311013