ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

了解JAVA反射

2021-12-18 20:00:52  阅读:122  来源: 互联网

标签:lang 反射 JAVA String java reflect 了解 org public


了解JAVA反射

1.什么是反射

谈到反射,大家可能想到的是有反射是不是就有正射呢?是的,正如有阴有阳,那我们首先来了解了解什么是正射,当我们想调用一个类中的某个普通方法时,那我们首先想到的是啥?我觉得大部分人都应该能想到,new 一个对象出来,然后调用方法,这就是JAVA中所谓的正射,代码如下

public class Student {
    public void show(){
        System.out.println("show show ");
    }
}


public class Test {
    public static void main(String[] args) {
    //通过new的方式来实例化对象
        Student student = new Student();
        student.show();
    }
}

接下来,我们再来讲讲反射是什么,在程序运行状态下,对于任意类,都能知道类的属性和方法,对于任意一个对象,都能调用它的方法和属性,这种动态获得类的信息以及动态调用对象的方法的功能称之为反射,不过反射有一个前提时必须拿到该对象的字节码(一个类只有一份字节码)。

public class Test {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //获取Student类的Class对象
        Class<?> student = Class.forName("org.reflect.Student");
        //实例化对象
        Student instance = (Student)student.newInstance();
        instance.show();
    }
}

如何获取类的字节码

上面也说了,反射的前提就是获得该对象的字节码

public class Test {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //1,Class类的forName方法
        Class<?> student = Class.forName("org.reflect.Student");

        //2,我个人感觉略显鸡肋,都拿到对象了,才去获取字节码
        Student student1=new Student();
        Class<? extends Student> student1Class = student1.getClass();

        //3,通过class 属性
        Class<Student> studentClass = Student.class;


        //上面我说过,一个类只有一份字节码,接下来我们对通过三种方式拿到的Class 对象进行比较,看看是否相同

        System.out.println(student.equals(student1Class));
        System.out.println(student.equals(studentClass));

    }
}


true
true

从而也符合了我上边说的话,一个类只有一份字节码文件

如何实例化对象


package org.reflect;

public class Student {

    private String name;

    private Double height;

    public Student() {
    }

    public Student(String name, Double height) {
        this.name = name;
        this.height = height;
    }
    //隐藏setter getter
    public void show(){
        System.out.println("姓名为"+name+"\t\t\t"+"身高为"+height);
    }
}




package org.reflect;

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

public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        //首先我们必须要获取到类的Class
        Class<?> studentClass = Class.forName("org.reflect.Student");

        //1.getConstructor(Class<?>... parameterTypes)  获取公有
        //返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法
        //大家可以看到参数是一个可变长的参数,当我们需要获取无参构造时,不需要输入参数,如果需要指定的构造方法,则输入对应的Class对象

        //获取无参构造
        Constructor<?> constructor = studentClass.getConstructor();
        System.out.println(constructor);  //输出结果为public org.reflect.Student()
        Student student =(Student) constructor.newInstance();
        student.show();  // 姓名为null			身高为null

        //获取有参构造(切记,此方法只能获取构造方法为公有的方法)
        Constructor<?> studentClassConstructor = studentClass.getConstructor(String.class, Double.class);
        System.out.println(studentClassConstructor); //public org.reflect.Student(java.lang.String,java.lang.Double)
        Student student1 = (Student) studentClassConstructor.newInstance("BestLee", 175.0);
        student1.show();//姓名为BestLee	身高为175.0


        //getConstructors(),返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
        //一定要看到上面的重点,返回所有公共构造
        Constructor<?>[] constructors = studentClass.getConstructors();
        for (int i = 0; i < constructors.length; i++) {
            System.out.println(constructors[i]);
            //输出结果为
            //public org.reflect.Student()
            //public org.reflect.Student(java.lang.String,java.lang.Double)
        }

        //getDeclaredConstructor(Class<?>... parameterTypes),返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
        //大家看API的时候一定底仔细看,返回指定的构造方法,那么就代表一切都可以(public,default,protected,private)
        Constructor<?> classConstructor = studentClass.getDeclaredConstructor(String.class);
        System.out.println(classConstructor); //private org.reflect.Student(java.lang.String)
        classConstructor.setAccessible(true); // 暴力访问(忽略修饰符)
        Student student2 = (Student) classConstructor.newInstance("BestY");
        student2.show();


        //getDeclaredConstructors() 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。
        //获取Class所代表对象的所有构造
        Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();
        for (int i = 0; i < declaredConstructors.length; i++) {
            System.out.println(declaredConstructors[i]);
            //输出结果为
            //private org.reflect.Student(java.lang.String)
            //public org.reflect.Student(java.lang.String,java.lang.Double)
            //public org.reflect.Student()
        }


        //newInstance() ,创建此 Class 对象所表示的类的一个新实例。
        Student student3 = (Student)studentClass.newInstance();
        student3.show();
    }
}


//输出结果

public org.reflect.Student()
姓名为null			身高为null
public org.reflect.Student(java.lang.String,java.lang.Double)
姓名为BestLee			身高为175.0
public org.reflect.Student(java.lang.String,java.lang.Double)
public org.reflect.Student()
private org.reflect.Student(java.lang.String)
姓名为BestY			身高为null
private org.reflect.Student(java.lang.String)
public org.reflect.Student(java.lang.String,java.lang.Double)
public org.reflect.Student()
姓名为null			身高为null

Process finished with exit code 0


获取成员变量

package org.reflect;

public class People {
    private String name;
    public String height;
    protected String weight;
    String age;
}



package org.reflect;

public class Teacher extends People {
    public String tId;
    private String money;
    String workAge;
    protected String voice;
}



package org.reflect;

import java.lang.reflect.Field;

public class Test3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        //获取Class对象
        Class<?> teacherClass = Class.forName("org.reflect.Teacher");

        //getField(String name)
        //返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
        Field tId = teacherClass.getField("tId");
        System.out.println(tId);

        Field height = teacherClass.getField("height");
        System.out.println(height);

        //getFields()
        //返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
        Field[] fields = teacherClass.getFields();
        for (int i = 0; i < fields.length; i++) {
            System.out.println(fields[i]);
            //输出结果为
            //public java.lang.String org.reflect.Teacher.tId
            //public java.lang.String org.reflect.People.height
            //由此我们的出来一个结论,此方法可以获取到当前类以及父类的公共字段
        }


        //getDeclaredField(String name)
        //返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
        Field money = teacherClass.getDeclaredField("money");
        System.out.println(money); //private java.lang.String org.reflect.Teacher.money
        Field tId1 = teacherClass.getDeclaredField("tId");
        System.out.println(tId1); //public java.lang.String org.reflect.Teacher.tId
        Field workAge = teacherClass.getDeclaredField("workAge");
        System.out.println(workAge); //java.lang.String org.reflect.Teacher.workAge
        Field voice = teacherClass.getDeclaredField("voice");
        System.out.println(voice); //protected java.lang.String org.reflect.Teacher.voice

        
        //getDeclaredFields()
        // 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段
        Field[] declaredFields = teacherClass.getDeclaredFields();
        for (int i = 0; i < declaredFields.length; i++) {
            System.out.println(declaredFields[i]);
            //public java.lang.String org.reflect.Teacher.tId
            //private java.lang.String org.reflect.Teacher.money
            //java.lang.String org.reflect.Teacher.workAge
            //protected java.lang.String org.reflect.Teacher.voice
        }
    }
}


//输出结果
public java.lang.String org.reflect.Teacher.tId
public java.lang.String org.reflect.People.height
public java.lang.String org.reflect.Teacher.tId
public java.lang.String org.reflect.People.height
private java.lang.String org.reflect.Teacher.money
public java.lang.String org.reflect.Teacher.tId
java.lang.String org.reflect.Teacher.workAge
protected java.lang.String org.reflect.Teacher.voice
public java.lang.String org.reflect.Teacher.tId
private java.lang.String org.reflect.Teacher.money
java.lang.String org.reflect.Teacher.workAge
protected java.lang.String org.reflect.Teacher.voice

获取成员方法

package org.reflect;

public class Worker {

    public void work(){
        System.out.println("工作");
    }


    private void hh(){
        System.out.println("嘿嘿嘿..");
    }


    void eat(){
        System.out.println("吃饭喝水打豆豆");
    }

    protected void life(){
        System.out.println("生命是受到保护的");
    }
}



package org.reflect;

import java.lang.reflect.Method;

public class Test4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        //老样子,我们先来获取Worker的Class对象
        Class<?> workerClass = Class.forName("org.reflect.Worker");

        //getMethod(String name, Class<?>... parameterTypes)
        //返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
        //name为方法名称,后面的可变长参数为形参的类型,很多朋友好奇都有了方法名还要后面的干啥,这个时候你得想想某个关键词重载
        Method work = workerClass.getMethod("work");
        System.out.println(work); //public void org.reflect.Worker.work()


        //getMethods()
        //返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
        Method[] methods = workerClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            System.out.println(methods[i]);
            //public void org.reflect.Worker.work()
            //public final void java.lang.Object.wait() throws java.lang.InterruptedException
            //public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
            //public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
            //public boolean java.lang.Object.equals(java.lang.Object)
            //public java.lang.String java.lang.Object.toString()
            //public native int java.lang.Object.hashCode()
            //public final native java.lang.Class java.lang.Object.getClass()
            //public final native void java.lang.Object.notify()
            //public final native void java.lang.Object.notifyAll()
        }


        //getDeclaredMethod(String name, Class<?>... parameterTypes)
        Method work1 = workerClass.getDeclaredMethod("work");
        System.out.println(work1); //public void org.reflect.Worker.work()
        Method eat = workerClass.getDeclaredMethod("eat");
        System.out.println(eat);//void org.reflect.Worker.eat()
        Method life = workerClass.getDeclaredMethod("life");
        System.out.println(life); //void org.reflect.Worker.eat()
        Method hh = workerClass.getDeclaredMethod("hh");
        System.out.println(hh); //private void org.reflect.Worker.hh()
        
        //getDeclaredMethods()
        //返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

        Method[] declaredMethods = workerClass.getDeclaredMethods();
        for (int i = 0; i < declaredMethods.length; i++) {
            System.out.println(declaredMethods[i]);
            //protected void org.reflect.Worker.life()
            //public void org.reflect.Worker.work()
            //void org.reflect.Worker.eat()
            //private void org.reflect.Worker.hh()
        }
    }
}

反射执行方法以及为字段赋值

package org.reflect;

public class Man {

    private static String age;

    public static void main(String[] args) {

        System.out.println("年龄为:"+age);
        System.out.println("main方法执行了");
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
    }
}





package org.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test5  {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
        Class<?> aClass = Class.forName("org.reflect.Man");
        //实例化
        Man obj = (Man)aClass.newInstance();
        //获得main方法
        Method main = aClass.getMethod("main", String[].class);
        System.out.println(main);
        //反射获得字段并进行设置
        Field age = aClass.getDeclaredField("age");
        age.setAccessible(true);
        age.set(obj,"18");
        //反射执行方法


        String[] str={"1","2"};
        main.invoke(obj,(Object) str);
    }
}


//输出结果
public static void org.reflect.Man.main(java.lang.String[])
18
main方法执行了
1
2

反射越过泛型的检查

说起来泛型,大家会不会想到一句话,编译器有效,运行期擦除,说到运行期,大家会不会想到我上边说的呢,反射就是在运行期获取类的信息并进行操作的呢

package org.reflect;

import com.sun.org.apache.xpath.internal.operations.Bool;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test6 {
    public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //首先我来定义一个只能容纳Integer类型的集合
        List<Integer> integerList = new ArrayList<>();

        //然后我向这个集合中添加两个Integer类型的元素
        integerList.add(520);
        integerList.add(1314);

        //假设我现在想添加一个String类型的元素呢
        //编译器就会报错,因为我们上边做了类型约束
       // integerList.add("BestLee");

        //接下来就到了反射发挥用处的时候了
        //首先我们拿到该容器的Class对象
        Class<? extends List> integerListClass = integerList.getClass();

        //因为添加元素用到的是集合的add方法,所以我们得获取add方法
        Method add = integerListClass.getMethod("add",Object.class);


        //通过反射执行add方法
       add.invoke(integerList, "BestLee");
       
       //输出List
       System.out.println(integerList);
       
       //[520, 1314, BestLee]   
    }
}

标签:lang,反射,JAVA,String,java,reflect,了解,org,public
来源: https://blog.csdn.net/qq_48967079/article/details/122016202

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有