Spring IoCDI(3)—DI详解

目录

一、属性注入

二、构造方法注入

小结:构造函数的注入

三、Setter注入

四、三种注入的优缺点分析(面试题)

1、属性注入

优点:

缺点:

2、构造方法注入(Spring4.X推荐)

优点:

缺点:

3、Setter注入(Spring3.X推荐)

优点:

五、@Autowired存在问题

1、引入Autowired的错误代码:

(1)属性注入:

(2)构造方法注入:

(3)Setter方法注入:

(4)启动类代码:

2、Autowired查找依赖顺序:

3、解决方案

(1)解决方案一:根据名称去查

(2)解决方案二:给想要拿到的对象加上@Primary注解

(3)解决方案三:加@Qualifier注解,指定引入的依赖对象

(4)解决方案四:加@Resource注解

4、@Autowired 与 @Resource 的区别(常见面试题)

六、Spring IoC&DI 的总结

1、Spring,Spring Boot 和 Spring MVC的关系以及区别

(1)Spring

(2)Spring MVC

(3)Spring Boot

(4)总结

2、bean的命名

(1)五大注解存储的bean

(2)@Bean注解存储的bean

3、常见面试题


        上篇博客学习了控制反转IoC的细节,接下来就开始学习依赖注入DI的细节。

        依赖注入是一个过程是指IoC容器在创建Bean时,去提供运行时所依赖的资源,而资源指的就是对象。我们使用 @Autowired 注解,完成依赖注入的操作。

        简单来说,就是把对象取出来,放到某个类的属性中。在一些文章中,依赖注入也被称之为 “对象注入”、“属性装配”,具体含义需要结合文章的上下文来理解。

        关于依赖注入,Spring也给我们提供了三种方式:

1、属性注入(Field Injection)

2、构造方法注入(Construct Injection)

3、Setter 注入(Setter Injection)

一、属性注入

        属性注入是使用 @Autowired 实现的,将UserService 类注入到UserController类中,UserService 类代码如下:

@Service
public class UserService {
    public void doService() {
        System.out.println("do Service...");
    }
}

        UserController类的实现代码如下:

@Controller
public class UserController {
    //注入方法1:属性注入
    @Autowired
    private UserService userService;
    public void sayHi() {
        userService.doService();
        System.out.println("hi, UserController");
    }
}

        启动类获取到UserController的doService方法,代码如下:

@SpringBootApplication
public class SpringIoC2Application {
    public static void main(String[] args) {
        //获取Spring上下文对象
        ApplicationContext context = SpringApplication.run(SpringIoC2Application.class, args);
        //从Spring上下文中获取对象
        UserController userController = (UserController) context.getBean("userController");
        //使用对象
        userController.doService();
    }
}

        执行结果:

        如果去掉 注解@Autowired,再运行一下程序,结果如下:

        报错了,提示空指针异常,没办法调用doService() 方法,因为userServer为空。原因就是没有加@Autowired注解,没有注入依赖,Spring拿不到这个属性,也自然不会给它初始化了,那么它肯定就是一个空指针了

二、构造方法注入

        构造方法注入就是在类的构造方法中实现注入,代码如下:

@Controller
public class UserController {
    //注入方法2:构造方法注入
    private UserService userService;
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
    public void doController() {
        userService.doService();
        System.out.println("do UserController");
    }
}

注意事项如果类只有一个构造方法,那么@Autowired注解可以省略;但如果类有多个构造方法,那么就需要添加上@Autowired来明确指定要使用哪个构造方法了。下面的代码练习:

@Controller
public class UserController {
    //注入方法2:构造方法注入
    private UserService userService;
    public UserController(){
        
    }
    public UserController(UserService userService) {
        this.userService = userService;
    }
    public void doController() {
        userService.doService();
        System.out.println("do UserController");
    }
}

        加了个无参的构造函数,运行程序会报错,如图:

        报错解释空指针异常,虽然这个类交给Spring管理了,Spring内部也会给我们自动创建对象,但也是通过构造函数创建的,这里我们写了两个构造函数,如果不加@Autowired注解,Spring默认使用无参构造函数,自然也就没有成功创建对象了,那么这个userService也自然是空指针了

        现在代码改一下,把无参构造函数注释掉,再加一个构造函数,代码如下:

@Controller
public class UserController {
    //注入方法2:构造方法注入
    private UserService userService;
    private UserComponent userComponent;
//    public UserController(){
//
//    }
    public UserController(UserService userService) {
        this.userService = userService;
    }
    public UserController(UserService userService, UserComponent userComponent) {
        this.userService = userService;
        this.userComponent = userComponent;
    }
    public void doController() {
        userComponent.doComponent();
        userService.doService();
        System.out.println("do UserController");
    }
}

        运行代码报错了,报错信息如下:

        报错解释没有找到默认的构造方法,因为这里出现了两个构造方法,Spring不知道该用哪个,现在给第二个构造方法加上@Autowired注解,表示让Spring使用被注解的构造方法,代码如下:

@Controller
public class UserController {
    //注入方法2:构造方法注入
    private UserService userService;
    private UserComponent userComponent;
//    public UserController(){
//
//    }
    public UserController(UserService userService) {
        this.userService = userService;
    }
    @Autowired
    public UserController(UserService userService, UserComponent userComponent) {
        this.userService = userService;
        this.userComponent = userComponent;
    }
    public void doController() {
        userComponent.doComponent();
        userService.doService();
        System.out.println("do UserController");
    }
}

        运行结果:

        程序跑起来了。

小结:构造函数的注入

1只有一个构造函数的情况,可以不加@Autowired

2如果有多个构造函数,需要指定默认的构造函数(通过@Autowired指定,如果未指定,默认使用无参的构造函数)

构造规范如果添加构造函数,把无参构造函数显示添加(也就是把构造函数写下来,再给注释掉)


三、Setter注入

        Setter注入和属性的Setter方法实现类似,只不过在set方法的时候需要加上@Autowired注解,代码如下:

@Controller
public class UserController {
    private UserService userService;
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    public void doController() {
        userService.doService();
        System.out.println("do UserController");
    }
}

        启动类代码:

@SpringBootApplication
public class SpringIoC3Application {
    public static void main(String[] args) {
        //拿到Spring上下文
        ApplicationContext context = SpringApplication.run(SpringIoC3Application.class, args);
        //拿到Spring上下文对象
        UserController userController = context.getBean(UserController.class);
        //使用对象
        userController.doController();
    }
}

        执行结果:

        如果我们把@Autowired注解去掉呢?结果如下:

        又是空指针异常,原因和属性注入把@Autowired的情况一样。


四、三种注入的优缺点分析(面试题)

1、属性注入

优点:

        1、简洁、使用方便

缺点:

        1、只能用于IoC容器,如果非IoC容器则不可用,并且只有在使用的时候才会回出现NPE(空指针异常)

        2、不能注入一个final修饰的属性

1 的解释:

        可以看到,它的来源是Spring的,那么就只能用于IoC容器了。

2 的解释:

        final修饰的属性有个特点,必须初始化,如果我们给属性加上final,会有两种解决方案:1、提供构造函数,如图:

        如果加上构造方法,那不就是构造方法注入了吗,也就不是属性注入了,违背了初心。

        2、给它初始化,new 一个对象,如图:

        但是这样不就是我们自己管理我们的代码了吗,并不是Spring帮我们管理了,也违背了初心。

2、构造方法注入(Spring4.X推荐)

SpringBoot和Spring的版本号对应:

Spring Boot3.X -> Spring 6

Spring Boot2.X -> Spring 4

优点:

        1、可以注入final修饰的属性

        2、注入的对象不会被修改

        3、依赖对象在使用前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的方法

        4、通用性好,构造方法是JDK支持的,所以更换任何框架,它都是适用的

1 的解释:final修饰的属性要初始化,构造方法会进行初始化,复合它的要求。

2 的解释:因为构造方法在这个类创建的时候就会给它进行赋值了,不会再对它进行修改。

3 的解释:在类加载的这个阶段,就会执行构造方法了,把依赖对象给初始化完成。

4 的解释:因构造方法是JDK支持的,不再Spring框架也能正常的使用。

缺点:

        1、注入多个对象时,代码会比较繁琐

3、Setter注入(Spring3.X推荐)

优点:

        1、方便在类实例之后,重新对该对象进行配置或注入

1 的解释:因为Setter方法是可以被其他地方调用的,所以即使类已经被实例化了,也可以重新对该对象进行配置或注入。

缺点:

        1、不能注入一个final修饰的属性

        2、注入对象可能会被改变,因为Setter方法可能会被多次调用,就有被修改的风险

1 的解释:因为可能会被多次修改,所以不能使用final修饰。

2 的解释:Setter方法当然能被修改了,这即使它的优点,也是它的缺点。

4、Autowired查找依赖顺序:

1、根据名称和类型去查

2、如果根据名称查不到,就会根据类型去查

        根据名称查不到了,去查找类型,这时如果类型匹配多个,就会报错


五、@Autowired存在问题

        当同一类型存在多个bean时,使用@Autowired会存在问题。代码如下:

@Component
public class BeanConfig {
    @Bean
    public UserInfo userInfo1() {
        UserInfo user = new UserInfo();
        user.setId(6);
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }

    @Bean
    public UserInfo userInfo2() {
        UserInfo user = new UserInfo();
        user.setId(7);
        user.setName("lisi");
        user.setAge(19);
        return user;
    }
}

        此时我们在UserController类里面注入UserInfo类,代码如下:(下面这几个的注入方式都是错误的)

1、引入Autowired的错误代码:

(1)属性注入:

@Controller
public class UserController {
    @Autowired
    private UserInfo userInfo;

    public void sayHi() {
        System.out.println("hello, controller");
    }
}

        可以看到,还没运行代码,就报红线了,如图:

(2)构造方法注入:

@Controller
public class UserController {
    private UserInfo userInfo;
    @Autowired
    public UserController(UserInfo userInfo) {
        this.userInfo = userInfo;
    }
}

        这个也是,还没运行代码,就报红线了,如图:

(3)Setter方法注入:

@Controller
public class UserController {
    private UserInfo userInfo;
    @Autowired
    public void setUserInfo(UserInfo userInfo) {
        this.userInfo = userInfo;
    }

    public void sayHi() {
        System.out.println("hello, controller");
    }
}

        可以看到,这个也报红线了,如图:

(4)启动类代码:

@SpringBootApplication
public class SpringIoC3Application
{
    public static void main(String[] args) {
        //拿到Spring上下文
        ApplicationContext context = SpringApplication.run(SpringIoC3Application.class, args);
        //拿到Spring上下文对象
        UserController bean = context.getBean(UserController.class);
        //使用对象
        bean.sayHi();
    }
}

上面这三种方式注入都会出问题,启动程序后,而报错信息也都是一样的(有两个细微的差别,Field和Parameter,下面会介绍),如下图:

        可以看到,程序还没启动就失败了,可以看出来,Spring的依赖注入是在项目启动前就开始注入的了。

        上面报错提示UserController类需要一个bean,但是有两个,下面也打印出是哪两个bean了,Action介绍的就是解决方案。报错日志非常详细

        报错信息说UserController类找不到依赖注入的是哪一个,因为有多个方法被@bean注释,而依赖注入时,三个方法的属性名都是userInfo,先根据userInfo名称查找,但BeanConfig类没有这个方法名,那就只能去根据类名找了,但有2个bean,Spring就不知道要找那个了,并不是@bean注释下的方法名(userInfo1 / userInfo2),Spring并不知道该注入哪个依赖,所以报错了

        在项目启动失败,可以把Filed看都属性,如图:这个是使用属性注入的,会有Field

        构造方法和Setter注入都是第一张报错图,但就不是Field了,而是Parameter,但其实三种注入的报错原因都是一样的。

        解决方案使用属性注入时,就把属性名改成bean修饰的其中之一的方法名就好了;使用@Parimary注解;使用@Qualifier注解;使用@Resource注解

3、解决方案

(1)解决方案一:根据名称去查

属性名改成bean修饰的其中之一的方法名

属性注入:

@Controller
public class UserController {
    @Autowired
    private UserInfo userInfo2;

    public void sayHi() {
        System.out.println("hello, controller");
    }
}

构造方法注入:

@Controller
public class UserController {
    private UserInfo userInfo;
    @Autowired
    public UserController(UserInfo userInfo2) {
        this.userInfo = userInfo2;
    }
}

Setter方法注入:

@Controller
public class UserController {
    private UserInfo userInfo;
    @Autowired
    public void setUserInfo(UserInfo userInfo2) {
        this.userInfo = userInfo2;
    }

    public void sayHi() {
        System.out.println("hello, controller");
    }
}

        执行结果都一样,这里虽然注入了依赖,但没有用这些依赖,所以打印的都是:hello controller,如图:

(2)解决方案二:给想要拿到的对象加上@Primary注解

这个可以理解为依赖注入后,有多个依赖的方法,但默认使用加了@Primary的方法,代码如下:

UserController类:

@Controller
public class UserController {
    @Autowired
    private UserInfo userInfo;

    public void sayHi() {
        System.out.println(userInfo.toString());
        System.out.println("hello, controller");
    }
}

BeanConfig类:

@Component
public class BeanConfig {
    @Primary
    @Bean
    public UserInfo userInfo1() {
        UserInfo user = new UserInfo();
        user.setId(6);
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }

    @Bean
    public UserInfo userInfo2() {
        UserInfo user = new UserInfo();
        user.setId(7);
        user.setName("lisi");
        user.setAge(19);
        return user;
    }
}

启动类:

@SpringBootApplication
public class SpringIoC3Application
{
    public static void main(String[] args) {
        //拿到Spring上下文
        ApplicationContext context = SpringApplication.run(SpringIoC3Application.class, args);
        //拿到Spring上下文对象
        UserController bean = context.getBean(UserController.class);
        //使用对象
        bean.sayHi();
    }
}

        代码运行结果:

        其他注入的方式,使用@Primary注解用法也一样,把想要拿到的对象加上@Primary注解就好了。

(3)解决方案三:加@Qualifier注解,指定引入的依赖对象

UserController类:

@Controller
public class UserController {
    @Qualifier("userInfo2")
    @Autowired
    private UserInfo userInfo;
        
    public void sayHi() {
        System.out.println(userInfo.toString());
        System.out.println("hello, controller");
    }
}

BeanConfig类:

@Component
public class BeanConfig {
    @Bean
    public UserInfo userInfo1() {
        UserInfo user = new UserInfo();
        user.setId(6);
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }

    @Bean
    public UserInfo userInfo2() {
        UserInfo user = new UserInfo();
        user.setId(7);
        user.setName("lisi");
        user.setAge(19);
        return user;
    }
}

启动类:

@SpringBootApplication
public class SpringIoC3Application
{
    public static void main(String[] args) {
        //拿到Spring上下文
        ApplicationContext context = SpringApplication.run(SpringIoC3Application.class, args);
        //拿到Spring上下文对象
        UserController bean = context.getBean(UserController.class);
        //使用对象
        bean.sayHi();
    }
}

        执行结果:

(4)解决方案四:加@Resource注解

这里和上面的三方案代码改变的只有UserController类,其他都不变,UserController类的代码如下:

@Controller
public class UserController {
    @Resource(name = "userInfo2")
    @Autowired
    private UserInfo userInfo;
        
    public void sayHi() {
        System.out.println(userInfo.toString());
        System.out.println("hello, controller");
    }
}

        运行结果如下:

        但是这个注解不是Spring的而是JDK本身自带的,JDK早期也有这样的注解所以Spring不推荐使用这个注解,因为不是自己开发的,如果出现啥问题,不好处理,是有着不可控因素的原因;还有使用自家的东西也肯定会更放心一些

4、@Autowired 与 @Resource 的区别(常见面试题)

1、@Autowired 是 Spring框架提供的注解,而@Resource是JDK提供的注解

2、@Autowired默认是按照类型注入,而@Resource是按照名称注入相比于 @Autowired 来说,@Resource 支持更多的参数设置;例如 name 设置,根据名称获取 Bean


六、Spring IoC&DI 的总结

1、Spring,Spring Boot 和 Spring MVC的关系以及区别

(1)Spring

        简单来说,Spring是一个开发应用框架那是什么样的框架呢?有这么几个标签:轻量级、一站式、模块化,其目的是用于简化企业级应用程序开发

Spring的主要功能管理对象,以及对象之间的依赖关系,面向切面编程、数据库事务管理、数据访问、web框架支撑等等

但是Spring具备高度可开发性,并不强制依赖Spring,开发者可以自由选择Spring的部分或者全部,Spring可以无缝继承第三方框架,比如数据访问框架(Hibernate、JPA等等),web框架(如:Struts、JSF等等)

(2)Spring MVC

        Spring MVC是Spring的一个子框架,Spring诞生之后,大家觉得很好用,于是按照MVC模式设计了一个MVC框架(一些用Spring解耦的组件),主要用于开发WEB应用和网络接口,所以Spring MVC是一个Web框架

Spring MVC基于Spring进行开发的,天生的与Spring框架集成。可以让我们更简洁的进行Web层开发,支持灵活的URL到页面控制器的映射,提供了强大的约定大于配置的契约式编程支持,非常容易与其他视图框架集成,如 Velocity、FreeMarker等等。

(3)Spring Boot

        Spring Boot 是对Spring的一个封装,为了简化Spring一样的开发而出现的,中小型企业,没有成本研究自己的框架,使用Spring Boot 可以更加快速的搭建框架,降低开发成本,让开发人员更加专注于Spring应用的开发,而无需过多关注XML的配置和一些底层的实现

Spring Boot是脚手架,插拔式搭建项目,可以快速的集成其他框架进来

比如想使用Spring Boot开发Web项目,只需要引入Spring MVC框架即可,Web开发的工作是Spring MVC完成的,而不是Spring Boot,想完成数据访问,只需要引入Mybatis框架即可

Spring Boot只是辅助简化项目开发的,让开发变得更加简单,甚至不需要额外的web服务器,直接生成jar包执行即可。

(4)总结

        Spring MVC和Spring Boot都属于SpringSpring MVC是基于Spring的一个MVC框架,而Spring Boot是基于Spring的一套快速开发整合包

例如之前写的图书管理系统代码中,整体框架是通过SpringBoot搭建的IoC,DI功能是Spring提供的,而Web相关功能是Spring MVC提供的。

        因为这三个专注的领域不同,所以解决的问题也不一样,总的来说,Spring就像一个大家族,有众多衍生产品,但它们的基础都是Spring,上面三者的关系如下图:

2、bean的命名

(1)五大注解存储的bean

1、类名前面两位字母均为大写,则bean名称为该类名本身(特殊情况)

2、不是上面的特殊情况,其他的类名,首字母小写,驼峰形式命名

3、通过 value 属性设置bean名 ,例如:@Controller (value = "user")

(2)@Bean注解存储的bean

1、bean名称为方法名

2、通过name属性设置bean名,例如:@Bean (name = {"u1", "user1"})

3、常见面试题

(1)三种注入方式的优缺点(参考上面)

(2)常见注解有哪些,分别是什么作用?

web url映射@RequestMapping

参数接收和接口响应@RequestParam、@RequestBody、@ResponseBody

bean的存储:@Controller、@Service、@Repository、@Component、@Configuration、@Bean

bean的获取@Autowired、@Qualifier、@Resource

(3)@Autowired 和 @Resource 的区别(参考上面)

(4)说下你对Spring、Spring MVC、Spring Boot的理解(参考上面)


都看到这了,点个赞再走吧,谢谢谢谢谢

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/598672.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JetBrains DataGrip v2024.1 激活版 (多引擎数据库管理开发)

JetBrains系列软件安装目录 一、JetBrains IntelliJ IDEA v2024.1 安装教程 (Java集成开发IDE) 二、JetBrains WebStorm v2024.1 激活版 (JavaScript集成开发IDE) 三、JetBrains PhpStorm v2024.1 安装教程 (PHP集成开发IDE) 四、JetBrains PyCharm Pro v2024.1 安装教程 (…

5W 1.5KVDC、3KVDC 宽电压输入 DC/DC 电源模块 ——TP05DA 系列

TP05DA系列电源模块额定输出功率为5W,外形尺寸为31.75*20.32*10.65,应用于2:1及4:1电压输入范围 9V-18V、18V-36V、36V-72V、9V-36V和18V-72VDC的输入电压环境,输出电压精度可达1%,具有输出短路保护等功能,可广泛应用于…

06-07 -变量的高级主题

---- 整理自狄泰软件唐佐林老师课程 文章目录 1. 变量值的替换2. 变量的模式替换3. 规则中的模式替换4. 变量值的嵌套使用5. 命令行变量6. 环境变量7. 目标变量(局部变量)8. 模式变量9. 工程 1. 变量值的替换 使用指定字符(串)替…

华人团队用大模型实现“读心术”:大脑活动直接变文字

NeurIPS收录的一项新研究,让大模型也学会“读心术”了! 通过学习脑电波数据,模型成功地把受试者的脑电图信号翻译成了文本。 而且整个过程不需要大型设备,只要一块特制的“头巾”就能实现。 这项成果名为DeWave,能在…

观测云 VS ELK:谁是日志监控的王者?

前言 作为 IT 信息系统运行状态感知和故障分析的重要手段,日志在行业兴起之初便为运维和开发环节所广泛应用。当应用和系统发生故障或出现问题时,日志数据成为了排查和诊断问题的重要依据。通过分析日志,开发人员和运维人员可以了解系统的运…

Redis是什么? 日常运维 Redis 需要注意什么 ? 怎么降低Redis 内存使用 节省内存?

你的项目或许已经使用 Redis 很长时间了,但在使用过程中,你可能还会或多或少地遇到以下问题: 我的 Redis 内存为什么增长这么快?为什么我的 Redis 操作延迟变大了?如何降低 Redis 故障发生的频率?日常运维…

LeetCode刷题记(五):121~150题

121. 买卖股票的最佳时机 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从…

59-ARM与FPGA间RGMII通信电路设计

视频链接 ARM与FPGA间RGMII通信电路设计01_哔哩哔哩_bilibili ARM与FPGA间RGMII通信电路设计 第2课:千兆以太网电路设计 第3课:万兆网电路设计 第49课:PCIE转网口电路设计 第50课:RGMII & SGMII & QGMII电路设计 1、…

在做题中学习(51): x的平方根

69. x 的平方根 - 力扣(LeetCode)​​​​​​ 解法:二分查找 思路:看示例2: 可以看到8的平方根是2.82,在2^2和3^2之间,所以可以把数组分为两部分,(具有二段性) 而2.82去掉小数部…

java线上问题排查之内存分析(三)

java线上问题排查之内存分析 使用top命令 top命令显示的结果列表中,会看到%MEM这一列,这里可以看到你的进程可能对内存的使用率特别高。以查看正在运行的进程和系统负载信息,包括cpu负载、内存使用、各个进程所占系统资源等。 2.用jstat命令…

CCE云原生混部场景下的测试案例

背景 企业的 IT 环境通常运行两大类进程,一类是在线服务,一类是离线作业。 在线任务:运行时间长,服务流量及资源利用率有潮汐特征,时延敏感,对服务SLA 要求高,如电商交易服务等。 离线任务&…

shell脚本脚本变量

shell脚本的概念: 1.讲要执行的命令按顺序保存到一个文本文件 2.给文件可执行权限 3.可以结合各种shell控制语句以完成更复杂的操作 linux中包含shell的文件有 [rootlocalhost ~]# cat /etc/shells /bin/sh #UNIX最初使用的 shell,已经被…

AI编码时代到来?实现编程梦想的利器—Baidu Comate测评

文章目录 Comate智能编码是什么?Comate支持的环境 Comate应用安装实际操作对话式生成代码生成代码注释智能单测项目测试调优功能 总结 Comate智能编码是什么? 在如今这个拥抱AI的时代,市面上已经产出了很多Ai代码助手,如果你还没…

Java clone

Java clone 原型模式用一个已经创建的实例作为原型,通过复制(clone)该原型对象来创建一个和原型对象相同的新对象。Java中对象克隆需要重写Object.clone()方法,并实现Cloneable接口。 浅克隆 浅克隆仅仅克隆本对象,…

关于Oracle 23ai 你要知道的几件事情

1.版本生命周期 23ai发布后的Oracle版本生命周期图,可以看到23ai是长期支持版本可以到2032年。 引申 Oracle版本分为两类 Innovation Release--创新版本,一般提供至少两年技术支持 Long Term Release --长期支持版本,一般提供5年premier和…

MacOS快速安装FFmpeg,并使用FFmpeg转换视频

前言:目前正在接入flv视频流,但是没有一个合适的flv视频流地址。网上提供的flv也都不是H264AAC(一种视频和音频编解码器组合),所以想通过fmpeg来将flv文件转换为H264AAC。 一、MacOS环境 博主的MacOS环境(…

DAPP开发:揭秘DAPP软件开发的秘密

随着区块链技术的飞速发展,DAPP(去中心化应用)的开发逐渐成为了一个热门话题。在本文中,我们将探讨如何从零开始开发DAPP软件,并深入思考DAPP开发中的关键问题。 一、了解DAPP开发的基础知识 在开始开发DAPP之前&…

大数据API技术分享:使用API接口采集淘宝数据(商品详情丨关键词搜索丨店铺所有商品)

使用API接口采集淘宝数据(商品详情、关键词搜索、店铺所有商品)是大数据领域常见的应用场景。以下是一些关于如何使用API接口进行这些操作的技术分享: 1. 获取API权限 首先,你需要在淘宝开放平台注册成为开发者,并创建…

【最大公约数 并集查找 调和级数】1998. 数组的最大公因数排序

本文涉及知识点 最大公约数 并集查找 调和级数 LeetCode1998. 数组的最大公因数排序 给你一个整数数组 nums ,你可以在 nums 上执行下述操作 任意次 : 如果 gcd(nums[i], nums[j]) > 1 ,交换 nums[i] 和 nums[j] 的位置。其中 gcd(nums…

免备案香港主机会影响网站收录?

免备案香港主机会影响网站收录?前几天遇到一个做电子商务的朋友说到这个使用免备案香港主机的完整会不会影响网站的收录问题,这个问题也是站长关注较多的问题之一。小编查阅了百度官方规则说明,应该属于比较全面的。下面小编给大家介绍一下使用免备案香…