Java 的反射机制是指在运行状态中:
反射中包含了一个“反”字,那么肯定就有所谓的“正”字;
“正射”: 引入需要的“包类”名称 --> 通过new实例化 --> 取得实例化对象;
从 Java 入门到现在,我们已经了解了什么是类,当我们使用这个类(Person 类)的时候,我们要理解这个类中的属性(年龄、姓名、性别…)和方法(技能,比如唱歌、跳舞、写代码…),在了解了属性和方法之后,我们对这个类进行实例化(理解为创造一个游戏角色),之后使用这个类对象(创建好的角色)操作(命名,定义性别,年龄,定义技能等);
Person person = new Person(); //“正”
person.skill("伐木");
“反射”:实例化对象 --> getClass()方法 --> 得到完整的"包类"名称;
反射则是一开始我们并不知道我们初始化的类对象是什么,我们通过所谓的反射机制,创建对象,以及其调用含有的方法;
Class c1 = Class.forName("com.sd.day25.Person");
Method method = c1.getMethod("skill", String.class);
Person person = (Person)c1.newInstance();
person.skill("伐木");
以上代码的意思,稍后会将,但是验证了反射和正射得到的结果是相同的,但是思路却完全不同;正射代码在未运行时已经知道了要运行的类(Person);而反射代码则是在运行时通过字符串值才知道要运行的类(com.sd.day25.Person);
java.lang.Class //代表一个类
java.lang.reflect.Method //代表类的方法
java.lang.reflect.Field //代表类的成员变量
java.lang.reflect.Constructor //代表类的构造器
代码演示:
/*
反射
*/
public class Demo03Reflection {
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获取类的Class对象
Class aClass = Class.forName("com.sd.day25_Annotation.user");
System.out.println(aClass); //class com.sd.day25_Annotation.user
Class Class1 = Class.forName("com.sd.day25_Annotation.user");
Class Class2 = Class.forName("com.sd.day25_Annotation.user");
Class Class3 = Class.forName("com.sd.day25_Annotation.user");
//一个类在内存中只有一个Class对象(哈希值相同)
//一个类被加载后,类的整个结构都会被封装在Class对象中
System.out.println(Class1.hashCode()); //356573597
System.out.println(Class2.hashCode()); //356573597
System.out.println(Class3.hashCode()); //356573597
}
}
//定义实体类
class user {
private int age;
private String name;
private String password;
public user(int age, String name, String password) {
this.age = age;
this.name = name;
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "user{" +
"age=" + age +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
在 Object 类中定义了以下的方法,此方法将被所有子类继承;
public final Class getClass()
以上方法返回值的类型是一个 Class 类,此类是 Java 反射的源头,实际上所谓反射从程序的运行结果看就是:可以通过对象反射求出类的名称;
对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口;
对于每个类而言,jre 都为其保留了一个不变的Class 类型的对象;
一个 Class 对象包含了特定的某个结构(class / interface / enum / annotation / primitive type / void / [])的有关信息;
Class 本身也是一个类;
Class 对象只能由系统建立对象;
一个加载的类在 JVM 中只会有一个 Class 实例;
一个 Class 对象对应的是一个加载到 JVM 中的一个 .class 文件;
每个类的实例都会记得自己是由哪个 Class 实例所生成;
通过 Class 可以完整地得到一个类中的所有被加载的结构;
Class 类是 Reflection 的根源,针对任何你想动态加载、运行的类,唯有先获得相应的 Class 对象;
若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高;
Class aclass = Person.class;
已知某个类的实例,代用该实例的 getClass() 方法获取 Class 对象;
Class aclass = person.getClass();
已知一个类的全类名,且该类在类路径下,可通过 Class 类的静态方法 forName() 获取,可能抛出 ClassNotFoundException;
Class aclass = Class.forName("Demo01.Student");
内置基本数据类型可以直接用类名 .Type;
还可以利用 ClassLoader;
代码演示:
/*
Class 类创建方式
*/
public class Demo04CreatClass {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("This person is a " + person.name); //This person is a Student
//方式1:通过对象获得
Class c1 = person.getClass();
System.out.println(c1.hashCode()); //356573597
//方式2:forname获得
Class c2 = Class.forName("com.sd.day25_Annotation.Student");
System.out.println(c2.hashCode()); //356573597
//方式3:通过类名.class获得
Class c3 = Student.class;
System.out.println(c3.hashCode()); //356573597
//方式4:基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4); //int
//获得父类类型
Class c5 = c1.getSuperclass();
System.out.println(c5); //class com.sd.day25_Annotation.Person
}
}
class Person {
public String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person {
public Student() {
this.name = "Student";
}
}
class Teacher extends Person {
public Teacher() {
this.name = "Teacher";
}
}
static ClassforName(String name) //返回指定类名name的Class对象
Object newInstance() //调用缺省构造函数,返回Class对象的一个实例
getName() //返回此Class对象所表示的实体(类,接口,数组类或void)的名称
Class getSuperClass() //返回当前Class对象的父类的Class对象
Class[] getinterfaces() //获取当前Class对象的接口
ClassLoader getClassLoader() //返回该类的类加载器
Constructor[] getConstructors() //返回一个包含某些Constructor对象的数组
Method getMothed(String name, Class.. T) //返回一个Method对象,此对象的形参类型为paramType
Field[] getDeclareFields() //返回Field对象的一个数组;
代码演示:
import java.io.ObjectOutputStream;
import java.lang.annotation.ElementType;
/*
所有类型的class
*/
public class Demo05Class {
public static void main(String[] args) {
Class c1 = Object.class; // 类
Class c2 = Comparable.class; //接口
Class c3 = String[].class; // 一维数组
Class c4 = int[][].class; //二维数组
Class c5 = Override.class; //注解
Class c6 = ElementType.class; //枚举
Class c7 = Integer.class; //基本数据类型
Class c8 = void.class; //空类型
Class c9 = Class.class; //Class
System.out.println(c1); //class java.lang.Object
System.out.println(c2); //interface java.lang.Comparable
System.out.println(c3); //class [Ljava.lang.String;
System.out.println(c4); //class [[I
System.out.println(c5); //interface java.lang.Override
System.out.println(c6); //class java.lang.annotation.ElementType
System.out.println(c7); //class java.lang.Integer
System.out.println(c8); //void
System.out.println(c9); //class java.lang.Class
//只要元素类型与维度一样,就是同一个Class
int[] a = new int[10];
int[] b = new int[1000];
System.out.println(a.getClass().hashCode()); //356573597
System.out.println(b.getClass().hashCode()); //356573597
}
}
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤对该类进行初始化:
代码演示:
public class Demo06ClassLoad {
public static void main(String[] args) {
A a = new A();
System.out.println(a.m);
/*
运行过程分析:
1.加载到内存,会产生一个类对应的 Class 对象;
2. 链接,链接结束后 m = 0;(默认值,个人理解是系统规定)
3. 初始化
调用(){
System.out.println("A 类静态代码块初始化");
m = 300;
m = 100
}
m = 100;
*/
/*
运行结果:
A 类静态代码块初始化
A 类的无参构造函数初始化
100
*/
}
}
class A {
static {
System.out.println("A 类静态代码块初始化");
m = 300;
}
static int m = 100;
public A() {
System.out.println("A 类的无参构造函数初始化");
}
}
类的主动引用(一定会发生类的初始化):
类的被动引用(不会发生类的初始化):
代码演示:
/*
测试类什么时候会初始化
*/
public class Demo07ClassInit {
static {
System.out.println("main被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
//1.主动引用 :极大消耗资源
// Son son = new Son();
/*
运行结果:
main被加载
父类被加载
子类被加载
*/
//2.反射也会产生主动引用
// Class.forName("com.sd.day25_Annotation.Son");
/*
运行结果:
main被加载
父类被加载
子类被加载
*/
//3.不会产生类的引用方法
// System.out.println(Son.b);
/*
运行结果:
main被加载
父类被加载
2
*/
//4.通过数组定义类的引用,不会触发此类的初始化;
Son[] array = new Son[5];
/*
运行结果:
main被加载
*/
//5.引用常量不会触发此类的初始化
System.out.println(Son.M);
/*
运行结果:
main被加载
1
*/
}
}
class Father{
static int b =2;
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m = 300;
}
static int m = 100;
static final int M = 1;
}
引导类加载器:用 C++ 编写,是 JVM 自带的类加载器,负责 Java 平台核心库(rt.jar),用来装载核心库。该加载器无法直接获取;
扩展类加载器:负责 jre/lib/ext 目录下的 jar 包 -D java.ext.dirs 指定目录下的 jar 包装入工作库;
系统类加载器:负责 java -classpath 或 -D java.class.path 所指的目录下的类与 jar 包装入工作,是最常用的加载器;
代码演示:
public class Demo08ClassLoader {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类的加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2
//获取系统类加载器的父类加载器--->扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent); //sun.misc.Launcher$ExtClassLoader@1540e19d
//获取扩展类加载器的父类加载器---->根加载器(C/C++) 获取不到会返回null
ClassLoader parent1 = parent.getParent();
System.out.println(parent1); //null
//测试当前类的类加载器
ClassLoader classLoader = Class.forName("com.sd.day25_Annotation.Demo08ClassLoader").getClassLoader();
System.out.println(classLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2
//测试 JDK 内置类的类加载器 ------> 根加载器
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader); //null
//如何获得系统类加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
/*
D:\Program Files\java\jdk\jre\lib\charsets.jar;
D:\Program Files\java\jdk\jre\lib\deploy.jar;
D:\Program Files\java\jdk\jre\lib\ext\access-bridge-64.jar;
D:\Program Files\java\jdk\jre\lib\ext\cldrdata.jar;
D:\Program Files\java\jdk\jre\lib\ext\dnsns.jar;
D:\Program Files\java\jdk\jre\lib\ext\jaccess.jar;
D:\Program Files\java\jdk\jre\lib\ext\jfxrt.jar;
D:\Program Files\java\jdk\jre\lib\ext\localedata.jar;
D:\Program Files\java\jdk\jre\lib\ext\nashorn.jar;
D:\Program Files\java\jdk\jre\lib\ext\sunec.jar;
D:\Program Files\java\jdk\jre\lib\ext\sunjce_provider.jar;
D:\Program Files\java\jdk\jre\lib\ext\sunmscapi.jar;
D:\Program Files\java\jdk\jre\lib\ext\sunpkcs11.jar;
D:\Program Files\java\jdk\jre\lib\ext\zipfs.jar;
D:\Program Files\java\jdk\jre\lib\javaws.jar;
D:\Program Files\java\jdk\jre\lib\jce.jar;
D:\Program Files\java\jdk\jre\lib\jfr.jar;
D:\Program Files\java\jdk\jre\lib\jfxswt.jar;
D:\Program Files\java\jdk\jre\lib\jsse.jar;
D:\Program Files\java\jdk\jre\lib\management-agent.jar;
D:\Program Files\java\jdk\jre\lib\plugin.jar;
D:\Program Files\java\jdk\jre\lib\resources.jar;
D:\Program Files\java\jdk\jre\lib\rt.jar;
H:\2019Java-西开\Sd\out\production\HelloWorld;
H:\2019Java-西开\Sd\lib\kotlin-stdlib-js.jar;
C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.6\lib\idea_rt.jar
*/
}
}
代码演示:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//获取类的信息
public class Demo09ClassInformation {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class aClass = Class.forName("com.sd.day25_Annotation.user");
//获得类的名字:包名+类名
System.out.println(aClass.getName()); //com.sd.day25_Annotation.user
//获得类的简单名字:类名
System.out.println(aClass.getSimpleName()); //user
/*
获得类的属性
*/
//找到public属性
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
//找到全部属性
Field[] fields1 = aClass.getDeclaredFields();
for (Field field : fields1) {
System.out.println(field);
}
/*
private int com.sd.day25_Annotation.user.age
private java.lang.String com.sd.day25_Annotation.user.name
private java.lang.String com.sd.day25_Annotation.user.password
*/
//获得指定属性的值
Field name = aClass.getDeclaredField("name");
System.out.println(name); //private java.lang.String com.sd.day25_Annotation.user.name
/*
获得类的方法
*/
//获取本类及其父类的全部public方法
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
/*
public java.lang.String com.sd.day25_Annotation.user.toString()
public java.lang.String com.sd.day25_Annotation.user.getName()
public void com.sd.day25_Annotation.user.setName(java.lang.String)
public java.lang.String com.sd.day25_Annotation.user.getPassword()
public int com.sd.day25_Annotation.user.getAge()
public void com.sd.day25_Annotation.user.setAge(int)
public void com.sd.day25_Annotation.user.setPassword(java.lang.String)
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 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()
*/
//获得本类的所有方法
System.out.println("---------------------------");
methods = aClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
/*
public java.lang.String com.sd.day25_Annotation.user.toString()
public java.lang.String com.sd.day25_Annotation.user.getName()
public void com.sd.day25_Annotation.user.setName(java.lang.String)
public java.lang.String com.sd.day25_Annotation.user.getPassword()
public int com.sd.day25_Annotation.user.getAge()
public void com.sd.day25_Annotation.user.setAge(int)
public void com.sd.day25_Annotation.user.setPassword(java.lang.String)
*/
/*
获得指定的方法
*/
Method getName = aClass.getMethod("getName", null);
Method setName = aClass.getMethod("setName", String.class);
System.out.println(getName); //public java.lang.String com.sd.day25_Annotation.user.getName()
System.out.println(setName); //public void com.sd.day25_Annotation.user.setName(java.lang.String)
/*
获得类的构造器
*/
//获得public 方法
Constructor[] constructors = aClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
/*
public java.lang.String com.sd.day25_Annotation.user.getName()
public void com.sd.day25_Annotation.user.setName(java.lang.String)
*/
//获得所有的方法
constructors = aClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
/*
public com.sd.day25_Annotation.user(int,java.lang.String,java.lang.String)
public com.sd.day25_Annotation.user(int,java.lang.String,java.lang.String)
*/
/*
获得指定的构造器
*/
//欲获得user方法,里边的参数为 int age, String name, string password
Constructor declaredConstructor = aClass.getDeclaredConstructor(int.class, String.class, String.class);
System.out.println("指定的构造器:" + declaredConstructor);
//指定的构造器:public com.sd.day25_Annotation.user(int,java.lang.String,java.lang.String)
}
}
调用 Class 对象的 newInstance() 方法;
需要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,才可以实例化操作;
步骤如下:
代码演示:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/*
动态的创建对象,通过反射
*/
public class Demo10 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
/*
构造一个对象:含有无参构造器
*/
//获得 Class 对象
Class aClass = Class.forName("com.sd.day25_Annotation.Person");
//调用了无参构造器
Person person = (Person) aClass.newInstance();
System.out.println(person); //Person{name='null'}
/*
通过反射调用普通方法
*/
Person person1 = (Person) aClass.newInstance();
//通过放射获取一个方法
//invoke :激活的意思
//invoke(对象,“方法的值”)
Method setName = aClass.getDeclaredMethod("setName", String.class);
setName.invoke(person1, "灭霸");
System.out.println(person1.getName()); //灭霸
/*
通过反射操作属性
如属性为私有,采用setAccessible(true);关掉安全警告
*/
Person person2 = (Person) aClass.newInstance();
Field name = aClass.getDeclaredField("name");
name.set(person2, "灭绝");
System.out.println(person2.getName()); //灭绝
/*
构造一个对象:没有无参构造器
*/
//获得 Class 对象
Class aClass1 = Class.forName("com.sd.day25_Annotation.user");
// 获得构造器
Constructor constructor = aClass1.getDeclaredConstructor(int.class, String.class, String.class);
//创建对象
user userNo1 = (user) constructor.newInstance(25, "李四", "123456");
System.out.println(userNo1); //user{age=25, name='李四', password='123456'}
}
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/*
分析性能问题
*/
public class Demo11PerformanceContrast {
//普通方式调用
public static void test01() {
Person person = new Person();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
person.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式执行10亿次时间:" + (endTime - startTime) + "ms");
}
//反射方式调用
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Person person = new Person();
Class c1 = person.getClass();
Method getName = c1.getDeclaredMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
getName.invoke(person, null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式执行10亿次时间:" + (endTime - startTime) + "ms");
}
//反射方式调用 关闭检测
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Person person = new Person();
Class c1 = person.getClass();
Method getName = c1.getDeclaredMethod("getName", null);
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
getName.invoke(person, null);
}
long endTime = System.currentTimeMillis();
System.out.println("关闭检测后反射方式执行10亿次时间:" + (endTime - startTime) + "ms");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test01(); //普通方式执行10亿次时间:7ms
test02(); //反射方式执行10亿次时间:455ms
test03(); // 关闭检测后反射方式执行10亿次时间:177ms
}
}
反射操作泛型:
代码演示:
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
/*
通过反射获取泛型
*/
public class Demo12 {
//泛型参数
public void test01(Map<String, user> map, List<user> list) {
System.out.println("test01");
}
//泛型返回值
public Map<String, user> test02() {
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = Demo12.class.getMethod("test01", Map.class, List.class);
//获得泛型参数信息
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("泛型参数信息:" + genericParameterType);
if(genericParameterType instanceof ParameterizedType){
Type[] actualTypeArguments =((ParameterizedType)genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("真实泛型参数信息:" + actualTypeArgument);
}
}
}
/*
泛型参数信息:java.util.Map
真实泛型参数信息:class java.lang.String
真实泛型参数信息:class com.sd.day25_Annotation.user
泛型参数信息:java.util.List
真实泛型参数信息:class com.sd.day25_Annotation.user
*/
method = Demo12.class.getMethod("test02", null);
Type genericReturnType = method.getGenericReturnType();
if(genericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments =((ParameterizedType)genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println( actualTypeArgument);
}
}
/*
class java.lang.String
class com.sd.day25_Annotation.user
*/
}
}
对象映射关系(Object relationship Mapping, ORM);
代码演示:
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
/*
反射操作注解
*/
public class Demo13ReflectionAndAnnotation {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.sd.day25_Annotation.Student1");
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation); //@com.sd.day25_Annotation.TableTest(value=db_Student)
}
//获得注解value的值
TableTest tableTest = (TableTest) c1.getAnnotation(TableTest.class);
String value = tableTest.value();
System.out.println(value); //db_Student
//获得指定类的注解
Field f = c1.getDeclaredField("name"); //可将 name 换位 id 或者 age
FieldTest annotation = f.getAnnotation(FieldTest.class);
System.out.println(annotation.columnName()); //db_name
System.out.println(annotation.type()); //int
System.out.println(annotation.length()); //3
}
}
//创建类
@TableTest("db_Student")
class Student1 {
@FieldTest(columnName = "db_id", type = "int", length = 10)
private int id;
@FieldTest(columnName = "db_age", type = "int", length = 10)
private int age;
@FieldTest(columnName = "db_name", type = "int", length = 3)
private String name;
public Student1() {
}
public Student1(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student1{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableTest {
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldTest {
String columnName();
String type();
int length();
}