前言
感谢大家的观看,如果中间遇到写的有问题的地方,请多多指教
此文章,我是通过尚硅谷的视频进行编写的。我在之后的时间会将此类文章全部编写出来。完成我的java冲刺小专栏。谢谢大家的观看
[硅谷学习路线](2021年度全网最全Java学习路线 - 哔哩哔哩 (bilibili.com))
反射(reflection)
万事万物皆对象:学完反射进一步体会到了。
上面的网络编程连URL都可以做对象。
概念
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个 类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可 以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看 到类的结构,所以,我们形象的称之为:反射。
动态语言VS静态语言
动态语言
是一类在运行时可以改变其结构的语言:
例如新的函数、对象、甚至代码可以 被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运 行时代码可以根据某些条件改变自身结构。
主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。
静态语言
与动态语言相对应的,运行时结构不可变的语言就是静态语言。
如Java、C、 C++。
Java不是动态语言
但Java可以称之为“准动态语言”。即Java有一定的动 态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。 Java的动态性让编程的时候更加灵活!
java反射提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
反射主要的类
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造器
反射我看来都是各种API的操作
通过(Class)(Method)(Field)(构造)等的API来完成运行时的java创建对象,修改属性,运行函数等的操作。
Class类
在Object类中定义了以下的方法,此方法 将被所有子类继承:
public final Class getClass()
该方法可以获取一个Class类,可以通过找个Class类从而获取该类下的属性和方法
获取类实例
想要操作一个类,首先就是获取找个类的类实例
获取Class实例
java程序中获得Class实例通常有如下3中方式,可以根据实际情况灵活选择
调用类或接口实例的getClass()方法
- getClass()方法是java.lang.Object类中的一个方法
- 所有的类和接口的实例都可以调用这个方法,该方法会返回该实例的所数类型所对应的Class实例
//创建一个Student类用来作为反射的演示
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public static void main(String[] args) {
// 创建学生类的对象
Student student = new Student();
// 通过学生类对象获取Class实例
Class aClass = student.getClass();
System.out.println("我是什么类实例:"+aClass.getName());
}
调用类或接口的class属性
- 在某些类或接口没有实例的情况下,可以通过其class属性获得对应的Class实例
- 这种方式需要在编译器就知道类或接口名称
public static void main(String[] args) {
// 直接通过类的静态属性class获取类实例
Class<Student> studentClass = Student.class;
System.out.println("我是什么类实例:"+studentClass.getName());
}
结果同上
使用Class.forName()方法
若编译时候无法确认具体类型,需要程序在运行时候根据情况来加载
可以使用Class类的forName()
该方法是静态方法,需要传入字符串参数,该字符串的参数是某个类的完全限定类名,包括包名(相当于路径了)
public static void main(String[] args) {
try {
// 通过Class类静态方法指定类路径获取指定Student类实例
Class aClass = Class.forName("Reflection.Student");
System.out.println("我是什么类实例:"+aClass.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
获取到类实例之后,可以调用Class方法进行获取类实例的信息
Class的常用方法
方法 | 返回值 | 说明 |
---|---|---|
getName() | String | 以字符串形式返回类型的名称(类名) |
getSimpleName() | String | 一字符串形式返回该类的简称 |
getPackage() | Package | 获取该类所在包 |
getSuperclass() | Class | 返回该类的父类 |
getInterfaces() | Class[] | 返回该类实现的接口 |
getModifiers() | int | 返回该类型所有修饰符 由public,private,protected等对应的int常量组成 返回整数使用Modifier工具进行解码,判断访问修饰符的组成 |
getDeclaredClasses() | Class[] | 返回该类型中包含的全部内部类的Class实例 |
getDeclaringClass() | class | 返回该类型中的外部类的Class实例 |
newInstance | Object | 通过类实例创建对象 |
动态创建对象的两种方式
- 通过类实例的newInstance
- 通过构造函数的newInstance
Modifier(修饰符类)
该类表示的是修饰符类。
每个修饰符都对应Modifier的一个静态常量属性
根据其他反射API的getModifiers()来判断访问修饰符
Constructor(构造函数)
想要创建一个类的对象离不开构造函数。
获取构造函数
我们可以通过Class实例来获取构造函数对象,从而创建对象
返回值 | 方法名 | 说明 |
---|---|---|
Constructor | getConstructor(Class…params) | 返回该类型指定参数列表的public构造函数 构造函数的参数列表为params eg:Constructor co = 类实例.getConstructor(String name,list.class) |
Constructor[] | getConstructors() | 返回该类型的所有public构造方法 |
Constructor | getDeclaredConstructor(Class…params) | 返回该类型指定参数列表的构造函数,返回类型不限 |
Constructor[] | getDeclaredConstructors() | 返回该类型的所有构造函数访问级别不限 |
Constructor的常用方法
方法 | 描述 |
---|---|
public int getModifiers() | //得到构造方法的修饰符 |
public String getName() | //得到构造方法的名称 |
public Class<?>[] getParameterTypes() | //得到构造方法中参数的类型 |
public String toString() | //返回此构造方法的信息 |
public T newInstance(Object.class…initargs) | //向构造方法中传递参数,实例化对象 |
示例
public static void main(String[] args) throws Exception {
// 通过Student类的class属性获取指定的类实例
Class studentClass = Student.class;
// 通过类实例获取构造函数
Constructor constructor = studentClass.getConstructor();
System.out.println("构造函数名字:" + constructor.getName());
System.out.println("构造函数的访问修饰符:" + constructor.getModifiers());
// 通过Constructor创建对象
Object stu = constructor.newInstance();
System.out.println("该对象是否属于Student类型"+ (stu instanceof Student));
}
Field(属性类)
获取对应类型包括的属性的方法,通过反射获取类实例的属性信息
获取属性
返回值 | 方法名 | 描述 |
---|---|---|
FieId | getFieId(String name) | 返回该类型中指定名称为public属性,name参数为指定属性名称、 eg:类实例.getFieId(“age”) 获得类的age属性 |
FieId[] | getFieIds() | 返回该类型中所有的publi修饰的 |
FieId | getDeclaredFieId(String name) | 返回该类型中指定名称的属性,与访问修饰符无关 |
FieId[] | getDeclaredFieIds() | 返回该类型中全部属性,与属性访问修饰符无关 |
Field常用的方法
返回值 | 方法名 | 描述 |
---|---|---|
String | getName() | 获取属性的名 |
String | getType() | 获取属性的数据类型(int,String等) |
示例
public static void main(String[] args) throws Exception {
// 通过Student类的class属性获取指定的类实例
Class studentClass = Student.class;
// 获取指定的属性
// 不加上DeclareField的就是找public修饰的
Field name = studentClass.getDeclaredField("name");
System.out.println("属性的名字是:"+name.getName());
System.out.println("属性的类型是:"+name.getType());
}
Field的操作属性API
返回值 | 方法名 | 描述 |
---|---|---|
xxx | getXXX(Object obj) | xxx表示8中基本数据类型之一 obj表示该属性所在类的实例(对象) |
Object | get(Object obj) | 以Object类型返回obj中相关属性的值 |
void | setXxx(Object obj,xxx val) | 将Obj中相关属性的值设置为val,Xxx为8中基本数据类型之一 |
void | set(Object obj,Object val) | 将Obj中相关属性的值设置为val |
void | setAccessible(boolean flag) | 对相关属性设置访问权限,设置为true可以禁止java语言访问检查(就是可以访问) |
Method(方法类)
获取方法
返回值 | 方法名 | 描述 |
---|---|---|
Method | getMethod(String name,Class params) | 返回该实例中指定public方法,name参数用于指定方法的名称,params表示的指定的参数列表 |
Method[] | getMethods() | 返回该类实例中的public方法 |
Method | getDeclaredMethod(String name,Class params) | 返回该类实例指定方法,与方法访问修饰符无关 |
Method[] | getDeclaredMethods() | 返回该类实例中的全部方法 |
Method常见的方法
返回值 | 方法名 | 描述 |
---|---|---|
String | getName() | 获取方法名 |
String | getReturnType() | 获取返回值类型 |
Class[] | getParameterTypes() | 获取参数列表 |
int | getModifiers() | 获取访问修饰符 |
Class | getDeclaringClass() | 获取方法所属与的接口或方法 |
Class[] | getExceptionTypes() | 获取该方法抛出的异常 |
示例
下面都是基本的API调用。
只要思想不滑坡,利用这些API就可以做很多java动态代码
Method调用函数
Object | invoke(Object obj ,Object args) |
---|---|
- obj是执行该方法的对象,表示的就是实例(对象)
- args是执行时候带入的参数
- 调用者就是方法,表示obj调用这个方法带入arge参数
- 若Method是静态方法,则obj可以为null
- args也可以是null
这一篇文章没有安装硅谷的写,是自己学习中的总结。
反射这一章节讲述的就是API。