JAVA基础课程
第二十四天 Java 反射
Java 反射机制概述
(1)Reflection(反射)是被视为动态语言的关键,反射机制允许程序再执行期借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法
(2)加载完类以后,再堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息,我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以称为:反射
(3)Java反射机制研究及应用
①在运行是判断任意一个对象所属的类
②在运行是钩爪任意一个类的对象
③在运行是判断任意一个类所具有的成员变量和方法
④在运行是获取泛型信息
⑤在运行是调用任意一个对象的成员变量和方法
⑥在运行是处理注解
⑦生成动态代理
(4)Java反射主要的API
①java.lang.Class:代表一个类
②java.lang.reflect.Method:代表类的方法
③java.lang.reflect.Field:代表类的成员变量
④java.lang.reflect.Constuctor:代表类的构造器
(5)简单使用
package com.test.course.reflectiontest;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 〈Reflection〉
*
* @author PitterWang
* @create 2020/5/14
* @since 1.0.0
*/
public class ReflectionTest {
@Test
public void test(){
//1.创建Persion类的对象
Persion persion = new Persion(1,"TT");
}
@Test
public void test2() throws Exception {
Class<Persion> clazz = Persion.class;
/***
* 通过反射创建Persion类的对象
*/
Constructor<Persion> persionConstructor = clazz.getConstructor(int.class, String.class);
Persion persion = persionConstructor.newInstance(1, "TT");
System.out.println(persion.toString());
/*
persion.name = "NIBABA";
persion.setId(2);
System.out.println(persion.toString());
persion.speak();
*/
/**
* 通过反射,调用属性,私有的和公共的都可以调用
*/
Field name = clazz.getDeclaredField("name");
name.set(persion,"NIBABA");
System.out.println(persion.toString());
Method speak = clazz.getDeclaredMethod("speak");
speak.invoke(persion);
/***
* 调用私有属性
*/
Field id = clazz.getDeclaredField("id");
id.setAccessible(true);
id.set(persion,12);
System.out.println(persion.toString());
/***
* 调用私有方法
*/
Method eat = clazz.getDeclaredMethod("eat",String.class);
eat.setAccessible(true);
eat.invoke(persion,"biebie");
}
}
class Persion{
private int id;
String name;
public Persion(int id, String name) {
this.id = id;
this.name = name;
}
private Persion(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void speak(){
System.out.println(this.name + "说话了");
}
private void eat(String food){
System.out.println(this.name + "吃"+ food);
}
@Override
public String toString() {
return "Persion{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
理解Class类并获取Class实例
(1)类的加载过程
程序经过javac.exe命令后,会生成一个或者多个字节码文件(.class)接着我们使用java.exe命令对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中,次过程就叫做类的加载。加载到内存中的类,我们就称为运行时类,此时运行时类,就叫为Class的一个实例。
换句话说,Class的实例对应着一个运行时类。
(2)那些类型可以成为有Class对象?
①class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
②interface:接口
③数组
④enum:枚举
⑤annotation:注解
⑥primitive type:基本数据类型
⑦void
@Test
public void test1(){
Class c = Object.class;
Class c1 = Comparable.class;
Class c2 = String[].class;
Class c3 = int[][].class;
Class c4 = Override.class;
Class c5 = int.class;
Class c6 = void.class;
Class c7 = Class.class;
}
(3)Claaa实例的四种方式
package com.test.course.reflectiontest;
import org.junit.Test;
/**
* 〈Claaa实例〉
*
* @author PitterWang
* @create 2020/5/16
* @since 1.0.0
*/
public class ClassTest {
@Test
public void test1(){
Class c = Object.class;
Class c1 = Comparable.class;
Class c2 = String[].class;
Class c3 = int[][].class;
Class c4 = Override.class;
Class c5 = int.class;
Class c6 = void.class;
Class c7 = Class.class;
}
@Test
public void test() throws ClassNotFoundException {
/***
* 1.调用运行时类的属性:.class
*/
Class clazz = Persion.class;
System.out.println(clazz);
/***
* 2.通过运行时类的对象,调用getClass()
*/
Persion persion = new Persion();
Class<? extends Persion> aClass = persion.getClass();
System.out.println(aClass);
/***
* 3.调用Class的静态方法:forName(String classPath)
*/
Class<?> aClass1 = Class.forName("com.test.course.reflectiontest.Persion");
System.out.println(aClass1);
/**
* 4.通过类加载器:Classloader
*/
ClassLoader classLoader = ClassTest.class.getClassLoader();
Class<?> aClass2 = classLoader.loadClass("com.test.course.reflectiontest.Persion");
System.out.println(aClass2);
}
}
类的加载与ClassLoader的理解
以后在学习JVM中写,这里写一个ClassLoader加载配置文件
package com.test.course.reflectiontest;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 〈ClassLoader〉
*
* @author PitterWang
* @create 2020/5/16
* @since 1.0.0
*/
public class ClassLoaderTest {
@Test
public void test() throws IOException {
Properties properties = new Properties();
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("test.propertise");
properties.load(resourceAsStream);
String name = properties.getProperty("name");
System.out.println(name);
}
}
创建运行时类的对象
package com.test.course.reflectiontest;
import org.junit.Test;
import java.util.Random;
/**
* 〈通过反射创建对应运行时类的对象〉
*
* @author PitterWang
* @create 2020/5/16
* @since 1.0.0
*/
public class ClassTest1 {
@Test
public void test() throws IllegalAccessException, InstantiationException {
Class<Persion> persionClass = Persion.class;
/**
* newInstance();调用此方法,创建运行时类的对象,内部调用了运行时类的空参构造器
*
* 成功调用此方法,必须
* ①运行时类必须有空参构造器
* ②空参构造器的权限必须时public
*/
Persion persion = persionClass.newInstance();
System.out.println(persion);
}
/**
* 动态创建运行时类对象
* @throws Exception
*/
@Test
public void test1() throws Exception{
for(int j = 0;j<100;j++){
int i = new Random().nextInt(2);
String namePath = "";
if(i == 0){
namePath = "com.test.course.reflectiontest.Persion";
}else if(i == 1){
namePath = "java.lang.String";
}else{
namePath = "java.util.Date";
}
System.out.println(namePath);
Object o = getInstance(namePath);
System.out.println("******************");
System.out.println(o);
}
}
public Object getInstance(String namePath) throws Exception {
Class<?> aClass = Class.forName(namePath);
return aClass.newInstance();
}
}
获取运行时类的完整结构
(1)获取运行时类的方法结构
/***
* 获取运行时类方法
*/
@Test
public void test(){
Class<Persion> clazz = Persion.class;
/**
* 获取运行时类及其父类的中什么为public的方法
*/
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("******************");
/**
* 获取运行时类中所有的方法,不包含父类的方法
*/
Method[] declaredMethods = clazz.getDeclaredMethods();
/***
* 获取方法的修饰
* 注解 权限修饰符 返回值类型 方法名(参数) throws 异常{}
*/
for (Method method: declaredMethods) {
System.out.println(method);
System.out.println("************************");
//获取方法上的注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//方法的权限修饰符
int modifiers = method.getModifiers();
System.out.print(Modifier.toString(modifiers) + "\t");
//方法的返回类型
Class<?> returnType = method.getReturnType();
System.out.println(returnType.getName());
//方法名
System.out.println(method.getName());
//形成列表
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType.getName());
}
//抛出的异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType.getName());
}
}
}
(2)获取运行时类的属性结构
/***
* 获取运行时类属性
*/
@Test
public void test1(){
Class<Persion> clazz = Persion.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
int modifiers = declaredField.getModifiers();//权限修饰符
System.out.print(Modifier.toString(modifiers) + "\t");
Class<?> type = declaredField.getType();//数据类型
System.out.print(type.getName() + "\t");
String name = declaredField.getName();//变量名
System.out.print(name);
System.out.println();
}
}
(3)获取运行时类的构造器
/***
* 获取运行时类的构造器
*/
@Test
public void test2(){
Class<Persion> clazz = Persion.class;
/**
* 获取运行时类中声明为public的构造器
*/
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("*****************************");
/***
* 获取运行时类的所有构造器
*/
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor constructor : declaredConstructors) {
System.out.println(constructor);
}
}
(4)获取运行时类的父类及泛型类型
/**
* 获取运行时类的父类及泛型类型
*/
@Test
public void test3(){
Class<Persion> clazz = Persion.class;
/**
* 获取运行时类的父类s
*/
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
/***
* 获取父类的泛型类型
*/
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
(4)获取运行时类实现的接口及其父类实现的接口
@Test
public void test4(){
Class<Persion> clazz = Persion.class;
/**
*运行时类实现的接口
*/
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println(anInterface);
}
System.out.println("*********************8");
/**
* 运行时类父类实现的接口
*/
Class<?>[] interfaces1 = clazz.getSuperclass().getInterfaces();
for (Class<?> aClass : interfaces1) {
System.out.println(aClass);
}
}
(5)获取运行时类所在的包
/***
*获取运行时类所在的包
*/
@Test
public void test5() {
Class<Persion> clazz = Persion.class;
Package aPackage = clazz.getPackage();
System.out.println(aPackage);
}
(6)获取运行时类声明的注解
/***
*获取运行时类实现的注解
*/
@Test
public void test6() {
Class<Persion> clazz = Persion.class;
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
调用运行时类的指定结构
(1)操作运行时指定类的属性
/**
* 操作运行时指定类的属性
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchFieldException
*/
@Test
public void test() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<Persion> clazz = Persion.class;
/***
* 方法1:
*/
/**
* 创建运行时类的对象
*/
Persion persion = clazz.newInstance();
/**
* 获取指定的属性public的属性
*/
Field name = clazz.getField("name");
/**
* 为指定属性设置值
* 参数1时那个对象设值
* 参数2时设置的内容
*/
name.set(persion,"DD");
System.out.println(persion);
/***
* 获取指定对象的属性值
*/
Object o = name.get(persion);
System.out.println(o);
/**
* 方法2 获取任意权限的值
*/
/**
* 获取指定属性
*/
Field id = clazz.getDeclaredField("id");
/**
* 设置属性可访问
*/
id.setAccessible(true);
/**
* 设值
*/
id.set(persion,123);
System.out.println(persion);
/**
* 取值
*/
System.out.println(id.get(persion));
}
(2)操作运行时类的指定方法
@Test
public void test1() throws Exception {
/**
* 创建运行时类
*/
Class<Persion> clazz = Persion.class;
Persion persion = clazz.newInstance();
/**
* 获取指定方法
*/
Method eat = clazz.getDeclaredMethod("eat", String.class);
/**
* 设置可访问
*/
eat.setAccessible(true);
/**
* 调用方法
*/
eat.invoke(persion,"吃屎");
/**
* 获取指定方法
*/
Method tett = clazz.getDeclaredMethod("tett", String.class);
/**
* 设置可访问
*/
tett.setAccessible(true);
/**
* 调用方法 获取返回值
*/
Object ret = tett.invoke(persion,"吃屎");
System.out.println(ret);
}
(3)操作运行时类的构造器
@Test
public void test2() throws Exception {
/**
* 创建运行时类
*/
Class<Persion> clazz = Persion.class;
/***
* 调用无参构造器方法1
*/
Persion persion = clazz.newInstance();
System.out.println(persion);
/***
* 调用无参构造器方法2
*/
Constructor<Persion> declaredConstructor1 = clazz.getDeclaredConstructor();
Persion persion1 = declaredConstructor1.newInstance();
System.out.println(persion1);
System.out.println("************************");
/**
* 调用指定的构造器
*/
Constructor<Persion> declaredConstructor = clazz.getDeclaredConstructor(String.class);
declaredConstructor.setAccessible(true);
Persion persion3 = declaredConstructor.newInstance("DD");
System.out.println(persion3);
//Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
}