小白的成长来源于努力学习,坚持每天的积累。 ——半杯态
一、获取Class类型;
1.类型名.class
这种方式:简洁,但是编译期才可以使用。
public void test01() {
Class B1 = int.class; //基本数据类型
Class<Void> voidClass = void.class; // 特殊的空类型
Class<String> stringClass = String.class; //jdk 定义的类型
Class<Serializable> serializableClass = Serializable.class; //获取接口类型
Class<int[]> arryList = int[].class; // 获取数组类型
Class<TestClass> testClassClass = TestClass.class; //自定义类型
Class<ElementType> elementTypeClass = ElementType.class; //枚举类型
System.out.println(elementTypeClass);
}
2.对象.getClass()
这个方法在java.lang.Object类型中声明的,返回对象的运行时类型
@Test
public void test02() {
Class c2 = String.class;
//重点在student
Student student = new Student();
student.getClass();
Class c1 = "".getClass();
Class<Student> studentClass = Student.class;
System.out.println(studentClass);
System.out.println(c1 == c2);
}
3.Class.forName(“类型全名称”)
这个类型可以在编译期间未知,这个类名称可以在代码中出现,也可以配置在配置文件中,或者键盘输入等方式来指定。
@Test
public void test03() throws ClassNotFoundException {
Class<?> name = Class.forName("com.banbeitai.reflect.Student");
System.out.println(name);
}
4.使用类加载器对象.loadClass(“类型全名称”)
一般都是用在自定义类加载器对象去加载指定路径下的类
@Test
public void test04() throws ClassNotFoundException {
Class<TestClass> testClassClass = TestClass.class;
ClassLoader classLoader = testClassClass.getClassLoader();
Class<?> loadClass = classLoader.loadClass("com.banbeitai.reflect.Student");
System.out.println(loadClass);
}
二、反射的作用与运用
1、在运行时能够获取任意类型的详细信息
2、在运行时能够创建任意引用数据类型的对象
3、在运行时可以为任意对象的任意属性赋值,或者获取任意对象的任意属性的值
4、在运行时可以调用任意对象的任意方法
5、在运行时读取某个注解信息
6、在运行时读取某个类的泛型实参
使用步骤:
(1)获取这个类的Class对象
(2)获取类的信息
①包名②类名③类的修饰符Modifier④直接父类⑤父接口⑥属性⑦构造器⑧方法
package com.banbeitai.reflect;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.Properties;
public class TestClassInfo {
private Class clazz;
@Before
public void loadClass() throws IOException, ClassNotFoundException {
Properties pro = new Properties();
pro.load(TestClassInfo.class.getResourceAsStream("bean.properties"));
String className = pro.getProperty("className");
clazz = Class.forName(className);
System.out.println(className);
}
@Test
public void getProperty() {
//获取类所在的包名
Package aPackage = clazz.getPackage();
System.out.println("获取包名:" + aPackage);
//获取类名
System.out.println("获取包名:" + clazz.getName());
//获取类的修饰符
int mod = clazz.getModifiers();
System.out.println("修饰符的值:" + mod);
System.out.println("修饰符:" + Modifier.toString(mod));
//获取类的父类
System.out.println("父类是:" + clazz.getSuperclass());
//返回该类实现和继承的接口
Class[] interfaces = clazz.getInterfaces();
for (Class inter : interfaces) {
System.out.println(inter.getName());
}
//每一个属性就是一个Field的对象
/*
* (1)Field[] getFields() 得到所有公共的属性 包含本类非私有修饰的以及父级(接口,类)的全部的成员变量
* (2)Field[] getDeclaredFields() 得到所有声明的属性
*/
Field[] fields = clazz.getFields();
//Field[] fields = clazz.getDeclaredFields();
int count = 0;
for (Field field : fields) {
count++;
int fMod = field.getModifiers();
System.out.println("序号:" + count + ":属性名:" + field.getName());
System.out.println("序号:" + count + ":属性的数据类型:" + field.getType().getName());
System.out.println("序号:" + count + ":属性的修饰符::" + Modifier.toString(fMod));
}
/*
* Constructor[] getConstructors():得到所有的公共的构造器
* Constructor[] getDeclaredConstructors()():得到所有的声明的构造器
*/
count = 0;
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println("序号:" + count + ":构造器名字:" + constructor.getName());
int cMod = constructor.getModifiers();
System.out.println("序号:" + count + ":构造器修饰符:" + Modifier.toString(cMod));
Class[] parameterTypes = constructor.getParameterTypes();
Parameter[] parameters = constructor.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter.toString());
}
System.out.println(count + ":构造器的形参列表:" + Arrays.toString(parameterTypes));
/* (1)Method[] getMethods(); 得到所有公共的方法
* (2)Method[] getDeclaredMethods(); 得到所有声明的方法
*/
}
/* (1)Method[] getMethods(); 得到所有公共的方法
* (2)Method[] getDeclaredMethods(); 得到所有声明的方法
*/
count=0;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
count++;
int mMod = method.getModifiers();
System.out.println(count + ":方法的修饰符:" + Modifier.toString(mMod));
System.out.println(count +":方法的返回值类型:" + method.getReturnType());
System.out.println(count + ":方法的名称:" + method.getName());
System.out.print(count + ":抛出的异常类型们:");
Class<?>[] exceptionTypes = method.getExceptionTypes();
System.out.println(Arrays.toString(exceptionTypes));
Class[] parameterTypes = method.getParameterTypes();
System.out.println(count + ":方法的形参列表:" + Arrays.toString(parameterTypes));
}
}
}
2.1 创建对象
方式一:使用Class对象直接new对象
方式二:使用构造器创建对象
package com.banbeitai.reflect.Demo2;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDate;
public class TestNewInstance {
//使用反射创建对象
@Test
public void createObject() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> forName = Class.forName("com.banbeitai.reflect.demo1.Student");
//通过Class类创建对象
Object instance = forName.newInstance();
System.out.println(instance);
System.out.println("--------通过构造器创建对象---------");
Constructor<?> constructor = forName.getConstructor();
Object newInstance = constructor.newInstance();
System.out.println(newInstance);
System.out.println("--------通过有参构造器创建对象---------");
Constructor<?> nameConstructor = forName.getConstructor(String.class, LocalDate.class);
Object paramConstructor = nameConstructor.newInstance("小米", LocalDate.now());
System.out.println(paramConstructor);
System.out.println("---------------获取私有构造器---------------------");
Constructor<?> privateonstructor = forName.getDeclaredConstructor(String.class);
//开启获取私有修饰内容的权限
privateonstructor.setAccessible(true);
Object privateObj = privateonstructor.newInstance("小军");
System.out.println(privateObj);
}
}
2.2 为对象的属性赋值,以及获取对应属性的值
方法 | 含义/解释 |
---|---|
set(Object obj, Object value) | 为成员属性设置值,参数介绍:第一个参数是对象,第二参数是属性的值(Field) |
Object get(Object obj) | 获取某个属性的值,参数介绍:对象 |
setAccessible(true) | 开启访问权限,true为可以访问 |
package com.banbeitai.reflect.Demo2;
import org.junit.Test;
import java.lang.reflect.Field;
import java.time.LocalDate;
public class TestField {
@Test
public void getField() {
//(1)获取某个类型的Class对象
try {
Class clazz = Class.forName("com.banbeitai.reflect.demo1.Student");
Object newInstance = clazz.newInstance();
Field field = clazz.getDeclaredField("name");
Field localDate = clazz.getDeclaredField("localDate");
localDate.setAccessible(true);
field.setAccessible(true);
field.set(newInstance, "小军");
localDate.set(newInstance, LocalDate.now());
System.out.println(newInstance);
Object obj = field.get(newInstance);
System.out.println(obj);
System.out.println(localDate.get(newInstance));
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.3 得到所有公共的方法/私有方法 Method类
package com.banbeitai.reflect.Demo3;
import java.lang.reflect.Method;
public class TestFastMethod {
public static void main(String[] args) throws Exception {
//(1)获取Class对象:四种方式之一
Class clazz = Class.forName("com.banbeitai.reflect.demo1.Student");
//(2)得到方法Method对象
//例如:得到void setInfo(String info)方法
/*
* (1)Method clazz.getMethod(name, parameterTypes):得到公共的方法
* (2)Method clazz.getDeclaredMethod(name, parameterTypes):得到声明的方法
* 一个类中方法是可能重载,如何定位到某一个方法 方法名 + 形参列表
*/
Method method = clazz.getDeclaredMethod("getInfo", String.class);
//(3)调用方法
/*
* 静态方法:
* 类名.方法(【实参列表】)
* 非静态方法
* 对象名.方法(【实参列表】)
*/
//创建对象
Object obj = clazz.newInstance();
//调用方法
method.invoke(obj, "半杯态");
System.out.println(obj);
//获取public static void
Method testMethod = clazz.getDeclaredMethod("test", int.class);
//调用方法
testMethod.invoke(null, 10);
}
}