Java反射粗谈

反射的概述:

JAVA反射机制是在运行时将任何一个类的内部信息暴露出来,例如这个类的所有属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

  反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!

使用方法:

java.lang.Class:是反射的源头
通过运行时类的对象,调用其getClass方法,返回其运行时类
正常的顺序时通过类构建对象,反射是通过对象找到其所对应的类,进而调用这个类

创建的Persion类:包含注解、集成、接口、私有属性、私有方法等。

package D19;

/**
 * @Author: wj
 * @Date: 2018/11/25 8:35
 * @Version 1.0
 */

@MyAnnotation(value = "annotation")
public class Persion extends Creature<String> implements Comparable,MyInterface{
    public  String name;
    private  int age;

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

    public Persion() {
    }

    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;
    }


    @MyAnnotation(value = "123")
    public void show(){
        System.out.println("我是一个人");
    }


    private void display(String nation){
        System.out.println("我的国籍是:"     +nation);
    }


    public static void info(){
        System.out.println("中国人");
    }

    @Override
    public String toString() {
        return "Persion{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public int compareTo(Object o) {
        return 0;
    }
}

 

 

 

 

 1.

一.获取Class的四种方法:

1. 调用运行时类本身

Class clazz1 = Persion.Class;

System.out.print(clazz1.getName());

2. 通过运行时类的对象创建

Persion persion = new Persion();

Class clazz2 = persion.getClass();

System.out.print(clazz2.getName());

3.通过运行时类的全类名路径

Class clazz3 = Class.forName("D19.Persion");

System.out.print(clazz3.getName());

4.通过类加载器

ClassLoader  classLoader = this.getClass().getClassLoader();

Class clazz4 = classLoader.loadClass("D13.Persion");

System.out.print("clazz4.getName()");

二.Class 的运用

1.获取运行时类的属性:

属性的权限有别,有public、private、protected,不同权限的属性获取方法不同

下面提供两种方法:

  //获取运行时类的属性
    @Test
    public void test1(){
        Class clazz = Persion.class;
        //getFields 只能获取到运行时类及其父类中权限为public的
        Field[] fields = clazz.getFields();


        //getDeclaredFields只能获取到运行时类本身声明的所有属性,包括private
        Field[] fields2 = clazz.getDeclaredFields();
        for(int i =0 ; i<fields2.length;i++){
            System.out.println(fields2[i].getName());
        }
    }

2.各个属性的特征,包括权限修饰符、类型、变量名都可通过Class获取

  //属性有 权限修饰符  类型  变量名
    //获取属性各个部分的内容
    @Test
    public void test2(){
    //getDeclaredFields只能获取到运行时类本身声明的所有属性
        Class clazz = Persion.class;
        Field[] fields2 = clazz.getDeclaredFields();
        for(Field f:fields2){
            //1.获取每个属性的权限修饰符
            int i = f.getModifiers();
            String str1 = Modifier.toString(i);
            System.out.println(str1);

            //2.获取每个属性的变量类型
            Class type = f.getType();
            System.out.println(type.getName());

            //3.获取每个属性的变量名
            System.out.print(f.getName());
            System.out.println();
        }
    }

3.获取运行时类中的各种方法,同属性一样,不同权限的方法获取形式不同

与属性类似,获取方法也分为两种

    @Test
    public void test3(){
        Class clazz = Persion.class;
        //1.获取运行时类及其父类包括Object中所有的声明为Public的方法
        Method[] methods = clazz.getMethods();
        for(Method m :methods){
            System.out.println(m);
        }

        //2.获取运行时类自身的方法不包括父类的,其中也包含权限为private的
        methods = clazz.getDeclaredMethods();
        for(Method m :methods){
            System.out.println(m);
        }

    }

4.方法其他特征的获取,包括注解、权限修饰符、返回值类型、方法名、形参列表、抛出的异常等

以下通过Method[] methods = clazz.getMethods();获取

 //注解,权限修饰符,返回值类型,方法名,形参列表,抛出的异常
    @Test
    public void test4(){
        Class clazz =Persion.class;
        Method[] methods = clazz.getDeclaredMethods();
        for(Method m :methods){
            //1.获取注解
           Annotation[] ann = m.getAnnotations();
            System.out.print(ann);

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

            //3.返回值类型
            Class returnType = m.getReturnType();
            System.out.print(returnType.getName()+" ");

            //4.方法名
            System.out.print(m.getName()+" ");

            //5.形参列表
            System.out.print("(");
            Class[] params = m.getParameterTypes();
            for(Class p:params){
                System.out.print(p.getName());
            }
            System.out.print(")");

            //6.异常类型

            Class[] exceptions = m.getExceptionTypes();
            if(exceptions.length!=0){
                System.out.println("throws ");
            }
            for(Class e:exceptions){
                System.out.print(e.getName());
            }

            System.out.println();
        }
    }

5.类的泛型获取(JDBC常用)

   //获取父类泛型(JDBC用到)
    @Test
    public void test5() throws ClassNotFoundException {
        Class clazz = Class.forName("D19.Persion");
        //获取带泛型的父类
        Type type = clazz.getGenericSuperclass();
        ParameterizedType param = (ParameterizedType) type;
        Type[] args = param.getActualTypeArguments();
        System.out.println(((Class)args[0]).getName());
    }

6.获取实现接口


    //获取实现的接口
    @Test
    public void test6(){
        Class clazz = Persion.class;
        Class[] interfaces = clazz.getInterfaces();
        for(Class i:interfaces){
            System.out.println(i.getName());
        }
    }

7.通过Class创建对象,并为属性赋值,以及调用各类方法

1)通过无参构造器创建

   //使用反射创建对象,调用其中的方法(运行时类)
    @Test
    public void testReflection() throws Exception{
        Class<Persion> clazz = Persion.class;
        //1.创建clazz对应的运行时类(Persion)的对象
        Persion p =  clazz.newInstance();//必须有无参的构造方法
        System.out.println(p);
        //2.调用属性
        Field field1 = clazz.getField("name");//public属性
        //私有属性调用
        Field field2 =clazz.getDeclaredField("age");
        field2.setAccessible(true);//关键
        field1.set(p,"L");
        field2.set(p,22);
        System.out.println(p);

        //3.使用反射调用类的方法
        Method method1 = clazz.getMethod("show");//public方法
        method1.invoke(p);

        //带参数的以及私有的(private)方法
        Method method2 = clazz.getDeclaredMethod("display", String.class);
        method2.setAccessible(true);//关键
        //为参数赋值(注意invoke可变参数)
        method2.invoke(p,"China");


        //带返回值的
        Method method3 = clazz.getMethod("toString");
        Object returnVal = method3.invoke(p);
        System.out.println(returnVal);

        //静态方法
        Method method4 = clazz.getMethod("info");
        method4.invoke(p);
        //也可以不用太对象
        method4.invoke(Persion.class);
    }

2)调用指定构造器


    //调用指定构造器
    @Test
    public void test8() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        String className = "D19.Persion";
        Class clazz = Class.forName(className);
        Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
        cons.setAccessible(true);
        Persion p = (Persion) cons.newInstance("bxklx",20);
        System.out.println(p);
    }

8.通过ClassLoder读取配置文件

配置文件:

user=root;
password=123

读取方法:

 ClassLoader classLoader = this.getClass().getClassLoader();
        InputStream is =  classLoader.getResourceAsStream("Jdbc.properties");
        Properties properties = new Properties();
        properties.load(is);
        String user =  properties.getProperty("user");
        System.out.println(user);

结果:

以上就是我学习JAVA反射时用到的方法,对于反射用到的地方特别多,尤其是阅读框架源码时候,此外在通过Sql查询数据库获得对象时,也可通过反射构建实体对象,并未对象赋值。



 

猜你喜欢

转载自blog.csdn.net/weixin_38520617/article/details/84585625
今日推荐