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知识库 -> 封装、反射、Spring -> 正文阅读

[Java知识库]封装、反射、Spring

引言

变量

假设写一段打印向量维度的代码,多次打印某个值

print(100);
//业务逻辑
print(100);
//业务逻辑
print(100);

这里需要修改打印值的时候,需要修改三处,为了避免这种重复工作,可以用一个变量a表示常量

a = 100
print(a);
//业务逻辑
print(a);
//业务逻辑
print(a);

这样以后想要打印不同的值,只要修改a = 100 这一处就行了,这时第一级封装

方法

考虑上面这处代码段,如果每次需要这个业务逻辑都把这个代码段复制粘贴过去,就会出现很多冗余代码,极不美观,解决办法依然是封装,把这段代码写进一个方法,哪里用到只要调用这个方法即可,这时第二级封装

public void printNum(int a){
    a = 100
    print(a);
    //业务逻辑
    print(a);
    //业务逻辑
    print(a);
}

如此一来,以后需要这个逻辑处理,只需简单的调用printNum(100)即可,原始的代码段只在方法中出现了一次而不是哪里用到写哪里,提高了代码复用率。

有时候需要被服用的代码段不仅仅是几个变量或是某个方法,而是若干变量和方法的组合,如何将它们组织成一种方便使用的数据结构?答案是类,一种由成员变量,方法构造器组成的数据结构。

class PrintNum{
    int a;
	public PrintNum(){}
    public PrintNum(int a){this.a = a;}
    public void printNum(int b){
        b = 100
        print(b);
        //业务逻辑
        print(b);
        //业务逻辑
        print(b);
    }
}

通过这样的定义,我们只需要实例化一个PrintNum类型的对象PrintNum p = new PrintNum();就可以同时使用p的成员变量和方法,进一步提高了封装等级和代码复用率。

反射

? 上面的封装都考虑到了一件事:某些变量的值可能需要在实际被调用的时候才知道,所以不能在业务逻辑中写死,而是留一个形参以供调用者自己定义。现在考虑这样一种情况:项目里有很多类可以使用,在程序运行之前不知道要实例化谁(也就是程序员编代码的时候并不知道用户用哪些不用哪些,那就没办法提前实例化了),或者说要在运行时根据用户的输入决定实例化哪个类。说起来有点抽象,举个吃苹果的例子,程序需要根据用户的选择来决定实例化一个苹果还是别的以供食用:

public class Eat{
    public Eat(){}
    public void eat(){
		print("请输入您要吃的食物");
        Scanner sc = new Scanner(System.in);
        String food = sc.next();
        if(food.equals("apple")){
            Apple apple = new Apple();
            apple.eat();
        }
        else{
			SomethingElse se= new SomethingElse(); 
            es.eat();
        }
    }
}

? 上面这段代码由于事先不知道要实例化谁,使用判断语句来处理这个逻辑,缺点很明显,有多少个选项就要有多少个逻辑判断,代码主键臃肿。现在思考有没有一种方法能够在运行时更加优雅的实例化一个类,就像封装方法那样留出一个形参来决定实例化哪个类。

答案是有:反射。

首先依然考虑封装,有没有一种方法将所有的类都组织起来以供使用。就像类是一个把成员变量、构造器和方法组织起来的数据结构一样,有没有一种数据结构能把所有的类组织起来?答案是Class类,具体地说,每一个Class类的实例都对应一个类。

知识点

  • 项目中有多少类就有多少个对应的Class实例
  • 想要实例化哪个类只需要获取对应的Class对象即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0wvH5snS-1665134565364)(H:\gitfile\modiman.github.io\docs_posts\imgs\image-20221007164218924.png)]

那么在运行时,只要获取到了用户的需求,就可以定制实例化对象。

Class类

获取Class实例

获取class实例常用三种方法

  1. 类名.class:这种获取方式只有在编译前已经声明了该类的类型才能获取到 Class 对象
Class clazz = Students.class;
  1. 实例.getClass():通过实例化对象获取该实例的 Class 对象
Students sp = new Students();
Class clazz = sp.getClass();
  1. Class.forName(className):通过类的全限定名获取该类的 Class 对象
Class clazz = Class.forName("com.bean.Students");

构造类的实例化对象

通过反射构造一个类的实例方式有2种:

  1. Class 对象调用newInstance()方法
Class clazz = Class.forName("com.bean.Students");
Students stu = (Students) clazz.newInstance();
stu.getInfo();
// [null 的年龄是:0]
复制代码

即使 Students 已经显式定义了构造方法,通过 newInstance() 创建的实例中,所有属性值都是对应类型的初始值,因为 newInstance() 构造实例会调用默认无参构造器。

  1. Constructor 构造器调用newInstance()方法
Class clazz = Class.forName("com.bean.Students");
Constructor constructor = clazz.getConstructor(String.class, int.class);
constructor.setAccessible(true);
Students stu = (SmallPineapple) constructor.newInstance("苏世", 25);
stu.getInfo();
// [苏世 的年龄是:25]

通过Class对象调用 newInstance() 会走默认无参构造方法,如果想通过显式构造方法构造实例,需要提前从Class中调用getConstructor()方法获取对应的构造器,通过构造器去实例化对象。

应用场景

Spring IOC

Spring IOC的一种重要实现方式-依赖注入(DI)就需要使用反射的方式

首先Spring项目由一堆Bean组成,Bean本质上就是包括Controller、Model、Service等等在内的所有类

因为由用户管理这些Bean的实例化会使项目变得臃肿,所以Spring将对Bean的控制权交给了容器,这就叫控制反转

从本质上讲,java项目的运行逻辑就是实例化要使用的类得到对象,对这些对象进行操作。

在Spring中也不例外,使用model类的Bean封装数据,使用Service型的Bean处理业务逻辑,使用Controller型的Bean控制前后端的交互

之前已经说过,Spring将Bean的控制权交给了容器,那么容器什么时候实例化Bean?

两种加载

  • 立即加载:容器在项目启动时实例化所有的类并将对象存放进容器
  • 懒加载:容器在第一次使用Bean的时候才加载类

IOC中的反射

Spring使用xml配置bean,容器可以根据xml中Bean的全限定名获取Class实例得到Bean实例

AOP

AOP,面向切面编程,将业务逻辑剥离分层,分成一个一个的切面,将那些可以复用的非核心逻辑如日志从显式存在于代码中改为动态代理添加的方式,既能使代码更简洁,又能解耦合

AOP基于动态代理实现,动态代理基于反射实现

动态代理,运行时增强。比如有一个实现了某个接口的类,想要给他的某个方法添加一些功能,就可以使用动态代理创建一个同样实现了这个接口的代理类,重写要增强的方法并加入要添加的功能

以日志为例说明。在一个类中,有多个方法(连接点),现在想给其中的几个方法(切点)添加日志功能,

首先要知道日志添加在方法执行前还是执行后已经具体怎么做(处理),之后根据定义一个由切点和处理组成的切面类

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

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年3日历 -2025/3/10 15:46:41-

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