1、什么是反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的法的功能称为java语言的反射机制。
2、反射机制有什么用(或者说 学了反射我们可以干些啥)
通过java语言中的反射机制可以操作字节码文件(可以读和修改字节码文件。)通过反射机制可以操作代码片段。(class文件。)
3、反射之前得先了解字节码文件也就是.class文件
.class说明:在 Java 中,JVM 可以理解的代码就叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机。Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题并且保留了解释型语言可移植的特点,而通过即时编译器(jit)又有编译型语言执行效率高的特点。所以 Java 程序运行时比较高效。Java通过字节码文件和虚拟机jvm之间的关系,做到了平台无关性,一次编译,各平台都可运行。
4、反射机制相关重要的类
众所周知,Java是一门面向对象的语音。在Java中所有的操作,模型,都是封装成类进行操作。
反射也是如此,被封装在reflect下
java.lang.reflect.*;
其他与反射相关的类,包括:字节码对象,反射对应的方法对象,构造函数对象,成员变量对象。
类 | 含义 |
java.lang.Class | 代表整个字节码。代表一个类型,代表整个类。 |
java.lang.reflect.Method | 代表字节码中的方法字节码。代表类中的方法。 |
java.lang.reflect.Constructor | 代表字节码中的构造方法字节码。代表类中的构造方法。 |
java.lang.reflect.Field | 代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。 |
4、获取Class的三种方式
Java获取字节码的三种方式:
方式 | 备注 |
---|---|
Class.forName(“完整类名带包名”) | 静态方法 throws ClassNotFoundException Class<?> |
对象.getClass() | Class<? extends T> |
任何类型.class | Class<T> |
注:以上三种方式返回值都是Class<T>类型或者Class<? extends T>。
4、三种方式逐个分析
4.1 getClass方法 属于Object类
public final native Class<?> getClass()
说明:这个方法上有native关键字,说明调用的是C/C++的程序实现的底层库(本地代码)。这种功能的实现要依靠Java平台提供的与本地(c/c++)代码进行互操的API——JNI(Java Native Interface),它被称之为Java本地接口
返回值说明:
JDK 1.8的文档注释中,该方法返回的是运行时类的Class对象。这个对象与静态同步方法所使用的锁对象是一个对象。
补充:synchronized实现同步的基础:Java中的每一个对象都可以作为锁。
具体表现为以下3种形式。
对于普通同步方法,锁是当前实例对象。
对于静态同步方法,锁是当前类的Class对象。
对于同步方法块,锁是Synchonized括号里配置的对象。
public class TestReflect {
public static void main(String[] args) throws ClassNotFoundException {
String s = new String();
System.out.println(s.getClass());
}
}
结果:
4.2 使用Class类提供的方法:
public static Class forName(String className) throws ClassNotFoundException
底层调用的也是Class的forName0方法
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
4.3 类.class
范例:通过类名找对应的class 文件
public class TestClass {
public static void main(String[] args) {
System.out.println(String.class);
}
}
结果:
5、通过反射实例化对象
以上事例中可以看出除了getClass()方法会实例化对象之外,其他的俩种不会产生实例化对象,所以取得Class类对象的一个最直接的好处就是通过反射实例化对象,该方法为:
对象.newInstance()
5.1 pojo对象
package com.copy.pojo.vo;
public class Student {
private String name;
private Integer age;
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
当我显式的定了有参的构造函数,覆盖了无参构造后,那么通过newInstance()创建对象时会抛出
Exception in thread "main" java.lang.InstantiationException: com.copy.pojo.vo.Student
package com.copy.reflect;
import com.copy.pojo.vo.Student;
public class TestNewInstance {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> studentClass = Class.forName("com.copy.pojo.vo.Student");
Student S = (Student) studentClass.newInstance();
}
}
结果:
6、与反射相关的类
类名 | 说明 |
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类属性) |
Method类 | 代表类的方法 |
Construct类 | 代表类的构造方法 |
Annotiation类 | 代表类的注解 |
6.1 Class类中相关的方法
方法名 | 备注 |
public T newInstance | 通过反射创建对象 |
public String getName() | 返回完整类名带包名 |
public String getSimpleName() | 返回类名 |
public Field[] getFields() | 返回类中所有public修饰的属性 |
public Field[] getDeclaredFields() | 返回类中所有属性 |
public Field getDeclaredField(String name) | 根据属性名name获取指定属性 |
public Method[] getDeclareMethods() | 获取属性的修饰符列表,返回的修饰符是一个数字【一般配合Modeifiler类中的toString(int x)方法使用】 |
public Method getDeclaredMethod(String name Class<?> param) | 返回类中所有的实例方法 |
public Contruct<?>[] getDeclaredConstructors | 返回类中所有的构造方法 |
public Constructor getDeclaredConstructor(Class<?> param) | 根据方法形参获取指定的构造方法 |
----- | ------- |
public native Class<? super T> getSuperClass() | 返回调用类的父类 |
public Class<?>[] getInterface | 返回调用类实现接口的集合 |