java反射机制

认识反射机制:

我们正常的关于对象的处理流程:根据包名.类名找到类.

所谓的"反"指的是根据对象来取得对象的来源信息,而这个"反"的操作核心的处理理就在于Object类的一 个方法:

public final native Class<?> getClass(); 

该方法返回的是⼀一个Class类对象,这个Class描述的就是类.

public class Test {//getclass()
    public static void main(String[] args) {
        StringBuffer stringBuffer=new StringBuffer();
        System.out.println(stringBuffer.getClass());
    }
}

运行结果: class java.lang.StringBuffer
此时通过对象取得了了对象的来源,这就是"反"的本质。
在反射的世界里面,看重的不不再是⼀一个对象,⽽而是对象身后的组成(类、构造、普通、成员等);

1.三种实例化对象

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

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

import java.util.Scanner;

public class Test {//getclass()
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> cla=Class.forName("java.util.Scanner");
        System.out.println(cla.getName());
        Scanner scanner=new Scanner(System.in);
        System.out.println(scanner.getClass());
        System.out.println(Scanner.class);
    }
}

运行结果:
java.util.Scanner
class java.util.Scanner
class java.util.Scanner

在以上给出的三个方法中我们可以发现,除了第一种方法会产生Scanner类的实例化对象之外,其他的两种 都不会产生Scanner类的实例化对象。于是取得了Class类对象有一个最直接的好处:可以通过反射实例化对 象,在Class类中定义有如下方法:

public T newInstance()        throws InstantiationException, IllegalAccessException 
import java.util.Scanner;

public class Test {//getclass()
    public static void main(String[] args) throws ClassNotFoundException,IllegalAccessException,InstantiationException {
        Class<?> cla=Class.forName("java.util.Date");
            Object object=cla.newInstance();//实例化等价于 new Date();
        System.out.println(object);
    }
}

运行结果:Sun Aug 02 12:28:51 CST 2020

现在发现除了关键字new之外,对于对象的实例化模式有了第⼆二种做法,通过反射进行。
取得了Class对象就意味着取得了一个指定类的操作权 .

2.反射与类操作
取得父类信息

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

import java.util.Date;

public class Test1 {
    public static void main(String[] args) {
        Class<?> cla= Date.class;
        System.out.println(cla.getPackage().getName());
    }
}

运行结果:java.util.

2.获得父类与实现父类的接口

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

import java.sql.SQLOutput;
import java.util.ArrayList;

public class Test1 {
    public static void main(String[] args) {
        Class<?> cla= ArrayList.class;
        System.out.println(cla.getSuperclass().getName());//获得父类名称
        System.out.println("+++++++++++++++++");
        Class<?>[] classes=cla.getInterfaces();//取得实现父类接口对象
        for (Class<?> s:classes){
            System.out.println(s.getName());
        }
    }
}

运行结果:
在这里插入图片描述

3.反射调用构造

一个类中可以存在多个构造方法,如果要想取得类中构造的调用,就可以使用Class类中提供的两个方法:

取得指定参数类型的构造:
public Constructor<T> getConstructor(Class<?>... parameterTypes)        throws NoSuchMethodException, SecurityException
取得类中的所有构造:
public Constructor<?>[] getConstructors() throws SecurityException
import java.lang.reflect.Constructor;
class Person {
    public Person() {}
    public Person(String name) {}
    public Person(String name,int age) {}
}
public class Test3 {
    public static void main(String[] args) {
        Class<?> cls = Person.class ;
        // 取得类中的全部构造
        Constructor<?>[] constructors = cls.getConstructors() ;
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
    }
}

运行结果:
public Person()
public Person(java.lang.String)
public Person(java.lang.String,int)

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

class preson{
    private int age;
    private String name;
    public preson(String name,int age){
        this.age=age;
        this.name=name;
    }

    @Override
    public String toString() {
        return "preson{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
public class Test4{
    public static void main(String[] args) throws InstantiationException,
            IllegalAccessException, SecurityException,
            IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
        Class<?> cla=preson.class;
//        System.out.println(cla.newInstance());
//        Class类通过反射实例例化类对象的时候,只能够调用类中的无参构造。如果现在类中没有无参构造则无
//    法使用Class类调用,只能够通过明确的构造调用实例例化处理理。

        //通过Constructor类实例例化对象
        Constructor<?> constructor=cla.getConstructor(String.class,int.class);
        System.out.println(constructor.newInstance("小明",23));

    }

}

运行结果:preson{age=23, name=‘小明’}

4.调用普通方法

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

取得全部普通⽅方法:
public Method[] getMethods() throws SecurityException
取得指定普通⽅方法:
public Method getMethod(String name, Class<?>... parameterTypes)

import java.lang.reflect.Method;
import java.util.ArrayList;

public class Test5 {
    public static void main(String[] args) {
        Class<?> cla= ArrayList.class;
        Method[] methods=cla.getMethods();
        for(Method a:methods){
            System.out.println(a);
        }
    }
}

运行结果:
public void java.util.ArrayList.add(int,java.lang.Object)
public boolean java.util.ArrayList.add(java.lang.Object)
public boolean java.util.ArrayList.remove(java.lang.Object)
public java.lang.Object java.util.ArrayList.remove(int)
public java.lang.Object java.util.ArrayList.get(int)
public java.lang.Object java.util.ArrayList.clone()
public int java.util.ArrayList.indexOf(java.lang.Object)
public void java.util.ArrayList.clear()…所有的ArrayList方法.

之前程序编写的都是明确的对象调用。
而现在有了反射机制处理之后,即使你没有明确的Person类型对象(依然需要实例化对象,Object对象 描述,所有的普通方法必须在有实例化对象之后才可以进行调用)。就可以通过反射调用。

import java.lang.reflect.Method;
class Person2 {
    private String name ;
    private int age ;
    public Person2() {}
    public Person2(String name,int age) {
        this.name = name ;
        this.age = age ;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public class Test6 {
    public static void main(String[] args) throws
            Exception {
        Class<?> cls = Class.forName("Person2");

        // 任何时候调⽤用类中的普通⽅方法都必须有实例例化对象
        Object obj = cls.newInstance() ;
        // 取得setName这个⽅方法的实例例化对象,设置⽅方法名称与参数类型
        Method setMethod = cls.getMethod("setName", String.class) ;
        // 随后需要通过Method类对象调⽤用指定的⽅方法,调⽤用⽅方法需要有实例例化对象
        // 同时传⼊入参数
        setMethod.invoke(obj, "yuisama") ;// 相当于Person对 象.setName("yuisama") ;
        Method getMethod = cls.getMethod("getName") ;
        Object result  = getMethod.invoke(obj) ;  // 相当于Person对 象.getName() ;
        System.out.println(result) ;
    }
}

此类操作的好处是:不再局限于某⼀一具体类型的对象,而是可以通过Object类型进行所有类的方法调用

5.调用属性

类中的所有属性⼀一定在类对象实例化之后才会进行空间分配,所以此时如果要想调用类的属性,必 须保证有实例化对象。通过反射的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

import java.lang.reflect.Field;
class Person2 {
    private String name ;
    private int age ;
    public Person2() {}
    public Person2(String name,int age) {
        this.name = name ;
        this.age = age ;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public class Test6 {
    public static void main(String[] args) throws
            Exception {
        Class<?> cls = Class.forName("Person2");
        Field[] field = cls.getFields();//第一种
            for (Field a : field) {
                System.out.println(a);
            }
        System.out.println("--------------------------");

        Field[] fields=cls.getDeclaredFields();//第二种
        for(Field a:fields){
            System.out.println(a);
        }
    }
}

设置属性:

  1. 设置属性内容 : public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException
  2. 取得属性内容 : public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException
import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Person2 {
    private String name ;
    private int age ;
    public Person2() {}
    public Person2(String name,int age) {
        this.name = name ;
        this.age = age ;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public class Test6 {
    public static void main(String[] args) throws
            Exception {
        Class<?> cls = Class.forName("Person2");
        // 实例例化本类对象  
        Object obj = cls.newInstance() ;   
        // 操作name属性  
        Field nameField = cls.getDeclaredField("name");
        nameField.set(obj, "yuisama") ; 
        // 相当于对象.name = "yuisama" 
        System.out.println(nameField.get(obj)); // 取得属性
        }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值