JAVA反射机制及其原理实现_java反射机制原理详解-程序员宅基地

技术标签: Java  java反射  反射源码  java字节码  java反射实现原理  反射机制  

视频讲解

9.1 概念

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;public、protected、private。

OO(面向对象),private私有的,不能访问。这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。**

反射就是把java类中的各种成分映射成一个个的Java对象 例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。

物理:有个反射的概念,通过镜子,可以知道物体的存在。看到一个镜像或名字等,知道物体在哪里。

(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述) 如图是类的正常加载过程:反射的原理在与class对象。 熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。

Student.java--->Student.class 经过编译成了一个字节码文件。

img

9.2 作用

在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符。阅读源码发现,经过层层调用后在最终返回结果的地方对应用的权限进行了校验,对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的。

反射是框架设计的灵魂

(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

9.2.1 反编译:.class-->.java

9.2.2通过反射机制访问java对象的属性,方法,构造方法等;

User user=new User();--》形成的java文件-->XXX.class

将来赋值的时候,不是User类,是不是就报错了啊。存在紧耦合的状态,我们做OO的目的就是高内聚、松耦合,说白了,就是模块内部实现特定功能,模块与模块之间,关联度不大。

这种方式,是编译时

我们以后写程序,更多的应该是运行时给值。

9.3 反射机制的相关类

与Java反射相关的类如下:

类名 用途
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法

9.3.1 查看Class类在java中的api

img

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型) Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。

没有公共的构造方法,方法共有64个太多了。下面用到哪个就详解哪个吧 img

9.3.2 根据一个字符串得到一个类

类名 方法 含义
String getClass 表示此对象运行时类的 Class 对象
Class forName 具有指定名的类的 Class 对象
包装类 属性Type

参考代码:

         String str="今天是反射课程";
         Class clz=str.getClass();//得到当前正在运行的类;
         System.out.println(clz);
         Class clz2=Integer.TYPE; //包装类型,不同;包装类.Type
         System.out.println(clz2);
         System.out.println(Boolean.TYPE);
         System.out.println(Double.TYPE);
         System.out.println(Character.TYPE);
 ​

9.3.3 获取Class对象的 三种方式

  • Object:getClass

  • 任何数据类型(包含基本数据类型)都有一个"静态"的class属性,这时候可以通过类名.属性访问.

  • 通过Class类的静态方法:forName(string className路径)

参考代码

//1.使用第一种方式来获取User的Class对象;
         User user=new User(); //弄了一个User对象,在内存里面;
         Class clz1=user.getClass(); //对象.getClass
         System.out.println(clz1); //clz1:是什么类呢?com.aaa.chapter07.User;路径+类名;
         //2.使用第二种方式;
         Class clz2=User.class;      //类名.class 这个静态属性.
         System.out.println(clz2);
         //这时候,我们是不是考虑一下,之前讲的那个原理图。证明原理图,里面,正在运行的Class是一个。
         System.out.println(clz1==clz2);
         //3.Class.forName(类路径方式)
         try {
             Class clz3=Class.forName("com.aaa.chapter07.User");
             System.out.println(clz3);
             System.out.println(clz2==clz3);
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         }

提问?最常用哪种?一般用第三个。松耦合方式。

9.3.4 通过反射来获取构造方法

调用方法:

1.获取构造方法:

1).批量的方法: public Constructor[] getConstructors():所有"公有的"构造方法 public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)

2).获取单个的方法,并调用: public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法: public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;

例如:

调用构造方法: Constructor-->newInstance(Object... initargs)

package com.aaa.chapter07;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;

/**
 * Created by 张晨光 on 2020/3/10 10:24
 */
public class Constructors {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class clz=Class.forName("com.aaa.chapter07.User");
        //2.获取所有公共字段;
//        Field[] fields = clz.getFields();
//        for(Field f:fields){
//            System.out.println(f);
//        }
        //2.获取所有共有 私有字段;
//        Field[] fields = clz.getDeclaredFields();
//        for(Field f:fields){
//            System.out.println(f);
//        }
        Field field=clz.getField("country");
        System.out.println(field);
        Object obj=clz.getConstructor().newInstance();
        field.set(obj,"中国");
        User u=(User)obj;
        System.out.println(u.getCountry());
    }
}

2、newInstance是 Constructor类的方法(管理构造函数的类) api的解释为: newInstance(Object... initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。 它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用

package com.aaa.chapter07;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * Created by 张晨光 on 2020/3/10 22:29
 */
public class InstanceDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class clz=Class.forName("com.aaa.chapter07.User");
        //1.调用第一个默认构造方法,没有参数,创建实例之后,再次使用setter赋值。
//        Constructor constructor = clz.getConstructor();//Alt+Enter,
//        Object obj=constructor.newInstance();
//        User user=(User)obj;
//        user.setName("张老师");
//        System.out.println(obj);
        //2.调用第二个有3个参数的构造方法,公共的构造方法,注意里面参数的使用方式.
//        Constructor constructor2 = clz.getConstructor(String.class,char.class,Integer.class);
//        Object obj2=constructor2.newInstance("张晨光",'男',18);//类似于之前的构造方法,填充值;
//        User user2=(User)obj2;
//        System.out.println(user2);
        //3.调用第三个私有构造方法,这个构造方法,我们说外部无法访问.
        Constructor declaredConstructor = clz.getDeclaredConstructor(String.class);
        //设置私有构造方法,可以访问,强制(暴力)访问.
        declaredConstructor.setAccessible(true);
        Object obj=declaredConstructor.newInstance("登徒子");

        User user3=(User)obj;
        System.out.println(user3);
    }
}

9.3.5 获取成员变量并调用

获取成员变量并调用:

1.批量的

1).Field[] getFields():获取所有的"公有字段"

2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;

2.获取单个的:

1).public Field getField(String fieldName):获取某个"公有的"字段;

2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)

设置字段的值:

Field --> public void set(Object obj,Object value):

参数说明:

1.obj:要设置的字段所在的对象;

2.value:要为字段设置的值;

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhangchen124/article/details/104786250

智能推荐

torchvision.datasets.FashionMNIST报错[WinError 10054] 远程主机强迫关闭了一个现有的连接_torchvision.datasets下载mnist显示远程主机强迫关闭了一个现有的连接-程序员宅基地

文章浏览阅读1.5k次,点赞6次,收藏6次。项目场景: 在李沐老师视频课Softmax 回归 + 损失函数 + 图片分类数据集【动手学深度学习v2】中用到了FashionMNIST数据集。问题描述:trans = transforms.ToTensor()#下载到上一级目录的data文件中,下载的是训练数据集,类型时tensor,从网上下载mnist_train = torchvision.datasets.FashionMNIST( root="../data", train=True, transform=trans, down_torchvision.datasets下载mnist显示远程主机强迫关闭了一个现有的连接

Python 子类不可以直接访问父类的私有方法和私有属性_python 私有成员变量 子类没法调用?-程序员宅基地

文章浏览阅读2.7k次。子类对象不能在自己的方法内部直接访问父类的私有方法和私有属性。注意:在对象的方法内部是可以访问自己所在类的私有属性和私有方法。代码举例:class A(): #父类 def __init__(self): self.num1 =100 self.__num2 = 200 def __test(self): ..._python 私有成员变量 子类没法调用?

【完结篇】c# winfrom 工作流程图开发、自动表单开发、拖拽控件、流程图自定义拖拽连线、 全自动报表表单设计_c# 开发拖拽流程软件-程序员宅基地

文章浏览阅读2.1k次,点赞5次,收藏8次。报表配置完毕后,前端可以进行根据配置条件筛选结果。表单自由设计,支持全选、移动等功能。报表配置,根据表单自动配置报表。系统设置-角色与权限管理。流程节点配置-经办人。流程节点配置-可写字段。流程节点配置-流转设置。..._c# 开发拖拽流程软件

大数据考研毕设选题推荐-程序员宅基地

文章浏览阅读791次,点赞17次,收藏7次。且不提你是否真的有能力做毕设的时候把初试准备好(我自认做不到分心,为了备战初试,我几乎大四所有课程都是70左右飘过),你能保证你的毕设内容一定和目标院校的复试考察内容相关或者能成为老师眼中的加分点吗?因为考试是一件“千人过独木桥”的事情。拿我们计算机举例子,A的毕设就是一个在线网站,当时老师体谅A要二战,给了我个简单的题目,确实,毕设比别人轻松多了(相对而言,别人都是什么算法,这那的)大部分人的精力集中度是有限的,我还是建议优先做当前最重要的事情,如果考研是你当下最看重的事情,建议你有限把考研做好。

轻量级分布式文件系统FastDFS使用安装说明手册(新手入门级)_fastfs windows-程序员宅基地

文章浏览阅读2w次。轻量级分布式文件系统FastDFS使用安装说明手册(新手入门级)_fastfs windows

use of deleted function ‘std::basic_istream<_CharT, _Traits>::basic_istream(const std::basic_istream_use of deleted function 'std::basic_fstream<_chart-程序员宅基地

文章浏览阅读844次。下述代码报错,原因是因为istream后漏了一个 &//从输入流中将家庭作业的成绩读入到一个vector<double>中istream read_hw(istream& in, vector<double>& hw){ if (in) { //清除vector原先的内容 hw.clear(); //读家庭作业成绩 double x; while (in >_use of deleted function 'std::basic_fstream<_chart, _traits>::basic_fstream(

随便推点

Unicode的基本知识总结_61448 uncode是什么-程序员宅基地

文章浏览阅读680次。Unicode的基本知识总结前言一、Unicode是什么?二、Unicode的编码与实现1.Unicode的编码方式2.Unicode的实现方式总结前言秋招面试某公司的时候,面试官突然发难,问起了Unicode的相关知识,使我手足无措,今天抽出时间来专门学习整理一下相关知识一、Unicode是什么?Unicode,中文又称万国码、国际码、统一码、单一码,是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。二、Unicode._61448 uncode是什么

富文本编辑器:editor.md_editor编辑器-程序员宅基地

文章浏览阅读2.7k次,点赞5次,收藏21次。富文本编辑器Editormd简介Editor.md——功能非常丰富的编辑器,左端编辑,右端预览,非常方便,完全免费官网:https://pandao.github.io/editor.md/主要特征支持“标准” Markdown / CommonMark 和 Github 风格的语法,也可变身为代码编辑器;支持实时预览、图片(跨域)上传、预格式文本/代码/表格插入、代码折叠、搜索替换、只读模式、自定义样式主题和多语言语法高亮等功能;支持 ToC 目录(Table o_editor编辑器

一读就错的68个姓氏,第一个就读错了_任作为姓氏很多人读错-程序员宅基地

文章浏览阅读733次。一读就错的68个姓氏,第一个就读错了转载:http://cul.qq.com/a/20170414/032417.htm[摘要]我国有很多姓氏,看起来都是常见的字,一写就会,可是一读,就不是那个样子了,往往读错,让人啼笑皆非。我国有很多姓氏,看起来都是常见的字,一写就会,可是一读,就不是那个样子了,往往读错,让人啼笑皆非。中国的姓氏中,除了有生僻字,还有不少容易读错的姓_任作为姓氏很多人读错

Error downloading packages: qt3-3.3.8b-51.el7.x86_64: [Errno 256] No more mirrors to try._no presto metadata available for base-程序员宅基地

文章浏览阅读7.6k次。Error downloading packages: qt3-3.3.8b-51.el7.x86_64: [Errno 256] No more mirrors to try. 1:qt-x11-4.8.7-2.el7.x86_64: [Errno 256] No more mirrors to try. 解决办法_no presto metadata available for base

matlab cell2mat 函数将元胞转换成数值矩阵出错_m{n} = cat(1,c{:,n});-程序员宅基地

文章浏览阅读1.5w次,点赞5次,收藏19次。matlab cell2mat 函数将元胞转换成数值矩阵出错matlab 中经常涉及到各种数据类型的转换。在将元胞型转换成数值矩阵的过程中我遇到了一个非常有趣的问题,代码如下:% 元胞型转换为数值型矩阵close allclearclc% 这个data中的price是从excel中读取的数据并做在matlab中做了一定转换处理load data% 生成元胞型矩阵,m1整数型,m2浮..._m{n} = cat(1,c{:,n});

Python读取json文件-程序员宅基地

文章浏览阅读4.5w次,点赞22次,收藏91次。使用Python读取json文件,并输出为两种不同类型(python对象、字符串)的数据._python读取json文件

推荐文章

热门文章

相关标签