Java의 리플렉션 메커니즘은 Java의 특징 중 하나입니다. 리플렉션 메커니즘은 프레임워크 기술 구축의 기초입니다. 리플렉션을 사용하면 프로그램을 더 유연하게 만들고 코드에서 프로그램을 하드 코딩하는 것을 피할 수 있습니다. Java의 기본만 접한 많은 초보자에 비해 리플렉션은 여전히 매우 모호하고 어려운 개념입니다.
자바 리플렉션 메커니즘은 실행 상태에서 동적으로 정보를 획득하고 객체 메소드를 동적으로 호출하는 기능을 말합니다. Java 리플렉션에는 세 가지 동적 속성이 있습니다. 1. 런타임 시 객체 인스턴스 생성, 2. 런타임 중 호출 및 실행, 3. 런타임 시 속성 변경.
그럼 반성의 원리는 무엇일까요? 그러면 먼저 자바 프로그램의 실행 과정을 살펴봐야 합니다. 자바 프로그램을 실행하려면 자바 가상 머신이 자바 클래스를 로드해야 합니다. 프로그램을 실행할 때 필요한 클래스는 컴파일 중에 이미 로드되어 있습니다. 여기서 언급해야 할 점은 많은 사람들이 컴파일 타임이 무엇인지, 런타임이 무엇인지에 대한 명확한 개념을 갖고 있지 않다고 생각합니다. 예를 들어, 컴파일 컴파일러는 구문에 오류가 있는지 확인하고, 키워드나 이름을 쓰는 데 오류가 있는지 확인하고, 클래스를 로드하는 등 컴파일 중에 수행해야 하는 몇 가지 간단한 작업을 수행합니다. , 그러나 런타임 중에는 무엇을 합니까? 런타임은 프로그램이 시작되는 시점입니다. 코드가 메모리에 로드된 후 런타임 검사는 메모리에서 작업과 판단을 수행하는 것입니다.
int[] nums = new int[3]; nums[4] = 12;
위의 코드는 배열 첨자 범위를 벗어난 오류를 발생시키지만 프로그램은 컴파일할 때 오류를 보고하지 않지만 실행 시 ArrayIndexOutOfBoundsException 오류가 보고됩니다. 이것이 컴파일과 런타임의 차이입니다.
Java 리플렉션 메커니즘은 컴파일 시 어떤 클래스가 로드되는지 결정하지 않습니다. 이는 프로그램이 실행될 때 로드되어 사용됩니다. 간단한 그림을 사용하여 리플렉션의 실행 과정을 살펴보겠습니다. >
Java 리플렉션 메커니즘은 클래스의 기본 구조를 알 수 있습니다. Java 클래스의 구조를 감지하는 이러한 기능은 Eclipse와 같은 소프트웨어를 사용하여 작성할 때와 마찬가지로 "자체 검사"가 됩니다. 코드 자동 프롬프트 기능은 자바 반사 원리를 사용합니다. 그렇다면 Java의 리플렉션을 통해 어떤 기능을 달성할 수 있을까요? 1. 런타임에 개체가 속한 클래스를 결정합니다. 2. 런타임에 클래스의 개체를 구성합니다. 3. 런타임에 클래스의 속성과 메서드를 결정합니다. 4. 런타임 메서드에 개체를 호출합니다. Java Reflection에서 일반적으로 사용되는 클래스에는 Reflection의 핵심 클래스인 Class 클래스가 포함됩니다. Class 클래스를 통해 클래스의 속성, 메서드 등을 얻을 수 있습니다. Filed 클래스: 클래스의 속성을 나타내며, 클래스에 포함된 속성의 값을 가져오고 설정할 수 있습니다. 메소드 클래스(Method class): 클래스의 메소드를 나타내며, 클래스에 포함된 메소드에 대한 정보를 얻거나 메소드를 실행하는 데 사용할 수 있습니다. 생성자 클래스: 클래스의 생성자 메서드를 나타냅니다.
좋습니다. 이제 Java 리플렉션에 대한 기본 정보를 배웠습니다. 이제 코드를 사용하여 리플렉션의 각 기능을 하나씩 구현하겠습니다.
첫 번째는 가장 간단한 것이기도 합니다. 모두 Class 클래스를 사용해야 하며 먼저 인스턴스화해야 합니다. 그러나 Class 클래스에는 생성자가 없으므로 클래스 클래스를 만드는 방법에는 세 가지가 있습니다.
세 번째 forName() 메소드는 클래스가 불확실할 때 Class를 인스턴스화할 수 있어 더 유연합니다.public static void main(String[] args) { //第一种方法,通过对象.getClass()方法 User user = new User(); Class<? extends User> cs = user.getClass(); System.out.println(cs); //第二种方法,通过类名.class Class<User> cs1 = User.class; System.out.println(cs1); //第三种方法,通过Class本身的forName()方法,注意forName()方法会抛出一样,并且里面的参数需要完整的包名和类名 Class<?> cs2 = null; try { cs2 = Class.forName("cn.fanfu.demo.User"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(cs2); }
두 번째는 Class 클래스의 매개변수화된 구성을 통해 Class 클래스 객체의 새 인스턴스를 생성하는 것입니다.
세 번째는 클래스의 구조, 인터페이스, 메서드, 속성 등 시리즈 요소:public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { //在这里为了更直观的展示,直接使用String类 Class<?> cs =Class.forName("java.lang.String"); char[] ch = {'大','家','好','!','!'}; //调用Class类的有参构造函数,函数里的值为类.class Constructor<?> cst = cs.getConstructor(char[].class); String name = (String) cst.newInstance(ch); System.out.println(name); //因为这里的异常会使代码没有直观的显示,所以我直接抛给虚拟机 }네 번째는 클래스의 속성 값을 가져오거나 수정하는 것입니다.
public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { //先创建好两个对象 Class<?> cs = Class.forName("cn.fanfu.demo.User"); Constructor<?>[] con = null; //通过getConstructors()方法返回一个Constructor[]数组,数组里存储的是该类的各个构造 con = cs.getConstructors(); for (Constructor<?> item : con) { System.out.println(item); } //通过getInterfaces()方法返回一个Class<?>[]数组,数组里存储的是该类的各个接口 Class<?>[] inter = cs.getInterfaces(); for (Class<?> item : inter) { System.out.println(item); } //通过getSuperclass()方法返回一个Class<?> Class<?> parent = cs.getSuperclass(); //java中只支持单继承,所以只有一个父类 System.out.println(parent); //通过getMethods()方法返回一个Method[]数组,数组里存储的是该类的各个方法 Method[] method = cs.getMethods(); for (Method item : method) { System.out.println(item); } //通过getDeclaredFields()方法返回一个Field[]数组,数组里存储的是该类的各个属性 Field[] fiel = cs.getDeclaredFields(); for (Field item : fiel) { System.out.println(item); } //getDeclaredFields()方法可以获取全部属性,getFields()方法只能获取到公有属性 Field[] fiel1 = cs.getFields(); for (Field item : fiel1) { System.out.println(item); } }다섯 번째는 리플렉션을 통해 메서드를 호출하는 것입니다. :
public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException { //创建User对象 User us = new User(); us.setAge(12); us.setName("张三"); Class<?> cs = us.getClass(); //获取私有属性的值 Field fl = cs.getDeclaredField("name"); //要先设置允许访问 fl.setAccessible(true); //通过get方法指定对象获取值 String name = (String) fl.get(us); System.out.println(name); //通过set方法指定对象并修改值 fl.set(us, "李四"); String name2 = (String) fl.get(us); System.out.println(name2); }
public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException { //创建User对象 User us = new User(); us.setAge(12); us.setName("张三"); Class<?> cs = us.getClass(); //通过getMethod()方法获取类中方法,该方法有两个参数,一个指定方法名,一个指定方法中参数的类型 Method mm = cs.getMethod("say"); //通过invoke()方法调用方法,该方法有两个参数,一个指定对象,另一个传递参数 mm.invoke(us); }