迟早有一天,我要拿到唯一的发问权
—— 24.6.23
一、class对象以及反射介绍
1.反射概述:
解剖class对象的一个技术
2.问题:
能解剖class对象的啥呢?
a.解剖出成员变量 :赋值
b.解剖出成员方法:调用
c.解剖出构造方法:new对象
3.用反射的好处:
让代码变的更通用,更灵活
4.怎么学反射:
a.将反射看成是一套API来学
b.通过案例,体会反射的好处
5.问题:反射第一步:
获取Class对象
6.class对象:
class文件对应的对象
class类:描述class对象的类叫做class类
二、反射之获取Class对象
1.方式1:调用Object中的getClass方法
Class <?> getClass()
2.方式2:不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class
3.方式3:Class类中的静态方法
static Class<?> forName(String className)
className:传递的是类的全限定名(包名.类名)
写类的全限定名小技巧
a、如何快速写类的全限定名
① 直接复制粘贴
② 直接写类名 然后 回车
b、如何检测类的全限定名写正确与否?
按住ctrl不放,鼠标点击此类名,能跳到对应的类中,就证明写的全限定名是对的
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name,Integer age) {
this.age = age;
this.name = name;
}
// 私有构造
private Person(String name){
this.name = name;
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import org.junit.Test;
public class Demo333GetClass {
@Test
public void get1() throws Exception {
Person person = new Person();
Class<? extends Person> aClass = person.getClass();
System.out.println("aClass = " + aClass);
System.out.println("————————————————————————————————————");
// 方式二:不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class
Class<Person> aClass1 = Person.class;
System.out.println("aClass1 = " + aClass1);
System.out.println("————————————————————————————————————");
// 方式三:Class类中的静态方法 static Class<?> forName(String className),传递的是类的全限定名(包名.类名)
Class<?> aClass2 = Class.forName("S112Reflect.Person");
System.out.println("aClass2 = " + aClass2);
// class对象只有一个
System.out.println(aClass==aClass1);
System.out.println(aClass==aClass2);
System.out.println(aClass1==aClass2);
}
}
4.最通用获取Class对象的方式
1.方式3:class类中的静态方法:
static Class<?> forName(String className)
ClassName:传递的是类的全限定名(包名.类名)
2.原因:
参数为String形式,可以和properties文件结合使用
className=AllWillBest_Java.S112Reflect.Student
import java.io.FileInputStream;
import java.util.Properties;
public class Demo334GetClass2 {
public static void main(String[] args)throws Exception {
Properties properties = new Properties();
FileInputStream in = new FileInputStream("Pro.properties");
properties.load(in);
String className = properties.getProperty("className");
System.out.println(className);
Class<?> aClass = Class.forName("Pro.properties");
System.out.println("aClass = " + aClass);
}
}
5.开发中最常用的是哪一种
直接类名.class -> 最方便使用
三、反射构造方法
1.获取所有public的构造方法
Class类中的方法:
Constructor <?>[] getConstructors() ——> 获取所有public的构造
import java.lang.reflect.Constructor;
public class Demo335GetConstructor {
public static void main(String[] args) {
// 获取Class对象
Class<Person> aClass = Person.class;
// 获取所有public的构造
Constructor<?>[] constructors = aClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
}
}
2.获取空参构造 _public
1.Class类中的方法:
Constructor<T> getconstructor(class<?>...parameterTypes) ——> 获取指定的public的构造
parameterTypes:可变参数,可以传递0个或多个参数
a、如果获取的是空参构造:参数不用写
b、如果获取的是有参构造:参数写参数类型的class对象
import java.lang.reflect.Constructor;
public class Demo335GetConstructor {
public static void main(String[] args) {
// 获取Class对象
Class<Person> aClass = Person.class;
// 获取所有public的构造
Constructor<?>[] constructors = aClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
}
}
2.Constructor类中的方法
T newInstance(object...initargs) ——> 创建对象
initargs:传递的是构造方法的实参
a.如果根据无参构造new对象,initargs不写了
b.如果根据有参构造new对象,initargs传递实参
import java.lang.reflect.Constructor;
public class Demo336GetConstructor {
public static void main(String[] args) throws Exception {
// 获取class对象
Class<Person> aClass = Person.class;
Constructor<Person> constructor = aClass.getConstructor();
System.out.println("Person constructor: " + constructor);
// 空参构造,好比是Person person = new Person()
Person person = constructor.newInstance();
// 好比是直接输出对象名,默认调用toString
System.out.println(person);
}
}
3.利用空参构造创建对象的快捷方式_public
Class类中的方法:
T newInstance() ——> 根据空参构造创造对象
前提:被反射的类中必须有public的空参构造
public class Demo337GetConstructor {
public static void main(String[] args)throws Exception {
// 获取Class对象
Class<Person> aClass = Person.class;
Person person = aClass.newInstance();
System.out.println(person);
}
}
3.利用反射获取有参构造并创建对象_public
1.Class类中的方法:
Constructor<T> getconstructor(class<?>...parameterTypes) ——> 获取指定的public的构造
parameterTypes:可变参数,可以传递0个或多个参数
a、如果获取的是空参构造:参数不用写
b、如果获取的是有参构造:参数写参数类型的class对象
2.Constructor类中的方法
T newInstance(object...initargs) ——> 创建对象
initargs:传递的是构造方法的实参
a.如果根据无参构造new对象,initargs不写了
b.如果根据有参构造new对象,initargs传递实参
import java.lang.reflect.Constructor;
public class Demo338GetConstructor {
public static void main(String[] args) throws Exception{
// 获取class对象
Class<Person> aClass = Person.class;
Constructor<Person> constructor = aClass.getConstructor(String.class, Integer.class);
System.out.println("constructor: " + constructor);
// 创建对象 好比是Person person = new Person("小明",25);
Person person = constructor.newInstance("小明", 25);
// 好比是直接输出Person对象,直接调用toString
System.out.println(person);
}
}
4.利用反射获取私有构造(暴力反射)
1.Constructor<?>[] getDeclaredconstructors() —— 获取所有构造方法,包括private
2.Constructor<T> getDeclaredConstructor(类><?>...parameterTypes) —— 获取指定构造,包括private
parameterTypes:参数类型的class对象
3.Constructor有一个父类叫做Accessibeobject,里面有一个方法
void setAccessible(boolean fag) ——> 修改访问权限
flag为true:解除私有权限
import java.lang.reflect.Constructor;
public class Demo339GetConstructor {
public static void main(String[] args)throws Exception{
Class<Person> aClass = Person.class;
// 获取所有的class对象,包括private
Constructor<?>[] dc = aClass.getDeclaredConstructors();
for (Constructor<?> c : dc) {
System.out.println(c);
}
// 获取指定class对象,包括private
Constructor<Person> dC = aClass.getDeclaredConstructor(String.class);
System.out.println(dC);
// Constructor有一个父类叫做Accessibeobject,里面有一个方法,void setAccessible(boolean fag) ——> 修改访问权限
Constructor<Person> DC = aClass.getDeclaredConstructor(String.class);
DC.setAccessible(true); // 接触私有权限 ——> 暴力反射
System.out.println(DC);
Person person = DC.newInstance("小明");
System.out.println(person);
}
}
![](https://img-blog.csdnimg.cn/direct/afac5b7ba0a64bf9a4a608e6dee58274.png)
四、反射成员方法
1.利用反射获取所有成员方法_public
1.Class类中方法:
Method[] getMethods() ——> 获取所有public的方法,包括父类中的public方法
import java.lang.reflect.Method;
public class Demo340GetConstructor {
public static void main(String[] args)throws Exception{
method01();
}
// 获取所有的public方法
private static void method01(){
Class<Person> aClass = Person.class;
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
2.反射之获取方法(有参,无参)_public
1.Class类中的方法:
Method getMethod(string name, class<?>... parameterTypes) ——> 获取指定的public的成员方法
name:传递方法名
parameterTypes:方法参数类型的class对象
2.调用方法Method对象中的方法:
object invoke(object obj,object...args) ——> 执行方法
obj:根据构造new出来的对象
args:方法实参 ——> 如果有参数,直接传递实参,否则不用传
返回值:object ——> 接收被执行方法的返回值,如果方法没有返回值,不用接收了
import java.lang.reflect.Method;
public class Demo340GetConstructor {
public static void main(String[] args)throws Exception{
method02();
}
// 获取指定的public方法
private static void method02() throws Exception {
Class<Person> aClass = Person.class;
// 创建对象
Person person = aClass.newInstance();
Method setName = aClass.getMethod("setName", String.class);
System.out.println(setName);
setName.invoke(person,"小明");
System.out.println(person); // 好比调用同String
System.out.println("——————————————————————————————————");
// 反射一个get方法
Method getName = aClass.getMethod("getName");
// 好比是person.getName() 有返回值,用变量接收
Object name = getName.invoke(person);
System.out.println(name);
}
}
3.反射之操作私有方法
1.Methodll getDecaredMethods() ——> 获取所有的成员方法,包括private 的
2.Method getDeclaredethod(string name,类<?>...parameterTypes) ——> 获取执行成员方法,包括private
name:传递方法名
parameterTypes:方法参数类型的class对象
3.解除私有权限:void setAccessible(boolean flag)
获取所有成员方法
import java.lang.reflect.Method;
public class Demo340GetConstructor {
public static void main(String[] args)throws Exception{
method03();
System.out.println("——————————————————————————————————");
}
// 获取所有成员方法,包括private
private static void method03() {
Class<Person> aClass = Person.class;
Method[] dm = aClass.getDeclaredMethods();
for (Method method : dm) {
System.out.println(method);
}
}
}
获取执行成员方法
import java.lang.reflect.Method;
public class Demo340GetConstructor {
public static void main(String[] args)throws Exception{
method04();
}
// 反射指定方法,包括private
private static void method04() throws Exception {
Class<Person> aClass = Person.class;
Person person = aClass.newInstance();
Method method = aClass.getDeclaredMethod("eat");
method.setAccessible(true);
method.invoke(person);
}
}
五、反射成员变量
1.获取所有属性
Class类中的方法:
1.Field[] getFields() ——> 获取所有public的属性
2.Field[] getDeclaredFields() ——> 获取所有属性,包括private的
import java.lang.reflect.Field;
public class Demo341GetField {
public static void main(String[] args) {
method01();
System.out.println("——————————————————————————————");
method02();
}
/**
* 1.Field[] getFields() ——> 获取所有public的属性
* 2.Field[] getDeclaredFields() ——> 获取所有属性,包括private的
*/
private static void method02() {
Class<Student> studentClass = Student.class;
Field[] df = studentClass.getDeclaredFields();
for (Field f : df) {
System.out.println(f);
}
}
private static void method01() {
Class<Student> studentClass = Student.class;
Field[] fields = studentClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
2.获取指定属性
Class类中的方法:
1.Field getField(String name) ——> 获取指定public的属性
2.Field getDeclaredField(String name) ——> 获取指定属性,包括private的
Field类中的方法:
3.void set(object obj,object value) ——> 为属性赋值,相当于javabean中的set方法
obj:对象
value:赋予的值
4.Object get(Object obj) ——> 获取属性值
obj:对象
import java.lang.reflect.Field;
public class Demo341GetField {
public static void main(String[] args) throws Exception {
method01();
System.out.println("——————————————————————————————");
method02();
System.out.println("——————————————————————————————");
method03();
System.out.println("——————————————————————————————");
method04();
}
private static void method04() throws Exception {
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
Field name = studentClass.getDeclaredField("name");
// 解除私有权限
name.setAccessible(true);
// 调用set方法为属性赋值
name.set(student,"小明");
// 调用get方法获取属性值
Object o = name.get(student);
System.out.println(o);
}
/**
* 3.void set(object obj,object value) ——> 为属性赋值,相当于javabean中的set方法
* obj:对象
* value:赋予的值
* 4.Object get(Object obj) ——> 获取属性值
* obj:对象
*/
private static void method03() throws Exception {
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
Field age = studentClass.getField("age");
// 调用set方法为属性赋值
age.set(student,10);
// 调用get方法获取属性值
Object o = age.get(student);
System.out.println(o);
}
/**
* 1.Field[] getFields() ——> 获取所有public的属性
* 2.Field[] getDeclaredFields() ——> 获取所有属性,包括private的
*/
private static void method02() {
Class<Student> studentClass = Student.class;
Field[] df = studentClass.getDeclaredFields();
for (Field f : df) {
System.out.println(f);
}
}
private static void method01() {
Class<Student> studentClass = Student.class;
Field[] fields = studentClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
六、反射练习(编写一个小框架)
需求:
在配置文件中,配置类的全限定名,以及配置一个方法名,通过解析配置文件,让配置好的方法执行起来
className=包名.Person
methodName=eat
步骤:
1.创建properties配置文件,配置信息
a.问题:properties配置文件放到哪里?
答:将来我们开发完之后给用户的是out路径下的class文件,将class文件打包, 如果将配置文件直接放到模块下那么out路径下是不会生成这个配置文件的,如果没有配置文件,程序也就运行不起来了
解决:我们可以将配置文件放到src下,放到src下,out路径下就会出现配置文件
b.问题:将配置文件放到src下,out路径下会自动生成配置文件,但是如果我们将来将所有的配置文件都放到src下,那么src下面会显得特别乱
解决:我们可以单独创建一个文件夹,将所有的配置文件放到此文件夹下,将此文件夹改成资源目录,取名为resources
配置文件
className=S114ReflectExample.Person
methodName=eat
2.读取配置文件,解析配置文件
a.问题:如果将配置文件放到resources资源目录下,我们怎么读取?
new FileInputstream("模块名\\resources\\properties文件名") ——> 这样不行,out路径下没有resources ——> 相当于写死了
b.问题解决:用类加载器
ClassLoader classLoader = 当前类.class.getclassLoader()
Inputstream in = classLoader.getResourceAsstream("文件名")//自动扫描resources下的文件 ——> 可以简单理解为扫描out路径下的配置文件
3.根据解析出来的className,创建Class对象
4.根据解析出来的methodName,获取对应的方法
5.执行方法
public class Person {
public void eat(){
System.out.println("人要吃饭");
}
}
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class Demo342Reflect {
public static void main(String[] args) throws Exception {
// 1.创建properties集合
Properties properties = new Properties();
// 2.读取配置文件,解析配置文件
InputStream in = Demo342Reflect.class.getClassLoader().getResourceAsStream("Pro.properties");
properties.load(in);
// System.out.println(properties);
// 3.根据解析出来的className,创建class对象
// 4.根据解析出来的methodName,获取相应的方法
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
Class<?> aClass = Class.forName(className);
Object o = aClass.newInstance();
Method method = aClass.getMethod(methodName);
// 5.执行方法
method.invoke(o);
}
}
修改配置文件
className=S114ReflectExample.Person
methodName=sleep
public class Person {
public void eat(){
System.out.println("人要吃饭");
}
public void sleep(){
System.out.println("人要睡觉");
}
}