Java学习:初识反射

首先我们来了解一下Java的反射机制:在运行状态下,我们能够知道一个类有哪些属性和方法,对于一个对象来说我们能够调用他的属性和方法,这种获取一个类的信息和调用一个对象的属性和方法就是Java的反射机制,我们要解刨一个类,就必须先得到他的字节码对象,通过使用class类的方法才能对这个类进行剖析,所以我们要先获得每一个字节码文件对应的class类型的对象。
获得class对象有三种方法:
1.通过object的getclass()方法

public class MyDemo {
    public static void main(String[] args) {
        Student student = new Student();
        Class<? extends Student> aClass = student.getClass();
        System.out.println(aClass);
    }
}

编译运行可得到

class org.jimmy.demo5.Student

2.通过class静态属性,每个类都有自己的一个class属性

public class MyDemo2 {
    public static void main(String[] args) {
        Class<Student> aClass = Student.class;
        System.out.println(aClass);
    }
}

同样的编译运行可得到

class org.jimmy.demo5.Student

3.通过class的静态forname()方法,通过一个类的全路径,就可以获得该类的字节码对象

public class MyDemo3 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> aClass = Class.forName("org.jimmy.demo5.Student");
        System.out.println(aClass);
    }
}

一个类的全路径:就是这个类带包名的写法,编译运行得到:


class org.jimmy.demo5.Student

在了解的上述内容后,我们可以试着通过反射来获取一个类的构造器
一个类的构造方法,可以是有参的无参的,可以是公有的也可以是私有的,所以获取不同的构造方法也是不一样的。
1.getConstructors()方法和getDeclaredConstructors()方法
这两个方法可以获得一个类的构造方法,但前者获得的构造方法不是私有的,后者是获取所有包含私有的构造方法,我们新建一个student类,里面包含了私有和公有的构造方法,以及无参和有参的构造方法。

public class Student {
    public Student() {
        System.out.println("该类的无参构造方法");
    }
    public Student(String name,int age){
        System.out.println("该类的有参构造方法");
    }
    private Student(String name){
        System.out.println("该类的私有构造方法");

    }
}

那么获取该类的构造方法

public class MyDemo4 {
    public static void main(String[] args) {
        Class<Student> aClass = Student.class;
        Constructor<?>[] constructors = aClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("-----------------------------------");
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
    }
}

编译运行得到:

public org.jimmy.demo5.Student()
public org.jimmy.demo5.Student(java.lang.String,int)
-----------------------------------
public org.jimmy.demo5.Student()
public org.jimmy.demo5.Student(java.lang.String,int)
private org.jimmy.demo5.Student(java.lang.String)

我们也可以获取单个的构造方法
利用getConstructor()或者 getConstructor(Class<?>… parameterTypes)
后者是获取带参数的构造方法
parameterTypes就是指该参数的class类型
同样的getDeclaredConstructor()方法就是获得私有的构造方法,

public class MyDemo5 {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<Student> aClass = Student.class;
        Constructor<Student> constructor = aClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
    }
}
public org.jimmy.demo5.Student(java.lang.String,int)

这就是如何获得一个类的构造方法。
而创建一个类的实例化对象,就需要调用该类的构造方法,因此,通过刚才获得的构造方法,我们就可以创建该类的实例化对象。
通过调用newInstance()方法类创建实例化对象

public class MyDemo6 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Student> aClass = Student.class;
        Constructor<Student> constructor = aClass.getConstructor();
        Student student = constructor.newInstance();
    }
}

通过该类的无参构造方法来获取一个实例对象

该类的无参构造方法

在这里,私有的构造方法来创建对象就需要注意了,因为该构造方法是私有的,外界是不能访问的,因此我们要先取消语法检测,setAccessible(type)方法可以取消语法检测,里面的参数为布尔值,为true即为取消语法检测,我们来用代码体会一下:

public class MyDemo6 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Student> aClass = Student.class;
        Constructor<Student> declaredConstructor = aClass.getDeclaredConstructor(String.class);
        declaredConstructor.setAccessible(true);
        declaredConstructor.newInstance("小明");
    }
}
该类的私有构造方法

获取了构造方法,创建了该对象,我们来尝试获取变量和设置变量,首先设置student类的变量

public class Student {
    private String name;
    int age;
    public  String sex;
}

接下来获取变量和设置变量

public class MyDemo3 {
    public static void main(String[] args) throws Exception {
        Class<Student> aClass = Student.class;
        Field sex = aClass.getField("sex");
        Student student = aClass.newInstance();
        sex.set(student,"男");//给哪个对象设,第一个参数就是该对象
        Object o = sex.get(student);//通过字段对象来获取字段的值
        System.out.println(o);
    }
}

同样的,获取私有的变量也有getDeclaredField()方法,同样的,在设置变量的时候,我们也要取消语法检测。这里不做代码展示。

获取完变量,我们自然要来试一下获取方法,这和前面两个又是同样的套路;
getMethods()
getDeclaredMethods()
getDeclaredMethod()
getMethod()
获取单个的方法时,括号里面的参数为该方法名,如果该方法有参数,后面为该参数的class类型
那么如何调用该方法呢?
Object invoke (Object obj, Object…args),invoke方法,就可以实现,
如果实现的方法没有参数,invoke方法括号里面即为该对象名,如果有参数,后面紧跟该参数的class类型。我们来用代码来体会。
学生类:

public class Student {
    public void show() {
        System.out.println("我是一个无参数的公共方法");
    }

    public String show2() {
        System.out.println("我是一个无参数的公共方法,有返回值");
        return "一个字符串";
    }

    public void test(String name) {
        System.out.println("我是一个有参数的公共方法" + name);
    }

    private void myMethod(String name, int age) {
        System.out.println("我是一个有参数的私有方法" + name + "==" + age);
    }
}
public class MyDemo {
    public static void main(String[] args) throws Exception{
        Class<?> aClass = Class.forName("org.jimmy.demo4.Student");
        Object obj = aClass.newInstance();
        Method method = aClass.getMethod("show");
        method.invoke(obj);
        Method show2 = aClass.getMethod("show2");
        Object invoke = show2.invoke(obj);//该方法有返回值,invoke方法返回的就是返回值
        System.out.println(invoke);
        Method test = aClass.getMethod("test", String.class);
        Object show = test.invoke(obj, "测试");
        Method declaredMethod = aClass.getDeclaredMethod("myMethod",String.class, int.class);
        declaredMethod.setAccessible(true);//取消语法检测
        declaredMethod.invoke(obj, "小明", 20);
    }
}

编译运行可得到:

我是一个无参数的公共方法
我是一个无参数的公共方法,有返回值
一个字符串
我是一个有参数的公共方法测试
我是一个有参数的私有方法小明==20
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值