反 射
1、什么是反射?
在java中,反射是指在运行时检查和操作类、接口、字段、方法等程序结构的能力。通过反射可以在运行时获取类的信息,创建类的实例,调用类的放方法,访问和修改类的字段等。
2、反射有什么作用?
主要用途: 反射最重要的用途就是开发各种通用框架。
反射也是框架技术的灵魂,而框架是他人写好并且包装起来的一套工具,把自己原先必须要写的,必须要做的一些复杂的东西都写好存放在那里,自己只需要调用他的方法即可。从而大大提高了开发效率。
3、如何获取反射?
获取Class类对象的方式有三种:
第一种: Class.forName("类路径")
第二种: 类名.class
第三中: 对象.getClass();
3.1 Class.ForName("类路径")
public class Text1 {
public static void main(String[] args) throws ClassNotFoundException {
// 通过Class.forName("类路径") 获取A的反射类对象
Class<A> aClass = (Class<A>) Class.forName("com.dome.dome1.A");
System.out.println("aClass:"+aClass);
}
}
class A{
private String a;
private Integer b;
@Override
public String toString() {
return "A{" +
"a='" + a + '\'' +
", b=" + b +
'}';
}
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public Integer getB() {
return b;
}
public void setB(Integer b) {
this.b = b;
}
public A() {
}
public A(String a, Integer b) {
this.a = a;
this.b = b;
}
}
运行结果:
3.2 类.class
public class Text1 {
public static void main(String[] args) throws ClassNotFoundException {
// 通过Class.forName("类路径") 获取A的反射类对象
// Class<A> aClass = (Class<A>) Class.forName("com.dome.dome1.A");
// System.out.println("aClass:"+aClass);
// 通过 类.class 获取A的反射类对象
Class<A> aClass1 = A.class;
System.out.println("aClass1:"+aClass1);
}
}
运行结果:
3.3 对象.getClass();
public class Text1 {
public static void main(String[] args) throws ClassNotFoundException {
// 通过Class.forName("类路径") 获取A的反射类对象
// Class<A> aClass = (Class<A>) Class.forName("com.dome.dome1.A");
// System.out.println("aClass:"+aClass);
// 通过 类.class 获取A的反射类对象
// Class<A> aClass1 = A.class;
// System.out.println("aClass1:"+aClass1);
// 创建一个类
A a = new A();
// 通过 类.getClass(); 获取A的反射类对象
Class<? extends A> aClass2 = a.getClass();
System.out.println("aClass2:"+aClass2);
}
}
运行结果:
4、通过反射类获取类对象
通过Class类对象,调用newInstance()(此方法在JDK9之后已过时)
public class Text2 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
// 通过 Class.forName("类路径") 获取A的反射类对象
Class<A> aClass = (Class<A>) Class.forName("com.dome.dome2.A");
A a = aClass.newInstance();
System.out.println("a"+a);
}
}
运行结果:
总结:
先通过Class.forName(“类路径”)——得到该类的反射类——并通过newInstance()创建类对象
5、获取反射类中的属性成员对象
由于字节码中的属性成员通过ClassLoader(类加载器)加载到内存中之后,会以Field(属性)类对象的形式存在。
首先说明一下getDeclaredFields()和getFields()这两个方法的区别:
getFields(): 获取某个类的所有的public字段,其中是包括父类的public字段的。
getDeclaredFields():获取某个类的自身的所有字段,不包括父类的字段。
5.1getFields()
public class Text3 {
public static void main(String[] args) {
//1、获取C类的反射类 类.class
Class<C> cClass = C.class;
// 2、获取反射类中的成员对象
// // 获取本类中所有属性对象
// Field[] declaredFields = cClass.getDeclaredFields();
// for(Field field:declaredFields){
// System.out.println("field:"+field);
// }
System.out.println("---------分割线-------------");
// 获取本类及父类所有public字段
Field[] fields = cClass.getFields();
for (Field field1: fields){
System.out.println("field1"+field1);
}
}
}
运行结果:
)
5.2 getDeclaredFields()
public class Text3 {
public static void main(String[] args) {
//1、获取C类的反射类 类.class
Class<C> cClass = C.class;
// 2、获取反射类中的成员对象
// 获取本类中所有属性对象
Field[] declaredFields = cClass.getDeclaredFields();
for(Field field:declaredFields){
System.out.println("field:"+field);
}
}
}
// 创建一个类
class B{
public String b1;
private Integer b2;
}
class C extends B{
public Integer c1;
private String c2;
double c3;
public void cc(){
System.out.println("c1:"+c1+",c2:"+c2);
}
@Override
public String toString() {
return "C{" +
"c1=" + c1 +
", c2='" + c2 + '\'' +
", c3=" + c3 +
", b1='" + b1 + '\'' +
'}';
}
public Integer getC1() {
return c1;
}
public void setC1(Integer c1) {
this.c1 = c1;
}
public String getC2() {
return c2;
}
public void setC2(String c2) {
this.c2 = c2;
}
public double getC3() {
return c3;
}
public void setC3(double c3) {
this.c3 = c3;
}
public C() {
}
public C(Integer c1, String c2, double c3) {
this.c1 = c1;
this.c2 = c2;
this.c3 = c3;
}
}
运行结果:
)
6、Field类中具有的常用的方法
6.1 setAccessible(true)
setAccessible(true): 设置允许访问私有属性
public class Text5 {
public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
// 1、获取反射对象 类.getClass
AA aa = new AA();
Class<AA> aClass = (Class<AA>) aa.getClass();
// 2、通过反射获取类对象
AA aaa1 = aClass.newInstance();
// 3、通过getDeclaredField()得到反射类中的aa1对象
Field aa11 = aClass.getDeclaredField("aa1");
aa11.setAccessible(true); // 允许访问私有属性
//通过aa1属性对象为aaa1对象赋值
aa11.set(aaa1,"欸嘿");
System.out.println("aa11"+aa11);
}
}
class AA{
private String aa1;
public Integer a1a;
@Override
public String toString() {
return "AA{" +
"aa1='" + aa1 + '\'' +
", a1a=" + a1a +
'}';
}
}
没有运行setAccessible(true)结果:(https://img2023.cnblogs.com/blog/3257079/202308/3257079-20230811105742840-955167904.png)
)
运行setAccessible(true)结果:
)
6.2 getAnnotation(注解.class)
public class Text5 {
public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
// 1、获取反射对象 类.getClass
AA aa = new AA();
Class<AA> aClass = (Class<AA>) aa.getClass();
// 2、通过反射获取类对象
AA aaa1 = aClass.newInstance();
// 3、通过getDeclaredField()得到反射类中的aa1对象
Field aa11 = aClass.getDeclaredField("aa1");
aa11.setAccessible(true); // 允许访问私有属性
//通过aa1属性对象为aaa1对象赋值
aa11.set(aaa1,"欸嘿");
System.out.println("aa11:"+aa11);
System.out.println("-----------------分割线--------------");
// 通过 反射类中aa11.getAnnotation(注解.class) 获取注解
MyNote annotation = aa11.getAnnotation(MyNote.class);
System.out.println("annotation"+annotation.value());
}
}
运行结果:
)
7、获取方法类对象
7.1 getMethods()
getMethods(): 获得类的public类型的方法
public class Text6 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Class<E> eClass = E.class;
E e = eClass.newInstance();
// 获取本类及父类中所有的public修饰的Method方法对象
Method[] methods = eClass.getMethods();
for (Method method : methods) {
System.out.println("method:"+method);
}
}
}
class E{
public String fun01(){
System.out.println("~~~~~~~~~~~~~~~~~01");
return "hello01";
}
public String fun01(int age){
System.out.println("~~~~~~~~~~~~~~~~~01");
return "hello01";
}
public String fun02(int age){
System.out.println("~~~~~~~~~~~~~~02");
return "hello01"+age;
}
private void fun03(){
System.out.println("~~~~~~~~~~~~~~~03");
}
}
运行结果:
)
如果没有父类,会有默认的父类Object
7.2 getMethod(String name, Class[] params)
getMethod(String name, Class[] params): 获得类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型(null和不写都调用无参的方法)
public class Text6 {
public static void main(String[] args) throws Exception {
Class<E> eClass = E.class;
E e = eClass.newInstance();
// 获取本类及父类中某一个的public修饰的Method方法对象
Method methods = eClass.getMethod("fun01", int.class);
System.out.println(methods);
}
}
运行结果:
)
7.3 getDeclaredMethods()
getDeclaredMethods(): 获取本类中所有的方法(public、protected、default、private)
public class Text6 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Class<E> eClass = E.class;
E e = eClass.newInstance();
// 获取本类中所有的Method方法对象
Method[] methods = eClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println("method:"+method);
}
}
}
运行结果:
7.4 getDeclaredMethod(String name, Class[] params)
getDeclaredMethod(String name, Class[] params): 获得本类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型
public class Text6 {
public static void main(String[] args) throws Exception {
Class<E> eClass = E.class;
E e = eClass.newInstance();
// 获取本类中指定的public修饰的Method方法对象
Method methods = eClass.getDeclaredMethod("fun02",new Class[]{int.class});
System.out.println("method:"+methods);
}
}
运行结果:
7.5 Method类中常用的方法
invoke(): 执行该方法体
public class Text6 {
public static void main(String[] args) throws Exception {
Class<E> eClass = E.class;
E e = eClass.newInstance();
// 获取本类中某一个的class对象的Method方法对象
Method methods = eClass.getDeclaredMethod("fun02",new Class[]{int.class} );
Object invoke = methods.invoke(e,15);
System.out.println("invoke:"+invoke);
}
}
运行结果:
)
8、获取构造方法对象
8.1 getConstructors()
getConstructors()获取Class对象所表示类的所有的公共构造方法
public class Text7 {
public static void main(String[] args) {
Class<Q> qClass = Q.class;
// 只能得到本类中public的构造函数
Constructor<Q>[] constructors = (Constructor<Q>[]) qClass.getConstructors();
for (Constructor<Q> constructor : constructors) {
System.out.println("constructor:"+constructor);
}
}
}
class R{
public R(){
System.out.println("父类的无参构造函数");
}
public R(String n){
System.out.println("这是父类的有参构造函数:"+n);
}
}
class Q extends R{
public Q(){
super();
System.out.println("子类的无参");
}
public Q(String n){
System.out.println("子类的有参:"+n);
}
private Q(Integer age){
System.out.println("有参私有构造");
}
}
运行结果:
)
8.2 getDeclaredConstructors()
getDeclaredConstructors()获取Class对象所表示的类声明的所有构造方法
public class Text7 {
public static void main(String[] args) {
Class<Q> qClass = Q.class;
// 得到本类以及父类中public修饰的方法对象
Constructor<Q>[] declaredConstructors = (Constructor<Q>[]) qClass.getDeclaredConstructors();
for (Constructor<Q> declaredConstructor : declaredConstructors) {
System.out.println("declaredConstructor:"+declaredConstructor);
}
}
}
运行结果:
)
8.3 getConstructor(Class<?>… parameterTypes)
getConstructor(Class<?>… parameterTypes)获取Class 对象所表示的类的指定公共构造方法
public class Text7 {
public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException {
Class<Q> qClass = Q.class;
Constructor<Q> Constructor = qClass.getConstructor(String.class);
System.out.println("Constructor"+Constructor);
}
}
运行结果:
8.4 getDeclaredConstructor(Class<?>… parameterTypes)
getDeclaredConstructor(Class<?>… parameterTypes)获取Class对象所表示的类声明的某个构造方法
public class Text7 {
public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException {
Class<Q> qClass = Q.class;
Constructor<Q> declaredConstructor = qClass.getDeclaredConstructor(String.class);
System.out.println("declaredConstructor"+declaredConstructor);
}
}
运行结果:
)
8.5 Constructor类中常用的方法
public class Text7 {
public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class<Q> qClass = Q.class;
Constructor<Q> constructor = qClass.getConstructor(String.class);
constructor.newInstance("欸嘿 欸嘿");
}
}
运行结果: