反射

class类创建方式

package com.zhang.annotation;
public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println(person.name);
        //方式一:通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1);  //class com.zhang.annotation.Student
        //方式二:forname获得
        Class c2 = Class.forName("com.zhang.annotation.Student");
        //方式三:通过类名.class获得
        Class c3 = Student.class;
        System.out.println(c3);  //class com.zhang.annotation.Student
        //方式四:基本内置类型的包装类都有一个Type属性
        Class c4 = Integer.TYPE;
        System.out.println(c4);    //int
        //获得父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);    //class com.zhang.annotation.Person
    }
}
class Person{
    public String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student extends Person{
    public Student(){
        this.name = "学生";
    }
}

类加载内存分析

首先在方法区产生类的一些静态基本数据,加载完成-->类在堆里面产生class对象,在栈里面执行main()方法。链接的时候为类变量(static)分配内存并设置类变量默认初始值,这些内存都在方法区中进行分配,m=0. 在堆里面让A实例化new A(),产生A类的对象,会拿到A类的所有数值,给A类显示赋值,初始化,A执行了clinit()方法,把静态代码块初始值合并,m=300,m=100,所以A.m=100.

什么时候会发生类的初始化

  1. 类的主动引用(一定会发生类的初始化)
    • 当虚拟机启动,先初始化main方法所在的类
    • new一个对象的类
    • 调用类的静态成员(除了final常量)和静态方法
    • 使用java.lang.reflect包的方法对类进行反射作用
    • 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
  2. 类的被动引用(不会发生类的初始化)
    • 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
    • 通过数组定义类引用,不会触发此类初始化
    • 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中)
package com.zhang.annotation;
public class Test02 {
    public static void main(String[] args) throws ClassNotFoundException {
        //Son son = new Son();  子类和父类都被初始化
        //Class.forName("com.zhang.annotation.Son"); 同上
        //System.out.println(Son.b); 通过子类调用父类中的静态变量。子类没有被初始化,父类被初始化。
        //Son[] array = new Son[5];  儿子的数组,不会引起类的初始化
        System.out.println(Son.M);  //调用子类中常量池 M,不会引起初始化。
    }
}
class Father{
    static int b=2;
    static {
        System.out.println("父类被加载");
    }
}
class Son extends Father{
    static{
        System.out.println("子类被加载");
        m=300;
    }
    static int m=100;
    static final int M=1;
}

类加载器

类加载作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。

类缓存:JavaSE类加载器可以按要求查找类,一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。JVM垃圾回收机制可以回收这些Class对象。

获取运行时类的完整结构

package com.zhang.annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("com.zhang.oop.Coll.Students");
        System.out.println(c1.getName());//获得包名+类名:com.zhang.oop.Coll.Students
        System.out.println(c1.getSimpleName()); //获得类名:Students
//==================================================================
        Field[] fields = c1.getFields();
        for (Field field : fields) { //只能找到public 属性:public int com.zhang.oop.Coll.Students.id
            System.out.println(field);
        }
        Field[] fields1 = c1.getDeclaredFields();
        for (Field field : fields1) {  //找到全部属性
            System.out.println(field);
        }
        Field name = c1.getDeclaredField("name");
        System.out.println(name); //获得指定属性的值:private java.lang.String com.zhang.oop.Coll.Students.name
     //===================================================
        Method[] methods = c1.getMethods();
        for (Method method : methods) { //获得本类及其父类的全部public方法
            System.out.println("正常"+method);
        }
        methods = c1.getDeclaredMethods();
        for (Method method : methods) {  // 获得本类的所有方法
            System.out.println("全部"+method);
        }
        //获得指定方法
        Method getName = c1.getMethod("getName",null);
        Method setAge = c1.getMethod("setAge", int.class);
        System.out.println(getName);//public java.lang.String com.zhang.oop.Coll.Students.getName()
        System.out.println(setAge);//public void com.zhang.oop.Coll.Students.setAge(int)
   //===================================================
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {  //获得public构造器
            System.out.println(constructor);
        }
        constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {  //获得全部构造器
            System.out.println("#"+constructor);
        }
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class);
        System.out.println(declaredConstructor);  //获得指定构造器
    }
}

动态创建对象

有了Class对象,创建类的对象:调用Class对象的newlnstance()方法

  1. 类必须有一个无参数的构造器
  2. 类的构造器的访问权限需要足够

没有无参的构造器,只要在操作的时候明确的调用类中的构造器并将参数传递进去之后,才可以实例化操作

  1. 通过Class类的getDeclaredConstructor()取得本类的指定形参类型的构造器
  2. 向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数
  3. 通过Constructor实例化对象
package com.zhang.annotation;
import com.zhang.oop.Coll.Students;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Text04 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class c1 = Class.forName("com.zhang.oop.Coll.Students");  //获得class对象
        Students students = (Students) c1.newInstance();  //构造一个对象,本质调用了类的无参构造器
        System.out.println(students);  //Students{name='null', age=0}
        //通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(String.class,int.class);
        Students students1 = (Students)constructor.newInstance("zhangsan",20);
        System.out.println(students1);  //Students{name='zhangsan', age=20}
    // ========================================================================
        //通过反射调用普通方法
        Students students2 = (Students) c1.newInstance();  //创建类的对象
        //通过反射获取一个方法
        Method setname = c1.getMethod("setName", String.class);
        //invoke 激活  (对象,“方法的值”)
        setname.invoke(students2,"lisi");
        System.out.println(students2.getName());  //lisi
    //====================================================================
        //通过反射操作属性
        Students students3 = (Students)c1.newInstance();
        Field name = c1.getDeclaredField("name");
        //不能直接操作私有属性,需要关闭程序的安全检测,属性或者方法或者构造器的setAccessible(true)
        name.setAccessible(true);
        name.set(students3,"wangwu");
        System.out.println(students3.getName());  //wangwu
    }
}

参数值为true则指示反射的对象在使用时应该取消Java语言访问检查

  1. 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁调用,设置为true
  2. 原本无法访问的私有成员也可以访问

获取注解信息

package com.zhang.annotation;
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class Text05 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        //Students student = new Students(1001,20,"zhangsan");
        Class c1 = Class.forName("com.zhang.annotation.Students");
        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation); //@com.zhang.annotation.Tablezhang(value=db_student)
        }
        //获得注解的value值
        Tablezhang tablezhang = (Tablezhang)c1.getAnnotation(Tablezhang.class);
        String values = tablezhang.value();
        System.out.println(values);  //db_student
        //获得类指定的注解
        Field f = c1.getDeclaredField("name");
        Fieldzhang annotation = f.getAnnotation(Fieldzhang.class);
        System.out.println(annotation.columnName()); //db_name
        System.out.println(annotation.type());  //varchar
        System.out.println(annotation.length());  //3
    }
}
@Tablezhang("db_student")
class Students{
    @Fieldzhang(columnName = "db_id",type = "int",length = 10)
    private int id;
    @Fieldzhang(columnName = "db_age",type = "int",length = 10)
    private int age;
    @Fieldzhang(columnName = "db_name",type = "varchar",length = 3)
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Students{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
    public Students(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
    public Students() {
    }
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Tablezhang{
    String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldzhang{
    String columnName();
    String type();
    int length();
}
posted on 2023-03-15 10:14  似初吖  阅读(22)  评论(0编辑  收藏  举报