反射

将类的各个组成部分封装为其他对象,就是反射机制


image.png

反射的好处:

  • 在程序的运行过程中,操作这些对象
  • 可以解耦,提高程序的可扩展性

获取class对象(对应三个阶段)

  • class.forName("全类名"):将字节码文件加载进内存
  • 类名.class:通过类名的属性class获取
  • 对象.getClass():getClass()方法在Object类中定义着
class Person{
    private int age;
    private String name;
    public String a;
    protected String b;
    String c;

    public Person(){
    }

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

    public void eat(){
        System.out.println("eating");
    }

    public void eat(String food){
        System.out.println("eating:" + food);

    }

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


public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class cls1 = Class.forName("Person");
        System.out.println(cls1);

        Class cls2 = Person.class;
        System.out.println(cls2);

        Person p = new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);

        // 比较三个对象的内存地址
        System.out.println(cls1 == cls2);  // true
        System.out.println(cls1 == cls3);  // true
    }
}

结论:
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个

class对象功能:
1.获取功能

  • 获取成员变量们
    Field[] getFields():获取所有public修饰的成员变量
    Field getField(String name):获取指定名称的public修饰的成员变量
    Field[] getDeclaredFields():获取所有成员变量,不考虑修饰符(对于private,需设置setAccessible=true)
    Field getDeclaredField(String name):获取指定名称的成员变量

  • 获取构造方法们

  • 获取成员方法们

  • 获取类名

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class cls = Person.class;
        Field[] fields = cls.getFields();
        for(Field f: fields){
            System.out.println(f);
        }  // 只打印 public java.lang.String Person.a

        Field a = cls.getField("a");
        Person p = new Person();
        Object value = a.get(p);
        System.out.println(value);  // null

        // 设置a的值
        a.set(p, "张三");
        System.out.println(p);  // Person{age=0, name='null', a='张三', b='null', c='null'}
    }
}
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class cls = Person.class;
        Field f2 = cls.getDeclaredField("name");
        f2.setAccessible(true);  // 没有这句话会报错
        Person p = new Person();
        Object value = f2.get(p);
        System.out.println(value);

    }
}

构造方法
获取到构造器的最主要的目的就是创建对象

public class ReflectDemo {

    public static void main(String[] args) throws Exception {
        Class cls = Person.class;

        // 带参的构造器使用
        Constructor constructor = cls.getConstructor(int.class, String.class);
        System.out.println(constructor);  // public Person(int,java.lang.String)
        // 创建对象
        Object person = constructor.newInstance(18, "张三");
        System.out.println(person);  // Person{age=18, name='张三', a='null', b='null', c='null'}

        // 无参构造器的使用
        Constructor constructor1 = cls.getConstructor();
        Object person1 = constructor1.newInstance();
        System.out.println(person1);

        // 等价于上面的无参构造
        Object o = cls.newInstance();
        System.out.println(o);

    }
}

获取成员方法

public class ReflectDemo {

    public static void main(String[] args) throws Exception {
        Class cls = Person.class;

        Method method = cls.getMethod("eat");
        Person p = new Person();
        method.invoke(p);

        Method method1 = cls.getMethod("eat", String.class);
        method1.invoke(p, "fish");

        Method[] method2 = cls.getMethods();
        for(Method m: method2){
            // m.setAccessible(true);
            String name = m.getName();
            System.out.println(m);
        }

    }
}

你可能感兴趣的:(反射)