java基础之反射

**> **文章参考于B站-韩顺平

一. 一个需求引出反射

1.根据配置文件re.properties指定信息,创建Cat对象并调用方法hi
re.properties:

classfullpath=com.hspedu.Cat
method=hi

这样的需求在学习框架的时候特别多,即通过外部文件配置,在不修改源码情况下来控制程序,这符合设计模式的ocp原则(开闭原则:不修改源码,开扩容功能)

  • 利用反射代码实现5
public class ReflectionQuestion {







public static void main(String[] args) throws Exception {

    Properties properties = new Properties();
    properties.load(new FileInputStream("src\\re.properties"));
    String classfullpath = properties.get("classfullpath").toString();
    String method = properties.get("method").toString();
    //(1)加载类,返回Class类型的对象clazz
    Class<?> clazz = Class.forName(classfullpath);
    //(2)获得对象实例
    Object o = clazz.newInstance();
    //(3)通过cls得到你加载的类com.hspedu.Cat的methodName"hi" 的方法对象
    //在反射中,可以把方法视为对象(万物皆对象)
    Method declaredMethod = clazz.getDeclaredMethod(method);
    //通过方法对象来实现调用方法
    declaredMethod.invoke(o);
    }

}

如果Cat类中还有一个cry方法,输出cry cat

public void cry(){
    System.out.println("cry cat");
}

我们如果想要执行cry方法,只能将cat.hi()方法修改成cat.cry()方法,这样不仅很麻烦而且涉及到修改源码,如果使用反射,我们便可以不修改源码,只修改配置文件便可控制方法的调用

二. 反射机制:

1. Java Reflection

  1. 反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(比如成员变量没构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
  2. 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息,通过这个对象得到类的结构,这个对象就像一面镜子,透过这个镜子看到类的结构,

2. Java反射机制原理示意图

20210607165333672-16282402572274.png

Java反射机制可以完成以下事情:
  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时得到任意一个类所具有的成员变量和方法
  4. 在运行时调用任意一个对象的成员变量和方法
  5. 生成动态代理
Java反射相关的主要类:
  1. java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
  2. java.lang.reflect.Method:代表类的方法
  3. java.lang.reflect.Field:代表类的成员变量
  4. java.lang.reflect.Constructor:代表类的构造方法
Field的使用:
        //得到name字段的名字
        Field fieldName = clazz.getDeclaredField("name");
        fieldName.setAccessible(true);
        System.out.println("name:"+fieldName.get(o));
Constructor的使用:
    //获得无参构造器
    Constructor<?> Noconstructor = clazz.getConstructor();
    System.out.println("无参constructor:"+Noconstructor);
//获得有参构造器
Constructor<?> Allconstructor = clazz.getConstructor(String.class);
System.out.println("无参constructor:"+Allconstructor);

3. 反射优点和缺点:

优点:
可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑
缺点
使用反射基本是解释执行,对执行速度有影响,直接new出对象速度是反射出对象的几十倍
4.传统方式与反射的效率对比:

public class Reflection02 {







public static void main(String[] args) throws Exception {

    m1();
    m2();
}



public static void m1(){
    //普通new
    Cat cat = new Cat();
    long Newstart = System.currentTimeMillis();
    for (int i =0;i<1000000;i++){
        cat.hi();
    }
    long Newend = System.currentTimeMillis();
    System.out.println("传统方式耗时:"+(Newend-Newstart));
}

public static void m2() throws Exception{
    //反射创建
    Properties properties = new Properties();
    properties.load(new FileInputStream("src\\re.properties"));
    String classfullpath = properties.get("classfullpath").toString();
    Class<?> clazz = Class.forName(classfullpath);
    Method hi = clazz.getMethod("hi");
    Cat cat2 = (Cat)clazz.newInstance();
    long Refstart = System.currentTimeMillis();
    for (int i =0;i<1000000;i++){
        hi.invoke(cat2);
    }


    long Refend = System.currentTimeMillis();
    System.out.println("反射方式耗时:"+(Refend-Refstart));
}


}
对反射方式进行优化:

setAccessible(true)

反射调用优化-关闭访问检查:
  1. Method和Field、Constructor对象都有setAccessible()方法
  2. setAccessible作用是启动和禁用访问安全检查的开关
  3. 参数为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查

优化之后:
image.png


三. Class类

1. Class也是类,因此也继承Object类

Class类图结构

20210607165333672-16282404529196.png

2. Class类对象不是new出来的,而是系统创建的

传统的new出对象的方式
Cat cat = new Cat();1我们进入创建过程:
20210607170313894.png
反射的方式
20210607170337705.png
由此可见:
两者都是通过ClassLoader类加载Class对象

3. 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次

分别执行下面图中的代码
图一:20210607170514485.png
图二:
20210607170540963.png
随着图一debug我们进入了loadClass方法:
随着图二debug我们没有进入loadClass方法
这是因为图二在执行Cat cat = new Cat()时已经将Cat类加载到内存中,在堆中只会存在一份Class类对象,所以执行时不会再次进入loadClass方法

对象.getClass()

4. 通过Class对象可以完整地得到一个类的完整结构,通过一系列API

每个类的实例都会记得自己是由哪个Class实例所生成

  1. Class getSuperClass() 返回当前Class对象的父类的Class对象
  2. Class[] getInterfaces() 返回当前Class对象的所有接口
  3. ClassLoader getClassLoader()返回该类的类加载器
  4. Class getSuperclass() 返回表示此Class所表示的实体的超类的Class

5. 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码,变量名,方法名,访问权限等等)

当类加载完毕后,我们的字节码对应的二进制数据加载到方法去中,除此之外在堆中会产生
一个Class类对象,这其实是一种数据结构,可以把成员变量映射成一个对象并对其操作
Class类方法演示:创建Car类

public class Car {
    public String brand="品牌";
    public int price;
    public String color;
}
 public class Class02 {



public static void main(String[] args) throws Exception {
    String classAllPath = "com.hspedu.Car";
    Class<?> clazz = Class.forName(classAllPath);
    //1.输出clazz
    System.out.println(clazz);//显示clazz对象,是哪个类的Class对象 com.hspedu.Car
    System.out.println(clazz.getClass());//输出clazz运行类型 java.lang.Class
    //2.得到包名
    System.out.println(clazz.getPackage().getName());
    //3.得到全类名
    System.out.println(clazz.getName());
    //4.通过clazz创建对象实例
    Car o = (Car)clazz.newInstance();
    //5.通过反射获取属性
    Field brand = clazz.getDeclaredField("brand");
    System.out.println(brand.get(o));
    //通过反射给属性赋值
    brand.set(o,"奔驰");
    System.out.println(brand.get(o));
    //遍历得到所有的属性
    Field[] fields = clazz.getFields();
    for (Field field : fields) {
        System.out.println(field.get(o));
    }


}

获取反射的四种方式

不同阶段获取Class的不同方式
1.前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException创建方式: Class.forName()应用场景:多用于配置文件,读取类全路径,加载类
2.前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高创建方式: 类.class应用场景:多用于参数传递,比如通过反射得到对应构造器对象
3.前提:已知某个类的实例,调用该实例的geiClass()方法获取Class对象创建方式:对象.getClass()应用场景:通过创建好的对象,获取Class对象
4.其他方式ClassLoader cl = 对象.getClass().getClassLoader();创建方式:Class clazz =cl.getloadClass(“类的全类名”);
代码示例:

public class GetClass {
	public static void main(String[] args) throws Exception {
		//1.Class.forName()
		Class<?> cls1 = Class.forName("com.hspedu.Car");
		//2.类名.class,应用场景:多用于参数传递
		Class<Car> cls2 = Car.class;
		//3.对象名.getClass()
		Car car = new Car();
		Class<? extends Car> cls3 = car.getClass();
		//4.通过类加载器来获取类的Class对象
		//先得到类加载器
		ClassLoader classLoader = car.getClass().getClassLoader();
		Class<?> cls4 = classLoader.loadClass("com.hspedu.Car");
   	}
 }

四、哪些类型有Class对象

如下类型有Class对象

  1. 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
  2. interface:接口
  3. 数组enum:枚举
  4. annotation:注解
  5. 基本数据类型
  6. void

五、动态加载和静态加载:

类加载基本说明:

反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载
静态加载:编译时加载相关的类,如果没有则报错,依赖性太强动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不会报错,降低了依赖性

类加载时机:

  1. 当创建对象时(new)//静态加载
  2. 当子类被加载时,父类也加载//静态加载
  3. 调用类中的静态成员时//静态加载
  4. 通过反射//动态加载

代码示例:20210607171544949.png也就是说,静态加载是不论程序是否会执行A代码,A都会被加载,而动态加载是说,只有在真正要用到A段代码时,A代码才会被加载

类加载过程图:20210607171628343.png

类加载的三个阶段的任务:20210607171651488.png

类加载各个阶段的介绍:

一、加载阶段Loading

JVM在该阶段的主要目的时将字节码从不同的数据源(可能是class文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象

二、连接阶段Linking

连接阶段-验证:
目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机中的要求,并且不会危害虚拟机自身的安全包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据校验、字节码验证和符号饮用验证可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间
连接阶段-准备:
代码案例:

class A{
    //连接阶段-准备
    //1.n1是实例属性,不是静态变量,因此在连接阶段-准备时不会被分配内存
    //2.n2是静态变量,分配内存 n2 是默认在此阶段初始化,值为0,只有在连接阶段后的初始化阶段值才会被初始化为20
    //3.n3是常量,他和静态变量不一样,因为一旦赋值就不会改变,所以n3此阶段值为30
    public int n1=10;
    public static int n2=20;
    public static final int n3=30;
}

连接阶段-解析:
虚拟机将常量池内的符号引用替换为直接引用的过程比如A类中有B类的引用,但只作为符号存在,只有在解析阶段才会将这类的符号引用解析为直接引用

三、初始化阶段Initialization

到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行()方法的过程clinit()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并虚拟机会保证一个类的()方法在多线程环境中被正确地加锁,同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕
代码展示:

package com.hspedu.reflection.classload_;







/**初始化过程




 * Description
 * User:
 * Date:
 * Time:
   */
     public class ClassLoad03 {
   public static void main(String[] args) {
       //1.加载B类,并生成B的Class对象
       //2.连接 num = 0;
       //3.初始化
       // 依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并合并,
       //先执行静态代码块中的代码,再执行静态变量
       /*
           clinit() {
               System.out.println("B 静态代码块被执行");
               num = 300;
               static int num = 100;
           }
           合并:num=100
        */
     //        new B();
       System.out.println(B.num);
   }
     }
     class B{
   static {
       System.out.println("B 静态代码块被执行");
       num = 300;
   }
   static int num = 100;
   public B(){
       System.out.println("B() 构造器被执行");
   }
}

JVM对于clinit方法的加锁机制,在加载类的时候有同步机制控制

protected Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException {
	synchronized (getClassLoadingLock(name)) {
}

六、通过反射获取类的结构信息

java.lang.Class类方法:

  1. getName:获取全类名
  2. getSimpleName:获取简单类名
  3. getFields:获取所有public 修饰的属性,包括本类以及父类的
  4. getDeclareFields:获取本类中的所有属性
  5. getMethods:获取所有public修饰的方法,包括本类以及父类的
  6. getDeclaredMethods:获取本类中的所有方法
  7. getConstructors:获取所有public修饰的构造器
  8. getDeclaredConstructors:获取本类中所有构造器
  9. getPackage:以Package形式返回包信息getSuperClass:以Class形式返回父类信息
  10. getInterfaces:以Class[]形式返回接口信息
  11. getAnnotations:以Annotation[]形式返回注解信息

代码示例:

package com.hspedu.reflection;










import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;



/**
 * Description:演示如何通过
 * User:
 * Date:
 * Time:
 */
public class ReflectionUtils {
    public static void main(String[] args) throws Exception {
        api1();

    }
    public static void api1() throws Exception{

        Class<?> clazz = Class.forName("com.hspedu.reflection.A");
        Object o = clazz.newInstance();

//        1. getName:获取全类名
        System.out.println("获取全类名:"+clazz.getName());
//        2. getSimpleName:获取简单类名
        System.out.println("获取简单类名:"+clazz.getSimpleName());
//        3. getFields:获取所有public 修饰的属性,包括本类以及父类的
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println("public属性:"+field.getName());
        }
//        4. getDeclareFields:获取本类中的所有属性
        Field[] fields2 = clazz.getDeclaredFields();
        for (Field field : fields2) {
            System.out.println("全部属性:"+field.getName());
        }
//        5. getMethods:获取所有public修饰的方法,包括本类以及父类的
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println("public修饰的方法:"+method.getName());
        }
//        6. getDeclaredMethods:获取本类中的所有方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类中的方法:"+declaredMethod.getName());
        }
//        7. getConstructors:获取所有public修饰的构造器,包括本类
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("public修饰的构造器:"+constructor.getName());
        }
//        8. getDeclaredConstructors:获取本类中所有构造器
        Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("获取本类中所有构造器");
        }
//        9. getPackage:以Package形式返回包信息
        Package aPackage = clazz.getPackage();
        System.out.println("包名:"+aPackage);
//        10. getSuperClass:以Class形式返回父类信息
        Class<?> superclass = clazz.getSuperclass();
        System.out.println("以class形式返回父类信息:"+superclass);
//        11. getInterfaces:以Class[]形式返回接口信息
        Class<?>[] interfaces = clazz.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println("接口信息:"+anInterface.getName());
        }
//        12. getAnnotations:以Annotation[]形式返回注解信息
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("注解信息:"+annotation.toString());
        }
    }
}

class B{
    public String bb;
}

class A extends B{
    public String name;
    protected int age;
    String job;
    private double sal;

    public void m1(){

    }
    protected void m2(){

    }
    void m3(){

    }
    private void m4(){

    }

}


java.lang.reflect.Field类方法:

  1. getModifiers:以int形式返回修饰符[说明:默认修饰符是0,public 是1,private是2,protected是4,static是8,final是16]
  2. getType:以Class形式返回类型
  3. getName:返回属性名

代码展示:

public static void api2() throws Exception{
    Class<?> clazz = Class.forName("com.hspedu.reflection.A");


    Object o = clazz.newInstance();


    Field[] declaredFields = clazz.getDeclaredFields();
    for (Field declaredField : declaredFields) {
    //            1. getModifiers:以int形式返回修饰符[说明:默认修饰符是0,public 是1,private是2,protected是4,static是8,final是16]
            int modifiers = declaredField.getModifiers();
            System.out.println(declaredField.getName()+":"+modifiers);
            //2. getType:以Class形式返回类型
            Class<?> type = declaredField.getType();
            System.out.println(declaredField.getName()+":"+type.getName());
            //3. getName:返回属性名
            String name = declaredField.getName();
            System.out.println(declaredField.getName()+":"+name);
        }
    }

java.lang.reflect.Method类方法:

  1. getModifiers:以int类型返回修饰符[说明:默认修饰符是0,public 是1,private是2,protected是4,static是8,final是16]
  2. getReturnType:以Class形式获取返回类型
  3. getName:返回方法名
  4. getParameterTypes:以Class[]返回参数类型数组

代码示例:

public static void api3() throws Exception{
    Class<?> clazz = Class.forName("com.hspedu.reflection.A");


    Object o = clazz.newInstance();


    Method[] declaredMethods = clazz.getDeclaredMethods();
    for (Method declaredMethod : declaredMethods) {
        //getModifiers:以int类型返回修饰符[说明:默认修饰符是0,public 是1,private是2,protected是4,static是8,final是16]
        System.out.println(declaredMethod.getName()+":"+declaredMethod.getModifiers());
        //getReturnType:以Class形式获取返回类型
        System.out.println(declaredMethod.getName()+":"+declaredMethod.getReturnType());
        //getName:返回方法名
        System.out.println(declaredMethod.getName());
        //getParameterTypes:以Class[]返回参数类型数组
        Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
        for (Class<?> parameterType : parameterTypes) {
            System.out.println(declaredMethod.getName()+":"+parameterType);
        }
    }

}

java.lang.reflect.Contructor类的方法

  1. getModifiers:以int形式返回修饰符
  2. getName:返回构造器名(全类名)
  3. getParameterTypes:以Class[]返回参数类型数组
public static void api4() throws Exception{
    Class<?> clazz = Class.forName("com.hspedu.reflection.A");


    Object o = clazz.newInstance();


    Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
    for (Constructor<?> declaredConstructor : declaredConstructors) {
        Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
        for (Class<?> parameterType : parameterTypes) {
            System.out.println(declaredConstructor.getName()+":"+declaredConstructor.getModifiers()+":"+parameterType);
        }
    }
}

七、反射爆破创建实例:

通过反射创建对象的几种方式

  1. 方式一、调用类中的public修饰的无参构造器
  2. 方式二、调用类中的指定构造器

Class类相关方法

  1. newInstance:调用类中的无参构造器,获取对应类的对象
  2. getConsturctor(Class…clazz):根据参数列表,获取对应的public构造器对象
  3. getDecalaredConstructor(Class…clazz):根据参数列表,获取对应的所有构造器对象

Constructor类相关方法

  1. setAccessible:爆破
  2. newInstance(Object…obj):调用构造器

案例演示:1 测试1:通过反射创建某类的对象,要求该类中必须有public的无参构造
2.测试2:通过调用某个特定构造器的方式,实现创建某类的对象

package com.hspedu.reflection;










import java.lang.reflect.Constructor;




/**


 * Description:演示通过反射机制创建实例
 * User:

 * Date:

 * Time:

 */

public class ReflecCreateInstance {
    public static void main(String[] args) throws Exception {



        //1.先获取到User类的Class对象
        Class<?> clazz = Class.forName("com.hspedu.reflection.User");

        //2.通过public的无参构造器创建实例
        Object o = clazz.newInstance();
        System.out.println("无参构造创建的对象实例:"+o);
        //3.通过public的有参构造器创建实例
        Constructor<?> constructor = clazz.getConstructor(String.class);
        Object ls = constructor.newInstance("ls");
        System.out.println("通过public的有参构造器创建实例:"+ls);
        //4.通过非public的有参构造器创建实例
        Constructor<?> constructor1 = clazz.getDeclaredConstructor(int.class, String.class);
        //爆破
        constructor1.setAccessible(true);//使用反射可以访问private构造器
        Object wql = constructor1.newInstance(20, "wql");
        System.out.println("通过非public的有参构造器创建实例:"+wql);
    }


}

class User{
    private int age=10;
    private String name="zs";

    public User(){
    }

    public User(String name) {
        this.name = name;
    }

    private User(int age, String name){
        this.age = age;
        this.name = name;
    }


    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

通过反射访问类中的成员:

访问属性:ReflecAccessProperty.java

  1. 根据属性名获取Field对象Field f = clazz对象.getDeclaredField(属性名)
  2. 爆破:f.setAccessible(true);
  3. 访问f.set(o,值)//o表示对象
  4. 如果是静态属性,则set中的o,可以写成null

案例演示:

package com.hspedu.reflection;










import java.lang.reflect.Field;




/**


 1. Description:演示反射访问属性
 2. User:
 3. Date:
 4. Time:
 */

public class ReflecAccessProperty {
    public static void main(String[] args) throws Exception {



        //1.得到Student类对应的Class对象
        Class<?> clazz = Class.forName("com.hspedu.reflection.Student");
        //2.创建对象
        Object o = clazz.newInstance();
        //3.得到age属性对象
        Field age = clazz.getField("age");
        age.set(o,20);
        System.out.println("age:"+age.get(o));
        //4.得到name属性
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(o,"zs");
        System.out.println("name:"+name.get(o));
        //5.静态变量设空
        Field name2 = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(null,"ls");
        System.out.println("name:"+name.get(o));
    }
}

class Student{
    public int age;
    private static String name;
    public Student(){
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +",name="+name+
                '}';
    }
}


通过反射访问方法:

  1. 根据方法名和参数列表获取Method方法对象:Method m = clazz.getDeclaredMethod(方法名,XX.class);
  2. 爆破:m.setAccessible(true);
  3. 访问:Object returnValue = m.invoke(o,实参列表);//o就是对象
  4. 注意:如果是静态方法,则invoke的参数o,可以写成null

案例演示:

package com.hspedu.reflection;










import java.lang.reflect.Method;




/**


 * Description
 * User:

 * Date:

 * Time:

 * 通过反射调用方法
 */
public class ReflecAccessMethod {
    public static void main(String[] args) throws Exception {

        Class<?> clazz = Class.forName("com.hspedu.reflection.Boss");
        Object o = clazz.newInstance();
        //1.调用public的hi方法
        Method hi = clazz.getMethod("hi",String.class);
        hi.invoke(o,"张三");
        //2.调用静态的say方法
        Method say = clazz.getDeclaredMethod("say", int.class, String.class, char.class);
        say.setAccessible(true);
        System.out.println(say.invoke(o,2,"张三",'c'));


        System.out.println(say.invoke(null,2,"张三",'c'));

    }
}
class Boss{
    public int age;
    private static String name;

    public Boss(){//构造器
    }

    private static String say(int n,String s,char c){//静态方法
        return n+" "+s+" "+c;
    }
    public void hi(String s){//普通public方法
        System.out.println("hi "+s);
    }
}

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYqfQfz5' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片