Java打怪之路----Java高级之反射

(一)Java反射机制概述

1.1理解

正常情况下我们是创建一个Person类,之后通过New实例化,最后取得实例化对象。
反射是通过实例化对象,调用getClass(),得到最终的类信息
在这里插入图片描述

1.2反射可以做什么

    //反射之前,对于Person的操作
    @Test
    public void test1() {
    
    

        //1.创建Person类的对象
        Person p1 = new Person("Tom", 12);

        //2.通过对象,调用其内部的属性、方法
        p1.age = 10;
        System.out.println(p1.toString());

        p1.show();

        //在Person类外部,不可以通过Person类的对象调用其内部私有结构。
        //比如:name、showNation()以及私有的构造器
    }

    //反射之后,对于Person的操作
    @Test
    public void test2() throws Exception{
    
    
        Class clazz = Person.class;
        //1.通过反射,创建Person类的对象
        Constructor cons = clazz.getConstructor(String.class,int.class);
        Object obj = cons.newInstance("Tom", 12);
        Person p = (Person) obj;
        System.out.println(p.toString());
        //2.通过反射,调用对象指定的属性、方法
        //调用属性
        Field age = clazz.getDeclaredField("age");
        age.set(p,10);
        System.out.println(p.toString());

        //调用方法
        Method show = clazz.getDeclaredMethod("show");
        show.invoke(p);

        System.out.println("*******************************");

        //通过反射,可以调用Person类的私有结构的。比如:私有的构造器、方法、属性
        //调用私有的构造器
        Constructor cons1 = clazz.getDeclaredConstructor(String.class);
        cons1.setAccessible(true);
        Person p1 = (Person) cons1.newInstance("Jerry");
        System.out.println(p1);

        //调用私有的属性
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(p1,"HanMeimei");
        System.out.println(p1);

        //调用私有的方法
        Method showNation = clazz.getDeclaredMethod("showNation", String.class);
        showNation.setAccessible(true);
        String nation = (String) showNation.invoke(p1,"中国");//相当于String nation = p1.showNation("中国")
        System.out.println(nation);
    }

(二)Class类和获取Class类的实例

2.1类的加载过程

程序经过Javac.exe之后,会生成一个或者多个字节码文件(.class)。接着我们通过java.exe对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。这个过程就叫类的加载(这个文件中包含一个个的类)。
加载到内存中的类,成为运行时类。这个运行时类就是Class的一个实例。

通俗点来讲,Class类是其他类的类,我们可以创建Person类,Animals类,这些类其实也是一个对象,他们共同的类就是Class类

2.2获取Class实例的三种方式

package com.sgyj.java;

import org.junit.Test;

public class ReflectionTest {
    
    
    @Test
    public void test1() throws ClassNotFoundException {
    
    
        //获取class实例的三种方式
        //1、通过运行时类的属性.class
        Class aClass=Person.class;

        //2、通过运行时类的对象,调用getClass()
        Person p1=new Person("ni",23);
        Class clazz=p1.getClass();

        //3、通过调用class的静态方法:forName(String,classPath)
        Class clazz2=Class.forName("com.sgyj.java.Person");

        //4、使用类的加载器
        ClassLoader classLoader=ReflectionTest.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("com.sgyj.java.Person");
    }

}

注意:这四种方式获取到的Class的对象其”==“都为true,都指向同一个Person类。

2.3类加载器

(三)创建运行时对象

Why:获取到Class类对象之后,我们要创建相应的实例:例如Person是Class类的对象,获取到相应的class,我们要创建Person类实例。

How:newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器

要想此方法正常的创建运行时类的对象,要求:
1.运行时类必须提供空参的构造器
2.空参的构造器的访问权限得够。通常,设置为public。

在javabean中要求提供一个public的空参构造器。原因:
1.便于通过反射,创建运行时类的对象
2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器`

    public void test2() throws IllegalAccessException, InstantiationException {
    
    
        //通过反射创建运行时类的对象
        Class<Person> clazz=Person.class;
        Person obj=clazz.newInstance();
    }

(四)获取当前运行时类的属性、方法等结构

4.1获取运行时类的访问权限、数据类型、变量名

public class FieldTest {
    
    

    @Test
    public void test1(){
    
    

        Class clazz = Person.class;

        //获取属性结构
        //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
        Field[] fields = clazz.getFields();
        for(Field f : fields){
    
    
            System.out.println(f);
        }
        System.out.println();

        //getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f : declaredFields){
    
    
            System.out.println(f);
        }
    }

    //权限修饰符  数据类型 变量名
    @Test
    public void test2(){
    
    
        Class clazz = Person.class;
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f : declaredFields){
    
    
            //1.权限修饰符
            int modifier = f.getModifiers();
            System.out.print(Modifier.toString(modifier) + "\t");

            //2.数据类型
            Class type = f.getType();
            System.out.print(type.getName() + "\t");

            //3.变量名
            String fName = f.getName();
            System.out.print(fName);

            System.out.println();
        }
    }
}

4.2获取运行时类中声明的方法、方法注解、权限修饰符、返回值类型、方法名、形参列表和抛出的异常

package com.atguigu.java2;

import com.atguigu.java1.Person;
import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 获取运行时类的方法结构
 *
 * @author shkstart
 * @create 2019 下午 3:37
 */
public class MethodTest {
    
    

    @Test
    public void test1(){
    
    

        Class clazz = Person.class;

        //getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
        Method[] methods = clazz.getMethods();
        for(Method m : methods){
    
    
            System.out.println(m);
        }
        System.out.println();
        //getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for(Method m : declaredMethods){
    
    
            System.out.println(m);
        }
    }

    /*
    @Xxxx
    权限修饰符  返回值类型  方法名(参数类型1 形参名1,...) throws XxxException{}
     */
    @Test
    public void test2(){
    
    
        Class clazz = Person.class;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for(Method m : declaredMethods){
    
    
            //1.获取方法声明的注解
            Annotation[] annos = m.getAnnotations();
            for(Annotation a : annos){
    
    
                System.out.println(a);
            }

            //2.权限修饰符
            System.out.print(Modifier.toString(m.getModifiers()) + "\t");

            //3.返回值类型
            System.out.print(m.getReturnType().getName() + "\t");

            //4.方法名
            System.out.print(m.getName());
            System.out.print("(");
            //5.形参列表
            Class[] parameterTypes = m.getParameterTypes();
            if(!(parameterTypes == null && parameterTypes.length == 0)){
    
    
                for(int i = 0;i < parameterTypes.length;i++){
    
    

                    if(i == parameterTypes.length - 1){
    
    
                        System.out.print(parameterTypes[i].getName() + " args_" + i);
                        break;
                    }

                    System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
                }
            }

            System.out.print(")");

            //6.抛出的异常
            Class[] exceptionTypes = m.getExceptionTypes();
            if(exceptionTypes.length > 0){
    
    
                System.out.print("throws ");
                for(int i = 0;i < exceptionTypes.length;i++){
    
    
                    if(i == exceptionTypes.length - 1){
    
    
                        System.out.print(exceptionTypes[i].getName());
                        break;
                    }

                    System.out.print(exceptionTypes[i].getName() + ",");
                }
            }
            System.out.println();
        }
    }
}

4.3获取运行时类的构造器、父类、带范型的父类、接口和所在的包

package com.atguigu.java2;

import com.atguigu.java1.Person;
import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * @author shkstart
 * @create 2019 下午 4:19
 */
public class OtherTest {
    
    

    /*
    获取构造器结构

     */
    @Test
    public void test1(){
    
    

        Class clazz = Person.class;
        //getConstructors():获取当前运行时类中声明为public的构造器
        Constructor[] constructors = clazz.getConstructors();
        for(Constructor c : constructors){
    
    
            System.out.println(c);
        }

        System.out.println();
        //getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for(Constructor c : declaredConstructors){
    
    
            System.out.println(c);
        }

    }

    /*
    获取运行时类的父类

     */
    @Test
    public void test2(){
    
    
        Class clazz = Person.class;

        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
    }

    /*
    获取运行时类的带泛型的父类

     */
    @Test
    public void test3(){
    
    
        Class clazz = Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
    }

    /*
    获取运行时类的带泛型的父类的泛型


    代码:逻辑性代码  vs 功能性代码
     */
    @Test
    public void test4(){
    
    
        Class clazz = Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) genericSuperclass;
        //获取泛型类型
        Type[] actualTypeArguments = paramType.getActualTypeArguments();
//        System.out.println(actualTypeArguments[0].getTypeName());
        System.out.println(((Class)actualTypeArguments[0]).getName());
    }

    /*
    获取运行时类实现的接口
     */
    @Test
    public void test5(){
    
    
        Class clazz = Person.class;

        Class[] interfaces = clazz.getInterfaces();
        for(Class c : interfaces){
    
    
            System.out.println(c);
        }

        System.out.println();
        //获取运行时类的父类实现的接口
        Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
        for(Class c : interfaces1){
    
    
            System.out.println(c);
        }

    }
    /*
        获取运行时类所在的包

     */
    @Test
    public void test6(){
    
    
        Class clazz = Person.class;

        Package pack = clazz.getPackage();
        System.out.println(pack);
    }

    /*
        获取运行时类声明的注解

     */
    @Test
    public void test7(){
    
    
        Class clazz = Person.class;

        Annotation[] annotations = clazz.getAnnotations();
        for(Annotation annos : annotations){
    
    
            System.out.println(annos);
        }
    }
}

(五)思维导图总结

请添加图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44020747/article/details/121221596