天天看点

【Java】反射Java反射调用方法获取继承关系

Java反射

通过

Class

实例获取

class

信息的方法称为反射(Reflection)

Class类

获取一个

class

Class

实例有三种方法:

  • 直接通过一个

    class

    的静态变量

    class

    获取
  • 如已有一个实例变量,可通过该实例变量的

    getClass()

    方法获取
String s = "Hello";
Class cls = s.getClass();
           
  • 如已知道一个

    class

    的完整类名,可通过静态方法

    Class.forName()

    获取

反射的目的是为了获得某个实例的信息。因此,当我们拿到某个

Object

实例时,我们可以通过反射获取该

Object

class

信息:

public class Main {
    public static void main(String[] args) {

        printClassInfo(String[].class);
    }

    static void printClassInfo(Class cls) {
        System.out.println("Class name: " + cls.getName());
        //Class name: [Ljava.lang.String;
        System.out.println("Simple name: " +cls.getSimpleName()); //Simple name: String[]
        if (cls.getPackage() != null) {
            System.out.println("Package name: " + cls.getPackage().getName());
        }
        System.out.println("is interface: " + cls.isInterface()); // is interface: false
        System.out.println("is enum: " + cls.isEnum()); //is enum: false
        System.out.println("is array: " + cls.isArray()); //is array: true
        System.out.println("is primitive: " + cls.isPrimitive()); //is primitive: false
    }
}
           

也可以根据一个已知的

Class

实例来创建对应类型的新实例:

// 获取String的Class实例:
Class cls = String.class;
// 创建一个String实例:
String s = (String) cls.newInstance();
           

上述代码相当于

new String()

。通过

Class.newInstance()

可以创建类实例,它的局限是:只能调用

public

的无参数构造方法。带参数的构造方法,或者非

public

的构造方法都无法通过

Class.newInstance()

被调用。

访问字段

通过

Class

实例,获取所有

Field

对象。

Class

类提供了以下几个方法来获取

Field

字段:

  • Field getField(name)

    :根据字段名获取某个

    public

    field

    (包括父类)
  • Field getDeclaredField(name)

    :根据字段名获取当前类的某个

    field

    (不包括父类)
  • Field[] getFields()

    :获取所有

    public

    field

    (包括父类)
  • Field[] getDeclaredFields()

    :获取当前类的所有

    field

    (不包括父类)

一个

Field

对象包含了一个字段的所有信息:

  • getName()

    :返回字段名称,例如,

    "name"

  • getType()

    :返回字段类型,也是一个

    Class

    实例,例如,

    String.class

  • getModifiers()

    :返回字段的修饰符,它是一个

    int

    ,不同的bit表示不同的含义。
public static void main(String[] args) throws NoSuchFieldException {

        Field f = People.class.getDeclaredField("name");
        f.getName(); // "name"
        f.getType(); // class java.lang.String
        int m = f.getModifiers();
        Modifier.isFinal(m); // false
        Modifier.isPublic(m); // false
        Modifier.isProtected(m); // false
        Modifier.isPrivate(m); // true
        Modifier.isStatic(m); // false
    }

    public final class People{
        private String name;

        public People(String name) {
            this.name = name;
        }
    }
           

获取字段值

对于一个

People

实例,我们可以先拿到

name

字段对应的

Field

,再获取这个实例的

name

字段的值:

public class Main {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

        Object p = new People("ASHER");
        Field f = p.getClass().getDeclaredField("name");
        f.setAccessible(true); //别管这个字段是public还是private,一律允许访问!暴力!
        System.out.println(f.get(p));
    }
}

class People{
    private String name;

    public People(String name) {
        this.name = name;
    }
}
           

注意:上述代码

People

类的

name

字段是

private

,如果不加**

f.setAccessible(true);

**,由于

Main

类无法访问

Person

类的

private

字段,就会得到一个

IllegalAccessException

设置字段值

通过

Field

实例不仅可以获取字段值,也可以设置字段值,通过

Field.set(Object,Object)

实现,其中第一个

Object

参数是指定的实例,第二个

Object

参数是待修改的值:

public class Main {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

        People p = new People("ASHER");
        Field f = p.getClass().getDeclaredField("name");
        f.setAccessible(true);
        System.out.println("原名:" + f.get(p)); //原名:ASHER
        f.set(p,"asher");
        System.out.println("现名:" + p.getName()); //现名:asher
    }
}

class People{
    private String name;

    public People(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
           

调用方法

通过

Class

实例,获取所有

Method

信息。

Class

类提供了以下几个方法来获取

Method

  • Method getMethod(name, Class...)

    :获取某个

    public

    Method

    (包括父类)
  • Method getDeclaredMethod(name, Class...)

    :获取当前类的某个

    Method

    (不包括父类)
  • Method[] getMethods()

    :获取所有

    public

    Method

    (包括父类)
  • Method[] getDeclaredMethods()

    :获取当前类的所有

    Method

    (不包括父类)

调用方法

  • getMethod("substring", int.class, int.class)

    就是获取这个

    class

    类的"

    substring

    "方法,然后传入该方法所需的两个参数的类
  • invoke()

    就是调用

    m

    这个方法,第一个参数是指定在哪个实例上是使用该方法
String s1 = "Hello world";
Method m = s1.getClass().getMethod("substring", int.class, int.class);
String s2 = (String)m.invoke(s1,6,8); //wo
           

调用静态方法

调用静态方法时,由于无需指定实例对象,所以

invoke

方法传入的第一个参数永远为

null

下面就是调用

Integer

getMethod()

方法,将

String

型的字符串转为

Integer

型:

Method m = Integer.class.getMethod("parseInt", String.class);
Integer s = (Integer)m.invoke(null,"123"); //123
           

调用非public方法

对于非public的方法,首先要对该方法设置

Method.setAccessible(true)

,然后再使用

Class.getDeclaredMethod()

获取。

public class Main {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        People p = new People();
        Method m = p.getClass().getDeclaredMethod("getName",null);
        m.setAccessible(true);
        String s = (String)m.invoke(p,null); //asher
    }
}

class People{
    private String name = "asher";

    private String getName() {
        return name;
    }
}
           

获取继承关系

获取父类的Class

Integer

的父类类型是

Number

Number

的父类是

Object

Object

的父类是

null

Object

外,其他任何非

interface

Class

都必定存在一个父类类型。

Class i = Integer.class;
Class n = i.getSuperclass(); //class java.lang.Number
Class o = n.getSuperclass(); //class java.lang.Object
System.out.println(o.getSuperclass()); //null
           

获取interface接口

  • Class[] getInterfaces()

    :获取当前类直接实现的所有接口(不包括父类实现的接口)
  • Class getSuperclass()

    :获取父类类型

查询

String

实现的接口:

Class cla = String.class;
Class[] clas = cla.getInterfaces();
System.out.println("=====接口为:=====");
for(Class c : clas){
    System.out.println(c.getName());
}
System.out.println("=====父类为:=====");
System.out.println(cla.getSuperclass().getName());
           

=接口为:=

java.io.Serializable

java.lang.Comparable

java.lang.CharSequence

=父类为:=

java.lang.Object

继承关系

  • instanceof

    :判断某个实例是否是某个类型
  • isAssignableFrom()

    :判断一个

    Class

    向上转型是否是另一个

    Class

// Integer i = ?
Integer.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Integer
// Number n = ?
Number.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Number
// Object o = ?
Object.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Object
// Integer i = ?
Integer.class.isAssignableFrom(Number.class); // false,因为Number不能赋值给Integer