IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java之反射 -> 正文阅读

[Java知识库]Java之反射

反射Reflection

静态语言(c、c++)和动态语言(JavaScript)
动态语言:程序运行的时候可以改变其结构,成为动态语言。
eg:

	function jsMethod(){
		var x="3;var y=5;alert(x+y)"
		执行该方法,会将原本为字符串的x变为一段代码的执行,这种语言即为动态语言
	}

Java通过反射可以达到动态语言的效果;

一个类在内存中只有一个Class对象
一个类被加载后,类的整个结构都会被封装在Class对象中。

反射得到的是一个Class类,此类是Java反射的源头,即通俗的理解为:通过对象反射出类的名称

获取Class对象的几种方式

Class类的特性:
一个类型的类在JVM中只会有一个Class实例
在这里插入图片描述

//类所在得包路径
package yh.com.pojo
//自定义一个类
class Person{
private String name;
Person(){
this.name="人类";}
}
class Teacher extends Person{
Teacher(){
this.name="老师";}
}
public class TestClass{
public stastic void main(String args[]){
//所得Class对象皆为同一实例,根据Class的特性可得
//方式1:通过对象获得(通过一个已存在得实例对象获取)
Student s=new Teacher();
Class c1=s.getClass();
System.out.println(c1.hashCode());
//2.通过Class类得forName(完整包名)方法来获取
Class c2=Class.forName("yh.com.pojo.Teacher")
System.out.println(c2.hashCode());
//3.通过 类名.class 来获取
Class c3=Teacher.class;
System.out.println(c3.hashCode());
//4.基本内置类型得包装类有一个Type属性可以获取
Class c4=Integer.Type;
System.out.println(c4);//int
System.out.println(c4.hashCode());
//5.class对象得方法调用
Class c5=c1.getSupercclass();
System.out.println(c5);//Person
System.out.println(c5.hashCode());
	}
}

Class类的常用方法:

  1. static ClassforName(String name):返回指定类名的class对象
  2. Object newIntence():调用无参构造器返回一个class对象的实例
  3. getName():返回该class对象所表示的实体(类、接口、数组、void等)的名称
  4. getSuperClass():获取当前class对象的父类的class对象
可以有Class对象的类型

在这里插入图片描述
eg:
在这里插入图片描述
比如数组和二维数组是不同维度的在这里插入图片描述

存内存分析反射流程

帮助理解反射,了解即可

  1. 加载class文件到内存的方法区,会在堆中产生一个包含类中所有信息的Class对象
  2. 链接:验证class文件信息,以及初始化静态变量。如是static m=0;
  3. 初始化:
    执行< clinit >(){}方法,对类中的静态代码和静态常量进行合并到方法体中进行执行
/**
初始化方法:
	clinit(){
		sout("A类的静态代码块初始化")//1;
		m=300;
	}
*/
Class A{
	static{
	sout("A类的静态代码块初始化")//1;
	m=300;//2
	}
	static int m=100//3;
	public A(){
	sout("A类的无参构造初始化")//4}
}

在这里插入图片描述

类加载器
  1. 引导类加载器:用来加载核心类库。该加载器无法直接获取。
  2. 扩展类加载器:负责加载jre/lib/ext目录下的jar包或者-D java.ext.dirs指定目录下的jar包的加载
  3. 系统类加载器(常用):负责加载java仙姑classpath下的jar包。

双亲委派模型:多重检测,检测自己写的类在系统加载路径中是否已存在,如果存在则会使用根加载器下的类而不会使用自定义的

使用反射获取

获取Class对象、获取类名、获取变量名、获取方法名、获取构造器

package Test;
//类所在得包路径
//自定义一个类
class Person {
    String name;
    public long idCard;
    Person() {
        this.name = "人类";
    }

    //父类方法
    public String method(String name) {
        System.out.println("带返回类型和参数的方法" + name);
        return name;
    }
}

class Teacher extends Person {
    private int id;
    private String home;
    public String address;
    Teacher() {
        this.name = "老师";
    }

    Teacher(int id, String home) {
        this.id = 1;
        this.name = "老师带参数";
    }

    public void method1() {
        System.out.println("public修饰的无参方法");
    }

    void method2() {
        System.out.println("无参方法");
    }

    public String method3(String name) {
        System.out.println("带返回类型和参数的方法" + name);
        return name;
    }
}

获取类的变量

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
/**
 获取类的信息*/

        Class aClass = Class.forName("test.Teacher");
        //1.1获取类的变量
        //获取本类以及父类中public修修饰的变量
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("---------------------");
        //获得本类中的所有修饰符的属性
        fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("=====================");
        //1.2获取类的具体某一变量
        //获取本类以及父类中public修饰的变量
        Field address= aClass.getField("address");
        Field idCard = aClass.getField("idCard");
        System.out.println(address);
        System.out.println(idCard);
        System.out.println("---------------------");
        //获取本类中任何修饰符的具体变量
        Field id = aClass.getDeclaredField("id");
        System.out.println(id);
        //Field name = aClass.getDeclaredField("name");//获取不到父类中的任何变量
        System.out.println("=====================");
    }
}

获取类的方法:

public class ReflectTest {
    public static void main(String[] args) throws Exception, NoSuchFieldException {
/**
 获取类的信息*/
        Class aClass = Class.forName("test.Teacher");
        //2.1获取类的方法
        //获取本类和父类的public修饰的所有方法
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("-----------------");
        //获取本类中所有修饰类型的方法
        methods=aClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("================");
        //2.2获取具体某一的方法:参数一:方法名,参数二:形参参数类型--->解决重载带来的方法的识别
        //获取本类以及父类中public修饰的方法
        Method method1 = aClass.getMethod("method1", null);
        System.out.println(method1);
        Method method = aClass.getMethod("method", String.class);
        System.out.println(method);
        System.out.println("-----------------");
        //获取本类中任意修饰符的某一方法
        Method method2 = aClass.getDeclaredMethod("method2", null);
        System.out.println(method2);
        Method method3 = aClass.getDeclaredMethod("method3", String.class);
        System.out.println(method3);
    }
}

获取类的构造器:

	
public class ReflectTest {
    public static void main(String[] args) throws Exception, NoSuchFieldException {
/**
 获取类的信息*/
        Class aClass = Class.forName("test.Teacher");
        //3.1获取类的构造器方法
        //获取本类的public修饰构造器方法
        Constructor[] constructors = aClass.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("-------------------");
        //获取本类中所有修饰类型的构造器函数
        Constructor[] cs = aClass.getDeclaredConstructors();
        for (Constructor c : cs) {
            System.out.println(c);
        }
        System.out.println("================");
        //3.2获取某一个具体的构造器;参数:构造器形参的参数类型的class
        //获取本类的public修饰的构造方法
        Constructor c = aClass.getConstructor();
        System.out.println(c);
        System.out.println("-----------------");
        //获取本类中任何修饰符的构造器方法
        Constructor cons = aClass.getDeclaredConstructor(int.class);
        System.out.println(cons);
        Constructor cons1 = aClass.getDeclaredConstructor(int.class,String.class);
        System.out.println(cons1);
    }
}

使用反射 *

  1. 创建对象的实例
    创建无参构造时可以通过class对象的newInstance()方法直接创建。
    根据有参构造创建时可以通过获取有参构造器然后使用构造器的newInstance(参数值)方法进行创建

  2. 执行对象对象的方法
    通过class对象的getMethod(参数一:方法名,参数二:方法参数的类型)方法获取到相应方法,执行invoke(参数一:所属对象,参数二:方法所需要的参数的值)激活方法来执行获取到的方法

  3. 直接给属性赋值
    先获取field对象然后执行set(参数一:要操作的对象,参数二:要设置的值)方法

  4. setAccessible():可以提高反射效率
    当方法、构造器或者属性对象在对应类中的修饰符为private时,在使用这些对象执行某些操作之前设置暴力反射即可正常获取和执行
    当权限不足时可以设置暴力反射,即关闭了代码的安全检测
    属性or方法名.setAccessible(true);
    如给私有属性赋值时失败

如执行类的private类型的方法时在invoke之前设置即可
如在使用类的private构造器创建对象时,在此之前设置即可


/**
 获取类的信息*/
        Class aClass = Class.forName("test.Teacher");
        //1.实例化一个对象
        //1.1根据无参构造器创建对象
        Teacher teacher = (Teacher) aClass.newInstance();
        System.out.println(teacher);
        //1.2根据有参构造器创建对象
        Constructor c = aClass.getDeclaredConstructor(int.class, String.class);
        System.out.println(c);
        Object o = c.newInstance( 2, "有参");
        System.out.println(o);
        System.out.println("=================");
        //2.执行对象的方法
        Method methot1 = aClass.getDeclaredMethod("method1");
        System.out.println(teacher);
        methot1.invoke(teacher);
        methot1=aClass.getDeclaredMethod("method3", String.class);
        methot1.invoke(teacher,"为方法的home属性传递的参数");
        System.out.println(teacher);
        System.out.println("=================");
        //3.取消安全性检测
        //通过私有构造器实例化对象
        Constructor c1 = aClass.getDeclaredConstructor(int.class);
        c1.setAccessible(true);
        Teacher o1 = (Teacher) c1.newInstance(5);
        System.out.println(o1);
        //3.2执行私有方法
        Method method2 = aClass.getDeclaredMethod("method2");
        method2.setAccessible(true);
        method2.invoke(teacher);
        
        //4.给对象的属性赋值
        Field name = aClass.getDeclaredField("home");
        name.setAccessible(true);
        name.set(teacher,"反射给name设置值");//home为private修饰需要修改安全监测
        System.out.println(teacher);

setAccessible提升效率测试

public class ReflectTest {
    public static long start;
    public static long end;

    public static void test1() {
        Teacher teacher = new Teacher();
        start = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            teacher.method1();
        }
        end = System.currentTimeMillis();
        System.out.println("new :" + (end - start));
    }
    public static void test2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class<?> aClass = Class.forName("test.Teacher");
        Teacher o = (Teacher) aClass.newInstance();
        Method method1 = aClass.getDeclaredMethod("method1");
        start = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            method1.invoke(o);
        }
        end = System.currentTimeMillis();
        System.out.println("Class :" + (end - start));
    }
    public static void test3() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class<?> aClass = Class.forName("test.Teacher");
        Teacher o = (Teacher) aClass.newInstance();
        Method method1 = aClass.getDeclaredMethod("method1");
        method1.setAccessible(true);
        start = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            method1.invoke(o);
        }
        end = System.currentTimeMillis();
        System.out.println("Class+Accessible :" + (end - start));
    }

    public static void main(String[] args) throws Exception, NoSuchFieldException {
        //3.3提高反射效率
        //对象执行方法通过new出的
        test1();//new :4
        //通过反射执行方法
        test2();//Class :257
        //通过反射执行方法且关闭检查机制
        test3();//Class+Accessible :136
        System.out.println("毫秒");
        }
 }

反射获取泛型信息

了解即可
在这里插入图片描述

在这里插入图片描述

https://www.bilibili.com/video/BV1p4411P7V3?p=15&spm_id_from=pageDriver

反射获取注解信息

此处用于帮助理解框架的底层原理

package test;

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class AnnoationRTest {
    public static void main(String[] args) throws Exception {
        Class aClass = Class.forName("test.Student");
        //1.通过反射获取类上所有注解;不会获取属性和方法上的注解
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);//@test.TableMy(value=tb_student)
            //获取所有注解时不建议使用因为可能有其他类型的注解
            TableMy b = (TableMy) annotation;
            String value = b.value();
            System.out.println(value);
        }
        //2.通过反射获取类上注解中的值
        TableMy m = (TableMy) aClass.getAnnotation(TableMy.class);
        String value = m.value();
        System.out.println(value);

        //3.反射获取类的属性上的注解
        Field id = aClass.getDeclaredField("id");
        FieldMy f = id.getAnnotation(FieldMy.class);
        System.out.println(f.columnName());//tb_id
        System.out.println(f.type());//int
        System.out.println(f.length());//10
        //4.反射获取方法上的注解也是先获取方法对象,后获取注解对象取得其值
    }

}

/**
 * 自定义pojo类对应数据库中的tb_student表
 */
@TableMy("tb_student")
class Student {
    @FieldMy(columnName = "tb_id", type = "int", length = 10)
    private int id;
    @FieldMy(columnName = "tb_name", type = "varchar", length = 20)
    private String name;
    @FieldMy(columnName = "tb_address", type = "varchar", length = 50)
    String address;

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Student() {
    }

    public Student(int id, String name, String address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }
}

/**
 * 自定义表对应注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableMy {
    String value();
}

/**
 * 自定义表字段对应注解
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldMy {
    String columnName();//列名称

    String type();//列数据类型

    int length();//数据长度
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-29 11:30:08  更:2021-07-29 11:30:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 10:12:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码