反射与类的具体操作

1. 获取父类信息

Class类中提供了一些方法来获取父类信息,以下列举出三个:

  • 获取类的包名称:public Package getPackage()
  • 取得父类的Class对象:public native Class<? super T> getSuperclass();
  • 取得实现的父接口:public Class<?>[] getInterfaces()

举例:使用以上三个方法


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

        Class classz = Student.class;
        //1.取得Student类的包名
        Package packagez = classz.getPackage();
        System.out.println(packagez.getName());  //www.csdn.classse

        //2.获取Student父类的Class对象
        Class superclass = classz.getSuperclass();
        //类的权限定名称,包含包名  www.csdn.classse.Person
        System.out.println(superclass.getName());
        //只含类名称  Person
        System.out.println(superclass.getSimpleName());

        //3.取得Student类实现的接口
        Class[] interfaces = classz.getInterfaces();
        for(Class cls:interfaces){
            System.out.println(cls.getSimpleName());
        }
    }
}
interface Message{}

interface Knowledge{}

class Person{}

class Student extends Person implements Message,Knowledge{}

2. 调用构造方法

一个类中可以有多个构造方法,如果想要取得类中的构造方法,就可以使用Class类中的两个构造方法

  • 取得指定参数类型的构造
public Constructor<T> getConstructor(Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException 
  • 取得类中的所有构造
public Constructor<?>[] getConstructors() throws SecurityException

举例:获取类中的构造方法


public class TestReflect {
    public static void main(String[] args) {
        Class personClass = Person.class;
        //获取所有构造方法
        Constructor[] constructors = personClass.getConstructors();
        for (Constructor c:constructors){
            System.out.println(c.getName()+" ("+Arrays.toString(c.getParameterTypes())+")");
        }
        System.out.println("------------");

        //获取不同参数列表的构造方法
        try {
            Constructor constructor = personClass.getConstructor(String.class);
            System.out.println(constructor.getName()+" ("+Arrays.toString(constructor.getParameterTypes())+")");

            Constructor constructor1 = personClass.getConstructor(String.class, Integer.class);
            System.out.println(constructor1.getName()+" ("+Arrays.toString(constructor1.getParameterTypes())+")");

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

使用到的Person类:


public class Person {
    private String name;
    private Integer age;

    public Person(){
    }

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

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

之前通过反射实例化对象的时候,是通过Class对象调用newInstance()方法实例化的。这其中必须保证该类是有一个无参构造的。但若此时我们在自定义Person类的时候,没有无参构造,则无法使用Class类调用。那么此时我们可以通过明确的调用构造实例化去处理。
Constructor中的newInstance方法

public T newInstance(Object ... initargs)
        throws InstantiationException, IllegalAccessException,
               IllegalArgumentException, InvocationTargetException

举例:通过Constructor实例化对象


public class TestReflect {
    public static void main(String[] args) {
        Class personClass = Person.class;
        try {
        	//取得指定参数列表的构造方法
            Constructor constructor = personClass.getConstructor(String.class,Integer.class);
            //利用构造方法实例化对象
            Object object = constructor.newInstance("张三",20);

            Constructor constructor1 = personClass.getConstructor(String.class);
            Object object1 = constructor1.newInstance("张三");

            System.out.println(object);
            System.out.println(object1);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

public class Person {
    private String name;
    private Integer age;


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

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

3. 反射调用普通方法

Class中有两种取得类中的普通方法的函数:

  • 取得所有类中的普通方法
public Method[] getMethods() throws SecurityException
  • 取得指定的普通方法
public Method getMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException 

举例:获取类中的普通方法


public class TestReflect {
    public static void main(String[] args) {
        Class personClass = Person.class;
        //获取Person类中所有的方法
        Method[] methods = personClass.getMethods();
        for (Method m:methods){
            System.out.println(m.getName()+"("+Arrays.toString(m.getParameterTypes())+")");
        }
        System.out.println("------------");

        //获取Person类中指定的普通方法
        try {
            Method method = personClass.getMethod("setName", String.class);
            System.out.println(method.getName()+"("+Arrays.toString(method.getParameterTypes()));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

在以前我们调用一个自定义类的setter和getter方法时,必须实例化该类的对象,用对象调用这些方法。现在通过反射,可以不用有明确的实例化对象,就可以调用方法
java.lang.reflect.Method中提供了一个调用方法的支持:

public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException

举例:使用反射去调用自定义类中的方法


public class TestReflect {
    public static void main(String[] args) {
        Class personClass = Person.class;

        try {
            //取得Class的实例化对象
            Object object = personClass.newInstance();
            //获取指定的方法,设置方法名称和参数类型
            Method setMethod = personClass.getMethod("setName", String.class);
            //用Method对象去调用指定方法,同时传入参数
            setMethod.invoke(object,"张三");  //相当于person.setName("张三");

            Method getMethod = personClass.getMethod("getName");
            Object result = getMethod.invoke(object);  //相当于person.getName();
            System.out.println(result);   //张三
            System.out.println(object);

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

4. 反射调用类中属性

在反射调用类中属性时,必须实例化对象,通过newInstance()可以直接取得实例化对象(Object)
在Class中提供了两组获得属性的方法:

  1. 取得类中(父类和子类)全部属性:public Field[] getFields()
  2. 取得类中(父类和子类)指定名称属性:public Field getField(String name)

  1. 取得类中(Class类对象的类型)全部属性:public Field[] getDeclaredFields()
  2. 取得指定类中(Class类对象的类型)的名称属性:public Field getDeclaredField(String name)

举例:使用两组方法


public class TestReflect {
    public static void main(String[] args) {
        Class<Student> studentClass = Student.class;
        try {
            Object object = studentClass.newInstance();
            //获取所有属性,包括父类属性
            Field[] fields = studentClass.getFields();
            for (Field f :fields){
                System.out.println(f.getName());
            }
            Field field = studentClass.getField("school");
            System.out.println(field.getName());

            System.out.println("--------------");
            //获取Class对象的类的所有属性
            Field[] fields1 = studentClass.getDeclaredFields();
            for (Field f:fields1){
                System.out.println(f.getName());
            }
            Field field1 = studentClass.getDeclaredField("school");
            System.out.println(field1.getName());

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
public class Person {
    private String name;
    public Integer age;

}
public class Student extends Person {
    private String school;
}

在以上的过程中发现,如果想要得到父类的属性必须属性是public修饰的。而如果只是访问本类属性,private修饰的也可以访问。所以常用的获取属性的方式为第二组。
另外,在java.lang.reflect.Field中有三个方法:

  • 设置属性内容:
public void set(Object obj, Object value)
        throws IllegalArgumentException, IllegalAccessException
  • 取得属性内容:
public Object get(Object obj)
        throws IllegalArgumentException, IllegalAccessException
  • 取得属性类型
public Class<?> getType()

举例:使用上面的方法


class Person{
    public String name;
    private Integer age;
}

public class TestReflect {
    public static void main(String[] args) {
        Class<Person> personClass = Person.class;
        try {
            Object object = personClass.newInstance();
            //获取指定属性
            Field field = personClass.getDeclaredField("name");
            //获取属性类型
            System.out.println(field.getType().getName());  //java.lang.String
            //设置属性内容
            field.set(object,"张三");  //等价于person.name = "张三";
            //取得属性内容
            System.out.println(field.get(object));  //张三

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

5. 总结

1. 在获取父类信息时,通过类对象调用Class类的方法,获取父类信息。在上面介绍的主要有三个:(1)获取包;(2)获取继承的父类;(3)获取实现的父类接口。
2. 对于获取构造方法,获取普通方法,获取属性,Class类都各自提供了2个方法。
3. 在通过反射实例化对象时,如果自定义类中含有无参构造,那么直接通过Class类中的newInstance()方法去实例化对象;如果没有,则先取得指定参数列表的构造方法,在通过Constructor类中的newInstance(Object...initargs)去实例化对象。
4. 反射调用方法时,通过Method类中的invoke(Object obj, Object...initargs),也可以同时传参。

这些方法都是很简单的,只要多用几次,就能熟练掌握!!!

猜你喜欢

转载自blog.csdn.net/mi_zhi_lu/article/details/91909612
今日推荐