1 反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)
1.1 获取Class对象方式:
// 方式1 通过对象获取Class对象
Student stu = **new** Student();
Class c1 = stu.getClass();
System.***out\***.println(c1);
// 方式2 直接根据类名获取
Class c2 = Student.**class**;
Class c4 = Student.**class**;
// 方式3 根据类的包名+类名的字符串获取 推荐
Class c3 = Class.*forName*("com.qfedu.reflect.Studen");
// true 类的类对象是唯一的
System.***out\***.println(c1 == c2);
System.***out\***.println(c2 == c3);
1.2 常用方法
// 获取类中构造方法,公共的
getConstructors();
// 获取所有的构造方法,包括公开的私有的。。。
getDeclaredConstructors();
// 获取类中公开的方法,包括继承的父类的方法
getMethods();
c.getDeclaredMethods();
// 获取类中公开的属性
getFields();
getDeclaredFields();
public class ClassApp2 {
public static void main(String[] args) throws ClassNotFoundException {
// TODO Auto-generated method stub
Class c = Class.forName("com.qfedu.reflect.Student");
// 获取类中构造方法,公共的
Constructor[] constructors = c.getConstructors();
for(Constructor con : constructors) {
System.out.println(con.getName());
}
System.out.println("----------------------");
// 获取所有的构造方法,包括公开的私有的。。。
Constructor[] declaredConstructors = c.getDeclaredConstructors();
for(Constructor con : declaredConstructors) {
System.out.println(con);
}
System.out.println("----------------------");
// 获取类中公开的方法,包括继承的父类的方法
Method[] methods = c.getMethods();
for(Method m : methods) {
System.out.println(m);
}
// c.getDeclaredMethods();
System.out.println("----------------------");
// 获取类中公开的属性
Field[] fields = c.getFields();
for(Field f : fields) {
System.out.println(f);
}
Field[] fields2 = c.getDeclaredFields();
for(Field f : fields2) {
System.out.println(f);
}
}
}
1.3 通过反射创建对象
public class ClassApp3 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Class c = Class.forName("com.qfedu.reflect.Student");
// 通过Class对象 创建指定类的对象 ,相当于调用了默认的构造方法,创建了一个Student对象
Object object = c.newInstance();
// Student s = (Student)object;
// s.setName("haha");
// System.out.println(s.getName());
// Method对象 是对方法信息的封装
Method method = c.getMethod("setName", String.class);
// 通过反射技术调用对象中的方法, 相当于 student.setName("zhangsan");
// 第一个参数,类的对象(本例中object指的是Student的对象)
// 第二个参数,给方法传的参数
method.invoke(object, "zhangsan");
Student s = (Student)object;
System.out.println(s.getName());
}
}
2 Calendar类
常用方法:
获取日历对象:Calendar.getInstance()
获取年月日等信息: get()
设置年月日等信息:set()
日期的计算:add()
public class CalendarApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 获取日历类的对象
Calendar calendar = Calendar.getInstance();
System.out.println(calendar);
// 年
System.out.println(calendar.get(Calendar.YEAR));
// 月 范围0-11 值+1,是真正的月份
System.out.println(calendar.get(Calendar.MONTH) + 1);
// 日
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
// 时
System.out.println(calendar.get(Calendar.HOUR));
// 分
System.out.println(calendar.get(Calendar.MINUTE));
// 秒
System.out.println(calendar.get(Calendar.SECOND));
// 设置年月日时分秒
calendar.set(2021, 4, 12, 13, 20, 20);
System.out.println(calendar.get(Calendar.YEAR));
// 具体设置某个属性
calendar.set(Calendar.MONTH, Calendar.MARCH);
System.out.println(calendar.get(Calendar.MONTH));
System.out.println("---------------------------");
// 日历类 -》 Date
Date date = calendar.getTime();
System.out.println(date);
// Date -> Calendar
Date date2 = new Date(1615969254000L);
calendar.setTime(date2);
System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
System.out.println("-----------------");
// 针对具体的属性 加减运算
calendar.add(Calendar.MONTH, 1);
System.out.println(calendar.get(Calendar.MONTH));
calendar.add(Calendar.HOUR_OF_DAY, -1);
System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
}
}
反射方法
1.Constructor
1.1 获取公开的构造器
获取类信息对象中所有的public修饰的构造方法
getConstructor(Class<?>... parameterType) 根据参数列表获取到一个public修饰的构造器对象
getConstructors() 获取到所有的public修饰的构造器对象
package com.qfedu.test1;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 通过反射获取类对象
*
* 获取类信息对象中所有的public修饰的构造方法
* getConstructor(Class<?>... parameterType) 根据参数列表获取到一个public修饰的构造器对象
* getConstructors() 获取到所有的public修饰的构造器对象
* @author WHD
*
*/
public class Test1 {
public static void main(String[] args) {
// 包名 + 类名 称之为 全限定名 com.qfedu.test1.Student
try {
Class<?> stuClass = Class.forName("com.qfedu.test1.Student");
Constructor<?>[] cons = stuClass.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con.getName() + "----" + con.getParameterCount());
}
Constructor<?> con1 = stuClass.getConstructor();
Object obj1 = con1.newInstance();
if(obj1 instanceof Student) {
Student stu1 = (Student) obj1;
stu1.setName("赵四");
stu1.setAge(20);
System.out.println(stu1);
}
Constructor<?> con2 = stuClass.getConstructor(String.class,int.class);
Object obj2 = con2.newInstance("广坤",17);
if(obj2 instanceof Student ) {
Student stu2 = (Student) obj2;
System.out.println(stu2);
}
Constructor<?> con3 = stuClass.getConstructor(int.class,String.class);
Object obj3 = con3.newInstance(17,"大拿");
if(obj3 instanceof Student) {
Student stu3 = (Student) obj3;
System.out.println(stu3);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
1.2 获取所有的构造器
getDeclaredConstructor(Class<?>... parameterType) 根据形参列表获取某一个任意修饰符修饰的构造器
getDeclaredConstructors() 获取所有已定义的任意修饰符修饰的构造器
package com.qfedu.test1;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* getDeclaredConstructor(Class<?>... parameterType) 根据形参列表获取某一个任意修饰符修饰的构造器
* getDeclaredConstructors() 获取所有已定义的任意修饰符修饰的构造器
* @author WHD
*
*/
public class Test2 {
public static void main(String[] args) {
try {
// 通过包名+类名 获取到类对象
Class<?> stuClass = Class.forName("com.qfedu.test1.Student");
// 获取所有已定义构造器
Constructor<?>[] cons = stuClass.getDeclaredConstructors();
// 遍历数组
for (Constructor<?> con : cons) {
System.out.println(con.getName() + "---" + con.getParameterCount());
}
// 获取单个的已定义的<默认修饰符>修饰的构造器
Constructor<?> con1 = stuClass.getDeclaredConstructor(String.class);
// 根据获取到构造器对象 调用newInstance方法创建对象
Object obj1 = con1.newInstance("赵四");
// 进行类型判断
if(obj1 instanceof Student) {
Student stu = (Student) obj1;
System.out.println(stu);
}
// 获取单个的已定义的<私有修饰符>修饰的构造器
Constructor<?> con2 = stuClass.getDeclaredConstructor(int.class);
// 设置con2构造器对象为可以访问 忽略调JVM的安全检查
con2.setAccessible(true); // 设置为可访问
// 创建对象
Object obj2 = con2.newInstance(17);
//类型判断
if(obj2 instanceof Student) {
Student stu = (Student) obj2;
System.out.println(stu);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
2. Field
2.1 获取公开的字段
使用反射获取public修饰的属性
getFiled(String filedName) 根据字段名称获取一个public修饰的属性
getFileds() 获取所有的public修饰的属性 返回值为Field数组
package com.qfedu.test2;
import java.lang.reflect.Field;
/**
* 使用反射获取public修饰的属性
* getFiled(String filedName) 根据字段名称获取一个public修饰的属性
* getFileds() 获取所有的public修饰的属性 返回值为Field数组
* @author WHD
*
*/
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
Class<?> stuClass = Class.forName("com.qfedu.test2.Student");
Field[] fields = stuClass.getFields();
for (Field f : fields) {
System.out.println(f.getName() + "---" + f.getType());
}
// 根据名字获取某一个public修饰的字段/属性/实例变量
Field nameField = stuClass.getField("name");
// 根据Class类提供的方法 来获取学生对象
Object obj1 = stuClass.newInstance(); // Student stu = new Student();
// 对字段对象赋值
nameField.set(obj1, "赵四"); // stu.setName("赵四");
// 取值
System.out.println(nameField.get(obj1)); // stu.getName();
}
}
2.2 获取所有的字段
获取已定义的字段
getDeclaredField(String name) 获取单个任意修饰符修饰的字段
getDeclaredFields() 获取所有任意修饰符修饰的字段
package com.qfedu.test2;
import java.lang.reflect.Field;
/**
* 获取已定义的字段
* getDeclaredField(String name) 获取单个任意修饰符修饰的字段
* getDeclaredFields() 获取所有任意修饰符修饰的字段
* @author WHD
*
*/
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
Class<?> stuClass = Class.forName("com.qfedu.test2.Student");// shift + alt + L
Field[] fields = stuClass.getDeclaredFields(); // shift + alt + L
for (Field f : fields) {
System.out.println(f.getName() + "---" + f.getType());
}
// 获取单个的非public修饰的属性
Field field1 = stuClass.getDeclaredField("sex");
// 使用Class类调用无参构造创对象
Object obj1 = stuClass.newInstance();
// 设置值
// 第一个参数 表示要设置的字段属于哪个对象
// 第二个参数 字段值
field1.set(obj1, "男");
// 获取值
System.out.println(field1.get(obj1));
// 获取private修饰的字段
Field field2 = stuClass.getDeclaredField("weight");
field2.setAccessible(true);
field2.set(obj1, 75.5);
System.out.println(field2.get(obj1));
}
}
3. Method
3.1 获取公开的以及继承的方法
获取public修饰的方法
getMethods() 获取所有的public修饰的,以及从父类继承的方法
getMethod(String name,Class<?>... paratemerType)根据方法名称和参数列表获取到一个public
修饰的方法
package com.qfedu.test3;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 获取public修饰的方法
* getMethods() 获取所有的public修饰的,以及从父类继承的方法
* getMethod(String name,Class<?>... paratemerType)根据方法名称和参数列表获取到一个public
* 修饰的方法
* @author WHD
*
*/
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<?> stuClass = Class.forName("com.qfedu.test3.Student");
Method[] methods = stuClass.getMethods();
for (Method m : methods) {
System.out.println(m.getName() + "---" + m.getParameterCount());
}
// 获取单个的方法
Method method1 = stuClass.getMethod("m1");
Object obj1 = stuClass.newInstance();
method1.invoke(obj1);
Method method2 = stuClass.getMethod("m1", String.class,int.class);
method2.invoke(obj1, "hello",20);
}
}
package com.qfedu.test3;
public class Student {
public void m1() {
System.out.println("public修饰的m1方法 无参的");
}
public void m1(String str,int num) {
System.out.println("public修饰的m1方法 有参数的String,int" + str + num);
}
public void m2(){
System.out.println("public修饰的m2方法");
}
void m3() {
System.out.println("包级别访问权限的m3方法");
}
private void m4() {
System.out.println("私有级别的m4方法");
}
private void m4(float num) {
System.out.println("私有级别的m4方法 float参数" + num);
}
}
3.2 获取所有的方法
获取已定义的方法(不包含继承的方法)
getDeclaredMethod(String name,Class<?>...parameterType) 获取单个已定义的方法
getDeclaredMethods() 获取所有已定义的方法
package com.qfedu.test3;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 获取已定义的方法(不包含继承的方法)
* getDeclaredMethod(String name,Class<?>...parameterType) 获取单个已定义的方法
* getDeclaredMethods() 获取所有已定义的方法
* @author WHD
*
*/
public class Test2 {
public static void main(String[] args) {
try {
Class<?> stuClass = Class.forName("com.qfedu.test3.Student");
Method[] methods = stuClass.getDeclaredMethods();
for (Method m : methods) {
System.out.println(m.getName() + "----" + m.getParameterCount());
}
// 获取单个的方法
Method m1 = stuClass.getDeclaredMethod("m3");
Object obj1 = stuClass.newInstance();
m1.invoke(obj1);
Method m2 = stuClass.getDeclaredMethod("m4",float.class);
m2.setAccessible(true);
m2.invoke(obj1, 3.14F);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
3. 反射再识
3.1 Java类和Java文件的关系
Java中的类,一定会存在于Java文件中。
【重点】
Java文件包含对应类的所有内容。
定义类的格式:
class 类名 {
成员变量;
构造方法;
成员方法;
}
3.2 .class文件和Java文件的关系
Java文件 ==> Javac.exe 编译之后 ==> .class 字节码文件/二进制文件
【重点】
.class文件中包含Java中的类所有内容
.class字节码文件中会包含当前 类 所有参与代码编译和执行的内容,不包括注释
3.3 类文件加载做什么
在Java程序运行之前,将.class字节码文件,加载到内存的【方法区】
【重点】
在内存方法区中,.class文件占用的空间,包含.class对应的所有内容。
代码执行过程中,需要使用对应类的内容(成员变量,成员方法,构造方法,类型提供),都要使用内存【方法区】.class文件占用的空间。
3.4 .class字节码文件占用的内存空间和Java类有什么关系???
.class字节码文件在内存【方法区】占用空间,是Java类对应内容的完整映射。
一个是程序员可以看懂,一个是计算机可以看懂。
成员变量看作一个类,你认为有什么属性?
1. 数据类型 [核心] Type
2. 变量名 【重点核心】 name
3. 数据内容
4. 权限修饰标记
5. 静态标记
6. final标记
成员方法看作是一个类,有什么属性?
1. 权限修饰标记
2. 静态标记
3. 返回值类型 [核心]
4. 方法名 【核心重点】
5. 形式参数列表 [核心]
6. 方法体
构造方法看做是一个类,有什么属性?
1. 权限修饰标记
2. 类名 [核心]
3. 形式参数列表 【核心重点】
4. 方法体
类也是一个类
Field[] 成员变量数组
Constructor[] 构造方法数组
Method[] 成员方法数组
实操案例
文件存储数据
className=com.qfedu.entity.Person
[id:1,name:苟磊,age=16,gender=false]
[id:2,name:狗鸽,age=16,gender=false]
1. 从文件中读取数据
2. 字符串解析
3. 通过反射获取指定名字的成员变量 Field对象
4. 通过该Field对象数据类型,转换 String 数据 到对应数据类型从【字符串转任意类型的转换器】
5. 生成一个 Person 类对象
4.1 复习
Java的类 ==> Java文件 ==> javac.exe ==> .class文件 ==> 加载 ==> 内存方法区有一块空间对应 .class文件
内存方法区 .class字节码文件占用的内存空间 ==> 对应 整个Java类,包含对应Java类的所有内容。
类也是一个类 Class类型 ==> 完整的类名 包名.类名
成员变量是一个类 Field类 ==> 变量名
成员方法是一个类 Method类 ==> 方法名 参数
构造方法是一个类 Constructor类 ==> 参数
1.2 万恶之源 -- Class类
Class类 是针对Java中所有类对应总结
Class类对应的对象 ===> 每一个类在内存方法区.class文件占用的内存空间 就是Class对象。
Person.java ===> Person.class ==> 加载到内存【方法区】 ==> Class<Person>对象
获取Class对象对应的方法:
Class Class.forName(String packageAndClassName);
根据提供的包名.类名获取对应类的Class对象
【特殊功能】可以用于加载指定包名.类名对应的类
【常用用途】指定类型获取,指定类型加载
例如:
Class cls = Class.forName("com.qfedu.entity.Student");
Student.java ==> Student.class
Class getClass();
通过类对象调用,获取当前对象对应的Class对象
【常用用途】用于获取类对象对应类型,参与判断
例如:
Student stu = new Student();
Class cls = stu.getClass();
Class 类名.class;
通过类名,获取当前类Class对象,或者可以理解为获取当前类的Class属性
【常用用途】用于约束方法参数类型。
例如:
Class cls = Student.class;
package com.qfedu.a_reflect;
/*
* 获取Class对象方法演示
*
* 异常说明:
* ClassNotFoundException 指定类未找到异常
*/
public class GetClassObject {
public static void main(String[] args) throws ClassNotFoundException {
/*
* 根据指定包名.类名 获取对应类的Class对象
*/
Class<?> cls1 = Class.forName("com.qfedu.a_reflect.Person");
/*
* 通过类对象,获取对应数据类型 Class对象
*/
Person person = new Person();
Class<? extends Person> cls2 = person.getClass();
/*
* 根据类名获取 Class对象。 或者说,根据类名获取Class属性
*/
Class<Person> cls3 = Person.class;
/*
* 杰总 20遍 三个 true
*
* 问题:
* 一个类加载几次???
* 一次
* 类加载一次的情况下,占用的内存【方法区】空间是否也是一次???
* 一次
* Class对象是对应当前.class字节码文件在内存方法区中的占用空间对象。
*
* 不管通过哪一种方式获取的Class对象,类相同的情况下,都是同一个对象
*/
System.out.println("cls1 == cls2 : " + (cls1 == cls2));
System.out.println("cls2 == cls3 : " + (cls2 == cls3));
System.out.println("cls1 == cls3 : " + (cls1 == cls3));
}
}
1.3 通过Class对象获取Constructor构造方法对象
1.3.1 获取Constructor分析
构造方法:
具有唯一性的内容是什么???
方法名??? No 可以存在多个构造方法,名称都一样,都是类名。
参数类型,个数,顺序是不是唯一性???
唯一!!!
方法的重载!!!reload
在一个类内,允许出现同名方法,但是要求方法对应的参数必须不一致!!!
获取构造方法,需要根据构造方法的数据类型,个数,顺序来获取!!!
Objects.hash(Object... value);
1.3.2 获取Constructor相关方法
Constructor[] getConstructors();
获取当前Class对象中,所有非私有化构造方法 Constructor 对象数组
Constructor[] getDeclaredConstructors();
【暴力反射】
获取当前Class对象中,所有构造方法 Constructor 对象数组,包括私有化构造方法对象。
Constructor getConstructor(Class... parameterTypes);
参数解释:
Class... parameterTypes
不定长参数,参数类型是Class类型,用于约束当前构造方法对应的数据类型是什么
根据指定的参数类型,获取对应非私有化构造方法 Constructor 对象
例如:
Constructor con1 = cls.getConstructor();
con1 ==> public Person() 无参数构造方法
Constructor con2 = cls.getConstructor(int.class, String.class);
con2 ==> public Person(int, String); 对应的构造方法参数为 int,String 类型
Constructor getDeclaredConstructor(Class... parameterTypes);
【暴力反射】
参数解释:
Class... parameterTypes
不定长参数,参数类型是Class类型,用于约束当前构造方法对应的数据类型是什么
根据指定的参数类型,获取对应构造方法 Constructor 对象,包括私有化构造方法。
例如:
Constructor con1 = cls.getDeclaredConstructor(String.class);
con1 ==> private Person(String); 私有化参数类型为String类型的构造方法。
package com.qfedu.a_reflect;
import java.lang.reflect.Constructor;
/*
NoSuchMethodException 指定方法不存在异常
SecurityException 安全异常
*/
public class GetConstructorObject {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, SecurityException {
/*
* 有请万恶之源
*/
Class cls = Class.forName("com.qfedu.a_reflect.Person");
/*
Constructor[] getConstructors();
获取当前Class对象中,所有非私有化构造方法 Constructor 对象数组
*/
Constructor[] constructors = cls.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println();
/*
Constructor[] getDeclaredConstructors();
【暴力反射】
获取当前Class对象中,所有构造方法 Constructor 对象数组,包括私有化构造方法对象
*/
Constructor[] declaredConstructors = cls.getDeclaredConstructors();
for (Constructor constructor : declaredConstructors) {
System.out.println(constructor);
}
System.out.println();
/*
Constructor getConstructor(Class... parameterTypes);
参数解释:
Class... parameterTypes
不定长参数,参数类型是Class类型,用于约束当前构造方法对应的数据类型是什么
根据指定的参数类型,获取对应非私有化构造方法 Constructor 对象
*/
Constructor con1 = cls.getConstructor();
Constructor con2 = cls.getConstructor(int.class);
Constructor con3 = cls.getConstructor(int.class, String.class);
System.out.println(con1);
System.out.println(con2);
System.out.println(con3);
/*
Constructor getDeclaredConstructor(Class... parameterTypes);
【暴力反射】
参数解释:
Class... parameterTypes
不定长参数,参数类型是Class类型,用于约束当前构造方法对应的数据类型是什么
根据指定的参数类型,获取对应构造方法 Constructor 对象,包括私有化构造方法。
*/
Constructor con4 = cls.getDeclaredConstructor(String.class);
System.out.println(con4);
}
}
1.3.3 通过Constructor对象创建类对象
Object newInstance(Object... parameterValues);
参数解释
Object... parameterValues
当前构造方法所需的实际参数,要求传入的参数和对应参数类型一致,【类型一致,顺序一致,个数一致】
Object... 可以支持任意类型,同时支持任意个数
通过该Constructor对象调用,创建Constructor对应类的对象
例如:
Constructor对象是 Person类,通过调用newInstance创建的对象,也就是Person对象。返回值Object类型
只是为了数据统一操作,可以通过强制类型转换或者泛型约束,明确类型。
1.4 通过Class对象获取Method成员方法对象
1.4.1 获取Method对象分析
Method 成员方法在调用过程中
1. 方法名字
2. 对应当前方法的数据类型[参数个数,参数类型,参数顺序]
明确一个方法所需的内容就是方法名+参数列表
1.4.2 获取Method相关方法
Method[] getMethods();
获取类内所有非私有化方法,并且包含从父类继承而来子类可以使用的非私有化成员方法。
Method[] getDeclaredMethods();
【暴力反射】
获取类内所有的本类自有方法,包含私有化方法,但是不包括继承而来父类的非私有化方法。
Method getMethod(String methodName, Class... parameterTypes);
参数解释:
String methodName 指定方法的名字
Class... parameterTypes 对应当前方法的参数类型,不定长参数,Class类型约束
根据用户指定的方法名称,和对应的参数类型,获取类内指定非私有化成员方法。
例如:
Method method1 = cls.getMethod("game");
method1 ==> public 待定 game();
Method method2 = cls.getMethod("game", String.class);
method2 ==> public 待定 game(java.lang.String);
Method getDeclaredMethod(String methodName, Class... parameterTypes);
【暴力反射】
参数解释:
String methodName 指定方法的名字
Class... parameterTypes 对应当前方法的参数类型,不定长参数,Class类型约束
根据用户指定的方法名称,和对应的参数类型,获取类内指定成员方法。包括私有化方法。
例如:
Method method1 = cls.getMethod("testPrivate");
method1 ==> private 待定 testPrivate();
Method method2 = cls.getMethod("testPrivate", String.class);
method2 ==> private 待定 testPrivate(java.lang.String);
package com.qfedu.a_reflect;
import java.lang.reflect.Method;
/*
* 通过Class对象获取对应类的 Method 成员方法对象演示
*/
@SuppressWarnings("all")
public class GetMethodObject {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, SecurityException {
Class cls = Class.forName("com.qfedu.a_reflect.Person");
/*
Method[] getMethods();
获取类内所有非私有化方法,并且包含从父类继承而来子类可以使用的非私有化成员方法。
*/
Method[] methods = cls.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println();
/*
Method[] getDeclaredMethods();
【暴力反射】
获取类内所有的本类自有方法,包含私有化方法,但是不包括继承而来父类的非私有化方法。
*/
Method[] declaredMethods = cls.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println();
/*
Method getMethod(String methodName, Class... parameterTypes);
参数解释:
String methodName 指定方法的名字
Class... parameterTypes 对应当前方法的参数类型,不定长参数,Class类型约束
根据用户指定的方法名称,和对应的参数类型,获取类内指定非私有化成员方法。
*/
Method method1 = cls.getMethod("game");
Method method2 = cls.getMethod("game", String.class);
System.out.println(method1);
System.out.println(method2);
System.out.println();
/*
Method getDeclaredMethod(String methodName, Class... parameterTypes);
【暴力反射】
参数解释:
String methodName 指定方法的名字
Class... parameterTypes 对应当前方法的参数类型,不定长参数,Class类型约束
根据用户指定的方法名称,和对应的参数类型,获取类内指定成员方法。包括私有化方法。
*/
Method declaredMethod1 = cls.getDeclaredMethod("testPrivate");
Method declaredMethod2 = cls.getDeclaredMethod("testPrivate", String.class);
System.out.println(declaredMethod1);
System.out.println(declaredMethod2);
}
}
1.4.3 Method对象执行对应方法
方法调用格式:
类对象.方法名(实际参数);
类名.方法名(实际参数);
目前已经得到了 Method 对象 ==> 方法
运行/执行当前方法缺什么???
1. 谁调用? 类对象/类名
2. 实际参数
Method执行方法操作
Object invoke(Object obj, Object... parameterValues);
参数解释:
Object obj 执行当前方法使用的对应类对象
Object... parameterValues 当前方法执行所需的实际参数
Method类对象调用执行 invoke 方法,执行当前Method对应方法内容
【补充】
静态成员方法在使用Method方法执行过程中,推荐在调用者位置提供一个当前类对象,明确方法执行的参数问题,
明确方法执行的调用者问题。
Object obj = cls.getConstructor().newInstance();
method1.invoke(obj);
method2.invoke(obj, "World Of Tank");
System.out.println();
declaredMethod1.setAccessible(true);
declaredMethod1.invoke(obj);
declaredMethod2.setAccessible(true);
declaredMethod2.invoke(obj, "猕猴桃");
cls.getMethod("test").invoke(obj); // 静态成员方法通过类对象调用,在语法层面没有任何错误
cls.getMethod("test").invoke(null); // null 表示未提供任何的调用对象,有且只允许在static修饰方法中使用
1.5 通过Class对象获取Field成员变量对象
1.5.1 获取 Field 对象分析
使用成员变量过程中,操作成员变量
1. 变量名
2. 比较关注 变量对应的数据类型。
1.5.2 获取 Field 相关方法
Field[] getFields();
获取当前类内所有非私有化成员变量Field对象数组。
Field[] getDeclaredFields();
【暴力反射】
获取当前类内所有成员变量,包括私有化成员变量。【常用】
Field getField(String fieldName);
根据指定的成员变量名称,获取对应的非私有化成员变量Field对象
Field getDeclaredField(String fieldName);
【暴力反射】
根据指定的成员变量名称,获取对应成员变量Field对象,包括私有化成员变量对象
package com.qfedu.a_reflect;
import java.lang.reflect.Field;
/*
* 通过Class对象获取对应类的Field成员变量对象演示
*/
public class GetFieldObject {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException {
/*
* 万恶之源
*/
Class cls = Class.forName("com.qfedu.a_reflect.Person");
Field[] fields = cls.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println();
Field[] declaredFields = cls.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}
System.out.println();
Field field1 = cls.getField("test");
Field field2 = cls.getField("testStatic");
System.out.println(field1);
System.out.println(field2);
System.out.println();
Field declaredField1 = cls.getDeclaredField("id");
Field declaredField2 = cls.getDeclaredField("name");
System.out.println(declaredField1);
System.out.println(declaredField2);
}
}
1.5.3 Field 对象操作对应方法
操作成员变量的方式
类对象.set成员变量名(对应成员变量数据类型参数);
赋值操作:
1. 明确是哪一个类对象的成员变量
2. 对应当前成员变量数据类型的实际参数
对应当前成员变量参数 类对象.get成员变量名();
取值操作:
明确是哪一个类对象的成员变量
void set(Object obj, Object value);
【赋值操作】
obj 是对应哪一个类对象,value 是对应当前成员变量赋值使用的数据
Object get(Object obj);
【取值操作】
obj 是对应哪一个类对象,返回值是当前成员变量存储的数据。
String getName();
获取成员变量的名称
Class<?> getType();
获取成员变量的数据类型,返回值是Class类型。
1.6 暴力反射授权
Constructor/Field/Method ==> setAccessible(boolean flag);
给予一个反射对象进行权限赋值操作,可以用于【私有化】构造方法,成员方法和成员变量权限授予操作。
主要的操作都是针对于 成员变量
class AccessibleObject
static void setAccessible(AccessibleObject[] arr, boolean flag);
class Constructor extends AccessibleObject
class Field extends AccessibleObject
class Method extends AccessibleObject
给予AccessibleObject数组所有元素,进行权限授予操作,AccessibleObject可以存储Constructor,Field,Method,批量操作。
主要的操作都是针对于 成员变量