java基础-反射(Reflect)

本文深入探讨了Java的反射机制,包括类的加载、初始化过程、类加载器的工作原理以及如何获取和使用Class对象。详细阐述了四种获取Class对象的方法,并展示了反射在创建对象、操作属性、调用方法、获取注解以及突破泛型限制等方面的应用。此外,还通过实例解释了如何使用反射创建数组。
摘要由CSDN通过智能技术生成

反射(Reflect)


类加载

  • 类在内存中的声明周期:加载→使用→卸载

类的加载过程

  1. 加载:将class加载到内存中
  2. 连接
    ① 验证:校验合法性/正确性(版本对不对)
    ②准备:准备对应的内存(方法区),创建Class对象,为类变量赋默认值,为静态常量赋初始值
    ③解析:把字节码中的符号引用替换为对应的直接地址引用
    可以提高资源查找的速度
  3. 类的初始化<clinit>
  4. 类的初始化可能会滞后(即使类没有完成初始化,也能够使用部分资源)

类的初始化

  • 那些操作会导致类的初始化
    1. 调用该类的main()方法,会导致该类完成初始化
    2. 当创建子类对象时,会先进行父类的初始化
    3. 使用类中静态资源时,会进行类的初始化
    4. 创建一个类的对象时,会进行该类的初始化
    5. 使用反射操作此类时,会进行该类的初始化
  • 类的初始化滞后
    1. 当使用类中的静态常量的时候,不会触发类的初始化,因为在类的加载阶段完成了对静态常量的赋值
    2. 当子类使用父类extends过来的static方法时,只会对父类完成类的初始化,子类不会进行初始化
    3. 创建一个类型的数组时,不会触发对该类型的初始化

类加载器

  • 类的加载器:加载类的

    1. 引导类加载器(根类加载器):加载java的核心类库:jre/rt.jar
    2. 扩展类加载器:负责加载jre/lib/ext扩展库
    3. 应用程序加载器:通过AppClassLoader加载 自己写的类
    4. 自定义类加载器:需要自主加载的内容
  • java系统类加载器的双亲委托模式:

    先由当前类加载器查看是否加载过这个类如果没有加载过
    父类加载器会查看是否加载过这个类继续向上传递
    根加载器没有加载过这个类ClassNotFoundException

javalang.Class类

  • Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
  • 要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关APl (1) java.lang.Class (2) java.lang.eflect.*。所以,Class对象是反射的根源。

哪些类型可以获取Class对象

所有java类型

1. 基本数据类型和void。例:int.class		void.class
2. 类和接口。例:String.class	Comparable.class
3. 枚举。例:ElementType.class
4. 注解。例:Override.class
5. 数组。例:int[].class

获取Class对象的四种方式

  1. 类型名.class:要求编辑期间已知类型
  2. 对象.getClass():获取对象的运行时类型
  3. Class.forName(类型全名称):可以获取编译期间未知的类型

class的作用

package com.z.reflect.clazz;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ClassTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {

        Class aClass = Class.forName("com.z.reflect.clazz.Cat");
        //获取当前类中的属性
//        Field[] fields = aClass.getFields();//只能拿到public的属性
        Field[] fields = aClass.getDeclaredFields();//获取所有的属性
        for (Field field:fields){
            System.out.println(Modifier.toString(field.getModifiers())+"    ====>属性名:   "+field.getName());
        }
        System.out.println("===================================================");
        // 只能获取本类中的方法 私有(不局限public)
//        Method[] declaredMethods = aClass.getDeclaredMethods();


        //不仅可以获取到本类中的public的方法  也会拿到父类public的方法
        Method[] declaredMethods = aClass.getMethods();
        for (Method method : declaredMethods) {
            System.out.println(method);
        }

        System.out.println("===================================================");
//        Constructor[] constructors = aClass.getConstructors();

//        拿到所有的构造器
        Constructor[] constructors = aClass.getDeclaredConstructors();
        for (Constructor c : constructors) {
            System.out.println(c);
        }
        System.out.println("===================================================");
//        拿父类
        Class superclass = aClass.getSuperclass();
        System.out.println(superclass);
        System.out.println("===================================================");
//      拿接口
        Class[] interfaces = aClass.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println(anInterface);

        }
    }
}
class Cat implements Comparable{
    private String name;
    double height;
    public String color;

    private void show(){
        System.out.println("this is show()");
    }

    @Override
    public int compareTo(Object o) {
        return 0;
    }
}

获取Class对象的四种方法

package com.z.review;

public class Test1 {
    public static void main(String[] args) throws ClassNotFoundException {
//        1. 类名.class
        Class aClass = Person.class;
//        2. 对象名.getClass();
        Person person = new Person();
        Class aClass1 = person.getClass();


//        3. 通过类的加载器 再去获取class对象
        Class aClass2 = aClass.getClassLoader().getClass();
//        4. 通过Class类的静态方法forName(类的全路径名)
        Class aClass3 = Class.forName("com.z.review.Person");
    }
}
class Person{}


使用反射创建对象

package com.z.createobject;

import java.util.Scanner;

/*
    使用反射去创建对象
    优点:
     1. 灵活
     2,可以在运行时再去确定要创建对象的类型
    缺点:难以理解
*/


public class CreateTest {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//      使用反射创建对象
//        1. 获取对应的Class对象
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你要创建对象的全类名");
        String next = scanner.next();

        Class aClass = Class.forName(next);
//        2. 创建对象       调用了对应类的无参构造器
        Object o = aClass.newInstance();
        System.out.println(o);

    }
}
class Student{
    String name = "张三";

    public Student() {
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Person{
	String name = "张三";
    int age;

    public Person() {
    }

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

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

在这里插入图片描述

  • 调用有参构造器(一个参数) 完成对成员的初始化
//        调用有参构造器(一个参数) 完成对成员的初始化
//        1. 获取Class对象
        Class clazz = Class.forName("com.z.createobject.Student");
//        2. 执行构造器
//        获取一个参数的构造器 方法是参数的Class
        Constructor constructor = clazz.getConstructor(String.class);
//        3. 执行构造器
        Object instance = constructor.newInstance("lisi");
//        4. 输出结果
        System.out.println(instance);
  • 调用有参构造器(多个参数) 完成对成员的初始化
//        调用有参构造器(多个参数) 完成对成员的初始化
//        1. 获取Class对象
        Class clazz1 = Class.forName("com.z.createobject.Person");
//        2. 执行构造器
//        获取的构造器是非public 要是用getDeclaredConstructor
        Constructor c = clazz1.getDeclaredConstructor(String.class,int.class);
//        设置私有的构造器可以访问
        c.setAccessible(true);
//        3. 执行构造器
        Object instance1 = c.newInstance("lisi",18);
//        4. 输出结果
        System.out.println(instance1);

在这里插入图片描述

使用反射操作属性

package com.z.field;

import java.lang.reflect.Field;

public class TestField {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
//        1. 获取对应的Class对象
        Class aClass = Class.forName("com.z.field.Person");
//        2. 获取对应的属性
       /* 获取公共属性
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }*/
//        获取公共属性
        Field sex = aClass.getField("sex");
//        获取静态属性
        Field country = aClass.getField("country");
//        获取私有属性
        Field name = aClass.getDeclaredField("name");
        name.setAccessible(true);//设置私有属性可见

//        3. 创建对象
//        调用无参构造器创建对象
        Object instance = aClass.newInstance();

//        3.1 修改属性值
        name.set(instance,"张三");

//        4. 获取属性值
        Object o = sex.get(instance);
//        静态变量 可以不用创建对象 直接使用
        Object o1 = country.get(null);

        Object value = name.get(instance);

        System.out.println(o);
        System.out.println(o1);
        System.out.println(value);
    }
}
class Person{
    public static String country = "China";
    private String name  = "李白";
    double height = 1.78;
    public String sex = "男";

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", height=" + height +
                ", sex='" + sex + '\'' +
                '}';
    }
}

使用反射操作方法

  • 静态的方法可以不用创建对象直接调用
  • 非静态方法必须创建对象调用
  • 私有方法要设置私有方法可见
package com.z.method;

import java.lang.reflect.Method;

public class MethodTest{
    public static void main(String[] args) throws Exception {
//    1. 获取Class对象
        Class aClass = Class.forName("com.z.method.Person");
//        2. 获取指定方法
        Method show = aClass.getDeclaredMethod("show");
        Method test = aClass.getDeclaredMethod("test", int.class, int.class);
        Method showMessage = aClass.getDeclaredMethod("ShowMessage");
        showMessage.setAccessible(true);//设置私有可见
//      3. 创建对象
        Object instance = aClass.newInstance();
//        4. 执行方法
//        show.invoke(instance);
        show.invoke(null);//show 是静态方法属于类的,可以不用传递对象
        test.invoke(instance,10,20);
        showMessage.invoke(instance);
    }
}

class Person {
    public static String country = "China";
    private String name = "李白";
    double height = 1.78;
    public String sex = "男";

    private void ShowMessage() {
        System.out.println("this is private ShowMessage()");
    }

    public void test(int a, int b) {
        System.out.println("a+b的和为:" + (a + b));
    }

    public static void show() {
        System.out.println("this is show()");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", height=" + height +
                ", sex='" + sex + '\'' +
                '}';
    }
}

使用反射获取注解

package com.z.ann;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//指注解可以存活到运行时
public @interface MyAnn {
    String value() default "haha";
}

package com.z.ann;

@MyAnn(value = "李白")//如未赋值则为默认值haha
public class Person {}
package com.z.ann;

import java.lang.annotation.Annotation;

public class TestAnn {
    public static void main(String[] args) throws Exception {
//        1. 获取Class对象
        Class aClass = Class.forName("com.z.ann.Person");
        /*获取所有的注解
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);

        }*/
        Annotation annotation = aClass.getAnnotation(MyAnn.class);
        System.out.println(annotation);
    }
}

在这里插入图片描述

使用反射突破泛型限制

package com.z.list;

import com.z.ann.Person;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;

public class ListTest {
    public static void main(String[] args) throws Exception{
        ArrayList<Integer> list = new ArrayList<>();
        list.add(10);
//        list.add(new Date()); 

        Class aClass = list.getClass();
        Method addMethod = aClass.getDeclaredMethod("add", Object.class);

//        Date Person 都不属于Integer类型
        addMethod.invoke(list,new Date());
        addMethod.invoke(list,new Person());

        System.out.println(list);
    }
}

使用反射创建数组

package com.z.arr;

import java.lang.reflect.Array;

public class TestArr {
    public static void main(String[] args) {
//        创建了一个数组, 长度是5
        Object o = Array.newInstance(String.class, 5);

        Array.set(o,0,"李白");
        Array.set(o,1,"杜甫");

        Object o1 = Array.get(o, 1);
        System.out.println(o1);//杜甫

        Object o2 = Array.get(o, 2);
        System.out.println(o2);//null

    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值