JavaSE|反射

什么是反射

反射指的是对象的反向处理操作。

范例:观察正常处理
默认情况下,必须先导入一个包,而后才能产生类的实例化对象

import java.util.Date;

public class HelloB {
    public static void main(String[] args) {
        Date data=new Date();
    }
}

所谓的反就是根据对象来取得对象的来源信息

Object类的一个方法,取得Class对象:

public final native Class<?> getClass();

范例:

import java.util.Date;

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

        Date data=new Date();
        //通过对象取得对象的来源
        System.out.println(data.getClass());
    }
}

在这里插入图片描述

所以在反射的世界里,看重的不再是一个对象,而是对象身后的组成(类,构造,普通,成员等)

Class类对象的三种实例化模式

Class类是描述整个类的概念,也是整个反射的操作源头,在使用Class类的时候需要关注的依然是这个类的对象。而这个类的对象的产生模式一共有三种:

  1. 任何类的实例化对象可以通过Object类中的getClass()方法取得Class类对象。
  2. “类.class”:直接根据某个具体的类来取得Class类的实例化对象。
  3. 使用Class类提供的方法:public static Class<?> forName(String className) throws ClassNotFoundException

范例:使用Class.forName方法

public class HelloB {
    public static void main(String[] args)throws ClassNotFoundException {
        Class<?> cls= Class.forName("java.util.Date");
        //通过对象取得对象的来源
        System.out.println(cls.getClass());
    }
}

范例:使用类.class

import java.util.Date;

public class HelloB {
    public static void main(String[] args)throws ClassNotFoundException {
        //通过对象取得对象的来源
        System.out.println(Date.class.getClass());
    }
}

在以上给出的三个方法中我们可以发现,除了第一种方法会产生Date类的实例化对象之外,其他的两种都不会产生Date类的实例化对象。

反射实例化对象

于是取得了Class类对象有一个最直接的好处:可以通过反射实例化对象,在Class类中定义有如下方法:

public T newInstance()
throws InstantiationException, IllegalAccessException

范例:反射实例化对象

public class HelloB {
    public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
        Class<?> cls=Class.forName("java.util.Date");//产生类对象
        System.out.println(cls);
        Object obj=cls.newInstance();// 实例化对象,等价于 new java.util.Date() ;
        System.out.println(obj);
    }
}


我们发现除了关键字new之外,对于对象的实例化模式有了第二种做法,通过反射进行

取得了Class对象就意味着取得了一个指定类的操作权

反射与工厂模式

详细工厂模式可参考之前的文章,简单工厂模式每加一个产品的种类就要修改一次工厂类。我们可以通过反射来完成处理。
范例:


package hhh.Test;

import java.util.Date;

interface IFruit {
    public void eat() ;
}
class Apple implements IFruit {
    @Override
    public void eat() {
        System.out.println("[Apple] 吃苹果 ");
    }
}
class Orange implements IFruit {
    @Override
    public void eat() {
        System.out.println("[Orange] 吃橘子 ");
    }
}
class FruitFactory{
    private FruitFactory(){}
    public static IFruit getInstance(String className){
        IFruit fruit=null;
        try {
            fruit=(IFruit)Class.forName(className).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return fruit;
    }
}
public class HelloB {
    public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
       IFruit fruit=FruitFactory.getInstance("hhh.Test.Orange");
       fruit.eat();
    }
}


引入反射后,每当新增接口子类,无需去修改工厂类代码就可以很方便的进行接口子类扩容。

反射与类操作

取得父类信息

在java中任何的程序类都一定会有父类,在Class类中就可以通过如下方法来取得父类或者实现的父接口:

1.取得类的包名称: public Package getPackage();

范例:取得包名称

interface IFruit {}
interface IMessage{}
class CLS implements IFruit,IMessage{}
public class HelloB {
    public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
       Class<?> cls=CLS.class;//取得Class类对象
        System.out.println(cls.getPackage().getName());
    }
}


在这里插入图片描述

2.取得父类的Class对象: public native Class<? super T> getSuperclass();
3.取得实现的父接口:public Class<?>[] getInterfaces()

interface IFruit {}
interface IMessage{}
class CLS implements IFruit,IMessage{}
public class HelloB {
    public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
       Class<?> cls=CLS.class;//取得Class类对象
        //取得包名
        System.out.println(cls.getPackage().getName());
        //取得父类名称
        System.out.println(cls.getSuperclass().getName());
        //取得实现的父类接口对象
        Class<?>[] iClass=cls.getInterfaces();
        for(Class<?> class1:iClass){
            System.out.println(class1.getName());
        }
    }
}

在这里插入图片描述

反射调用构造

1.取得指定参数类型的构造:

public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException

2.取得类中的所有构造方法


public Constructor<?>[] getConstructors() throws SecurityException

以上两个方法返回的类型都是java.lang.reflect.Constructor类的实例化对象,这个类之中大家只需要关注一个方法
实例化对象:


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

范例:

import java.lang.reflect.Constructor;
import java.util.Date;

class Person{
    public Person(){}
    public Person(String name){}
    public Person(String name,int age){}

}
public class HelloB {
    public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
       Class<?> cls=Person.class;//取得Class类对象
        Constructor<?>[] con=cls.getConstructors();
        for(Constructor<?> tmp:con){
            System.out.println(tmp);
        }
    }
}


在这里插入图片描述
范例:

class Person{
    private String name;
    private int age;

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

    @Override
    public String toString() {
         return "Person [name=" + name + ", age=" + age + "]";

    }
}
public class HelloB {
    public static void main(String[] args)throws ClassNotFoundException,InstantiationException,IllegalAccessException {
       Class<?> cls=Person.class;//取得Class类对象
        System.out.println(cls.newInstance());
    }
}

在这里插入图片描述

所以在定义简单java类的时候一定要保留有一个无参构造。Class类通过反射实例化类对象的时候,只能够调用类中的无参构造。如果现在类中没有无参构造则无法使用Class类调用,只能够通过明确的构造调用实例化处理。

范例:通过Constructor类实例化对象


package hhh.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;

class Person{
    private String name;
    private int age;

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

    @Override
    public String toString() {
         return "Person [name=" + name + ", age=" + age + "]";

    }
}
public class HelloB {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
       Class<?> cls=Person.class;//取得Class类对象
        Constructor<?> con=cls.getConstructor(String.class,int.class);
        System.out.println(con.newInstance("HL",18));
    }
}

在这里插入图片描述

反射调用普通方法(核心)

1.取得全部普通方法:


public Method[] getMethods() throws SecurityException

2.取得指定普通方法


public Method getMethod(String name, Class<?>... parameterTypes)

以上两个方法范辉的类型是java.lang.reflect.Method类的对象,在此类中提供有一个调用方法的支持


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

范例:取得一个类中的全部普通方法


package hhh.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

class Person{
    private String name;
    private int age;

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
         return "Person [name=" + name + ", age=" + age + "]";

    }
}
public class HelloB {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
       Class<?> cls=Person.class;//取得Class类对象
        Method[] methods=cls.getMethods();
        for(Method method:methods){
            System.out.println(method);
        }
    }
}


在这里插入图片描述
范例:通过反射调用setter、getter


package hhh.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

class Person{
    private String name;
    private int age;

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

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
         return "Person [name=" + name + ", age=" + age + "]";

    }
}
public class HelloB {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
      // Class<?> cls=Class.forName("hhh.Test.Person");//取得Class类对象
        Class<?> cls=Person.class;
       Object obj=cls.newInstance();//实例化类对象
        //取得setName这个方法的实例化对象,设置方法名称和参数模型
        Method setMethod=cls.getMethod("setName",String.class);
        // 随后需要通过Method类对象调用指定的方法,调用方法需要有实例化对象
        // 同时传入参数
        setMethod.invoke(obj,"HL");// 相当于Person对象.setName("HL") ;
        Method getMethod=cls.getMethod("getName");
        Object result=getMethod.invoke(obj);

        System.out.println(result);

    }
}

反射调用类中属性

类中的所有属性一定在类对象实例化之后才会进行空间分配,所以此时如果要想调用类的属性,必须保证有实例化对象。通过反射的newInstance()可以直接取得实例化对象(Object类型)

在Class类中提供有两组取得属性的方法:

  1. 第一组(父类中)-取得类中全部属性: public Field[] getFields() throws SecurityException
  2. 第一组(父类中)-取得类中指定名称属性: public Field getField(String name) throws
    NoSuchFieldException, SecurityException
  3. 第二组(本类中)-取得类中全部属性: public Field[] getDeclaredFields() throws SecurityException
  4. 第二组(本类中)-取得类中指定名称属性 : public Method getDeclaredMethod(String name, Class<?.. parameterTypes) throws NoSuchMethodException, SecurityException

范例:取得类中全部属性



package hhh.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

class Person{
    public String name;
    public int age;

    public Person(){}
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
class Student extends Person{
    private int id;
    public Student(){}
}
public class HelloB {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        Class<?> cls=Student.class; //取得Class类对象
        //如果父类成员变量是private属性,那么就不会被子类取得
        {//普通代码块
            Field[] fields=cls.getFields();
            for(Field field:fields){
                System.out.println(field);
            }
        }
        System.out.println("*********************");
        {
            Field[] fields=cls.getDeclaredFields();
            for(Field field:fields){
                System.out.println(field);
            }
        }
    }
}

属性的核心描述类:java.lang.reflect.Field,在这个类之中有两个重要方法:

  1. 设置属性内容 : public void set(Object obj, Object value) throws IllegalArgumentException,IllegalAccessException
  2. 取得属性内容 : public Object get(Object obj) throws IllegalArgumentException,IllegalAccessException
    在这里插入图片描述
    范例:通过反射操作属性

package hhh.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

class Person {
    public String name;
    public int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class HelloB {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
        Class<?> cls=Person.class; //取得Class类对象
        Object obj=cls.newInstance();//实例化类对象
        Field nameField=cls.getDeclaredField("name");//获取对象的成员变量
        nameField.set(obj,"HL");//设置指定的变量
        System.out.println(nameField.get(obj));//取得指定变量的值

    }
}

发布了87 篇原创文章 · 获赞 73 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/HL_HLHL/article/details/88637098