001 IOC与DI(有点杂)
文章目录
- IOC与DI
- 区别
- 联系
- 总结
- 依赖注入
- 解耦
- 管理对象的生命周期
- 提高配置灵活性
- 三种注入方式
- 不可变对象的设计
- =====================
- 构造器注入
- Setter方法注入
- 字段注入
- Setter方法注入为什么不破坏封装性
- 字段注入为什么破坏封装性
- 为什么将字段或setter方法设置为`private`?
- 总结
- =====================
- setter方法注入和字段注入
- Setter方法注入
- 字段注入
- 在Setter方法注入和字段注入中,提供访问和修改对象内部状态的途径
- Setter方法注入
- 字段注入
- 将字段注入和Setter方法注入中的字段或方法设置为`private`
- 字段注入(即使字段为`private`)
- Setter方法注入(即使setter方法为`private`)
- 潜在问题
Spring框架中,构造函数主要用于创建和管理bean。Spring通过构造函数来实例化bean,并可以自动注入所需的依赖项。这通常与Spring的依赖注入功能结合使用,以简化对象的创建和配置过程
- 构造函数注入(Constructor Injection):
- 构造函数注入是通过bean的构造函数来传递依赖项。在Spring中,你可以通过在构造函数上添加
@Autowired
注解来自动注入所需的依赖项。 - 构造函数注入的一个主要优点是它可以确保依赖项在bean创建时就已准备好,从而避免了部分初始化的状态。
- 然而,构造函数注入的一个潜在缺点是,如果依赖项很多,构造函数可能会变得非常长且难以管理。
- 构造函数注入是通过bean的构造函数来传递依赖项。在Spring中,你可以通过在构造函数上添加
- Setter方法注入(Setter Injection):
- Setter方法注入是通过bean的setter方法来设置依赖项。Spring容器会在bean实例化后调用相应的setter方法来注入依赖项。
- Setter方法注入的一个优点是它允许依赖项在bean的生命周期中的任何时间点进行注入,这在某些情况下可能更为灵活。
- Setter方法注入的另一个优点是它允许bean具有可选的依赖项,因为这些依赖项可以通过调用相应的setter方法来设置,也可以不设置。
所以,setter方法确实可以用来创建和管理bean,特别是在需要更灵活的依赖注入时。但在使用setter方法注入时,需要确保setter方法是public的,并且遵循JavaBean的命名约定(即方法名以set
开头,后面跟着属性名,属性名的首字母大写)。
在Spring中,虽然不直接使用new来创建对象,但Spring容器会根据配置(XML、JavaConfig或注解)自动创建和管理bean的实例。这相当于在幕后使用了new,但添加了更多的管理和配置功能。
IOC与DI
在Spring框架中,依赖注入(Dependency Injection,简称DI)和控制反转(Inversion of Control,简称IoC)是密切相关的概念,它们通常一起使用来实现松耦合的应用程序架构。以下是它们之间的区别与联系:
区别
- 概念层次:
- 控制反转(IoC):是一个更广泛的概念,它描述了一种设计原则,即应用程序中组件之间的依赖关系的管理权从组件内部转移到外部容器或框架。这种转移使得组件之间的耦合度降低,提高了系统的可维护性和可扩展性。
- 依赖注入(DI):是IoC原则的一种具体实现方式。它通过外部容器或框架将依赖项注入到组件中,而不是由组件自己创建或查找依赖项。这确保了组件只关注自己的核心功能,而不必关心依赖项的创建和管理。
- 关注点:
- IoC:关注的是控制权的转移,即谁负责创建和管理组件之间的依赖关系。
- DI:关注的是如何实现这种控制权的转移,即如何将依赖项注入到组件中。
联系
- 相互依赖:依赖注入是实现控制反转的一种手段。通过依赖注入,外部容器或框架可以管理组件之间的依赖关系,从而实现控制反转。
- 共同目标:IoC和DI都旨在降低组件之间的耦合度,提高系统的可维护性和可扩展性。它们通过外部化依赖项的管理和注入来实现这一目标。
- 在Spring中的应用:在Spring框架中,IoC容器负责创建和管理bean之间的依赖关系。这些bean可以通过构造器注入、Setter方法注入或字段注入等方式接收依赖项。因此,在Spring中,依赖注入是实现控制反转的一种核心机制。
总结
控制反转(IoC)和依赖注入(DI)是密切相关的概念,在Spring框架中共同发挥着重要作用。IoC描述了组件之间依赖关系管理权的转移,而DI是实现这种转移的一种具体方式。通过依赖注入,外部容器或框架可以管理组件之间的依赖关系,从而降低组件之间的耦合度,提高系统的可维护性和可扩展性。在Spring中,IoC容器通过依赖注入机制来创建和管理bean之间的依赖关系。
依赖注入
依赖注入是一种设计模式,用于实现控制反转。在Spring中,这主要通过以下方式实现:
解耦
通过依赖注入,对象的依赖关系由外部容器(如Spring容器)管理。这减少了对象之间的直接依赖,提高了代码的可维护性和可测试性
管理对象的生命周期
Spring容器不仅负责创建对象,还管理它们的生命周期,包括初始化、消耗等。
提高配置灵活性
依赖关系可以通过配置文件、注解或其他方式进行定义,这使得配置更加灵活。可以在不修改源代码的情况下,通过修改配置来改变对象之间的依赖关系
在Spring中,依赖注入通常与构造函数、setter方法或字段注入结合使用。例如,当Spring创建一个bean时,它可以通过调用该bean的构造函数并传递必要的依赖项来实现依赖注入
三种注入方式
在Spring框架中,依赖注入(Dependency Injection,简称DI)是一个核心概念。它允许你将对象的依赖关系(即它们需要的服务或组件)从外部注入,而不是在对象内部创建这些依赖。这有助于降低代码之间的耦合度,提高可测试性和可维护性。
Spring支持三种主要的依赖注入方式:构造函数注入、setter方法注入和字段注入。
- 构造函数注入:通过构造函数来传递依赖关系。当创建对象时,依赖项会作为构造函数的参数被传递进来。这种方式可以确保所有的依赖项在对象创建时就已经被初始化,从而保证对象的状态在创建后就是有效的。构造函数注入也支持不可变对象的设计,因为所有的依赖项在构造函数中就已经被赋值,之后无法再被修改。
@Component
public class MyClass { private final MyDependency myDependency; @Autowired public MyClass(MyDependency myDependency) { this.myDependency = myDependency; }
}
- setter方法注入:通过setter方法来传递依赖关系。在对象创建后,可以通过调用setter方法来设置依赖项。这种方式提供了更大的灵活性,因为可以在运行时动态地更改依赖项。然而,它也可能导致对象在部分初始化的状态下被使用,从而引发潜在的问题。
@Component
public class MyClass { private MyDependency myDependency; @Autowired public void setMyDependency(MyDependency myDependency) { this.myDependency = myDependency; }
}
- 字段注入:直接在字段上使用注解来注入依赖关系。这种方式简单且直观,但通常不建议在生产代码中使用,因为它违反了封装原则,使得字段直接暴露给外部。此外,它也不利于单元测试和代码的可维护性。
@Component
public class MyClass { @Autowired private MyDependency myDependency;
}
在实际开发中,推荐使用构造函数注入,因为它保证了依赖的不可变性,有助于编写更健壮和可测试的代码。然而,在某些特定场景下,setter方法注入可能更为合适,尤其是当需要在运行时动态更改依赖项时。字段注入虽然简单方便,但通常应谨慎使用,以避免潜在的问题。
不可变对象的设计
在构造函数注入中,依赖项是在对象创建时通过构造函数参数传递进来的。这些依赖项通常被赋值给类的私有成员变量。如果这些成员变量被声明为final
,那么它们就只能在构造函数中被赋值一次,之后就不能再被修改。
即使成员变量没有被声明为final
,如果类的设计遵循了不可变对象的原则,那么这些成员变量在构造函数中被初始化后,类中不会提供任何修改这些成员变量的方法(如setter方法)。这样,从类的外部就无法更改这些依赖项。
不可变对象的设计有几个优点:
- 线程安全:由于对象的状态在创建后就不能再改变,因此它是线程安全的,不需要额外的同步措施。
- 简化逻辑:不可变对象没有状态变化,因此更容易理解和推理其行为。
- 减少错误:由于状态不可变,因此不会出现因状态改变而导致的错误或不一致。
在Spring框架中,通过构造函数注入依赖并实现不可变对象的设计是一种常见的做法,因为它结合了依赖注入的优点和不可变对象的健壮性。这种做法确保了当Spring容器创建bean时,所有的依赖项都已经被正确地注入,并且之后不会再发生变化,从而提高了应用的稳定性和可预测性。
下面是一个简单的例子,展示了如何使用构造函数注入来创建一个不可变的对象:
@Component
public class MyService { private final MyDependency myDependency; // final关键字确保这个变量只能被赋值一次 @Autowired public MyService(MyDependency myDependency) { this.myDependency = myDependency; // 在构造函数中初始化依赖项 } // 类中不提供修改myDependency的方法,确保其不可变性 public void performAction() { // 使用myDependency来完成某些操作 }
}
在这个例子中,MyService
类的myDependency
成员变量被声明为final
,并且在构造函数中被初始化。由于没有提供修改这个变量的方法,因此它是不可变的。
=====================
在Spring框架中,依赖注入(Dependency Injection, DI)是一个核心概念,它允许我们将对象的依赖关系从外部注入,而不是在对象内部创建这些依赖。Spring提供了多种方式来实现依赖注入,其中最常见的是构造器注入和Setter方法注入。尽管字段注入也被Spring支持,但通常不推荐使用,因为它违反了封装性原则。
构造器注入
构造器注入是Spring推荐的方式之一,因为它强制在创建对象时提供所有必需的依赖项,从而确保对象在创建时就已经完全初始化。这种方式有助于减少对象处于部分初始化状态的风险,并提高了代码的健壮性。
在Spring中,你可以通过在类的构造器上添加参数来使用构造器注入。Spring容器在创建bean实例时,会自动调用带有适当参数的构造器,并将依赖项注入到这些参数中。
Setter方法注入
Setter方法注入允许在对象创建后通过调用setter方法来设置依赖项。这种方式提供了更大的灵活性,因为你可以在对象创建后的任何时间点注入依赖项。然而,它也可能导致对象在部分初始化的状态下被使用,从而引发潜在的问题。
在Spring中,你可以通过在setter方法上使用@Autowired
注解来使用Setter方法注入。Spring容器会在bean实例化后自动调用这些带有@Autowired
注解的setter方法,并将匹配的依赖项注入到对象中。
字段注入
尽管字段注入在Spring中是可能的(通过在字段上使用@Autowired
注解),但它通常不被推荐,因为它直接暴露了类的内部状态,破坏了封装性。使用字段注入的代码更难于测试和维护,因为它使得类的内部实现细节对外部可见。
Setter方法注入为什么不破坏封装性
Setter方法注入不破坏封装性的原因是因为它允许对象在创建之后通过公开的方法来设置其内部状态,同时保持了对这些状态的完全控制。对象通过setter方法可以执行任何必要的验证、初始化或其他逻辑,以确保状态的完整性和一致性。
例子:
假设有一个UserService
类,它依赖于一个UserRepository
来访问数据库。
@Service
public class UserService { private UserRepository userRepository; @Autowired public void setUserRepository(UserRepository userRepository) { // 这里可以添加一些初始化逻辑或验证 if (userRepository == null) { throw new IllegalArgumentException("UserRepository cannot be null"); } this.userRepository = userRepository; } // ... 其他方法 ...
}
在这个例子中,UserService
通过公开的setter方法setUserRepository
来接收UserRepository
的依赖注入。由于setter方法是公开的,外部代码(在这里是Spring容器)可以调用它,但UserService
仍然控制着userRepository
字段的访问和赋值,这符合封装性的原则。
字段注入为什么破坏封装性
字段注入破坏封装性的原因是因为它直接暴露了类的内部状态给外部代码。当字段被标记为public或通过字段注入的方式被外部直接访问和修改时,类的内部实现细节就被泄露了,这违反了封装性的原则。
例子:
@Service
public class UserService { @Autowired public UserRepository userRepository; // 直接字段注入 // ... 其他方法 ...
}
在这个例子中,userRepository
字段被直接标记为Spring管理的bean,这意味着Spring容器可以直接访问和修改这个字段。这不仅使得UserService
的内部状态对外部可见,而且还可能导致不可预测的行为,因为任何能够访问UserService
实例的代码都可以修改userRepository
字段。此外,这也使得测试和维护变得更加困难,因为你需要确保在所有情况下userRepository
字段都被正确地设置。
总结来说,Setter方法注入通过提供公开的方法来设置内部状态,同时保持了对这些状态的控制,因此不破坏封装性。而字段注入则直接暴露了类的内部状态给外部代码,从而破坏了封装性。在设计和编写代码时,应该优先考虑使用Setter方法注入来维护良好的封装性。
为什么将字段或setter方法设置为private
?
将字段或setter方法设置为private
可以提高封装性,这是面向对象编程的一个基本原则。封装性意味着隐藏对象的内部实现细节,只对外暴露必要的接口。通过将字段和setter方法设置为private
,你可以确保只有类的内部代码能够直接访问和修改这些字段,从而减少了外部代码对类内部状态的干扰和破坏。
然而,在Spring中,即使你将字段或setter方法设置为private
,Spring容器仍然能够注入依赖项,因为它使用了反射机制来访问和修改这些私有成员。但重要的是要明白,这并不是说你应该在Spring中使用反射来绕过封装性。相反,你应该利用Spring提供的依赖注入机制来正确地管理你的对象的依赖项。
总结
在Spring中,你应该优先使用构造器注入或Setter方法注入来管理对象的依赖项。这两种方式都提供了良好的封装性和灵活性,并且与Spring的依赖注入机制兼容。避免使用字段注入,因为它违反了封装性原则,并可能导致难以维护的代码。通过将字段和setter方法设置为private
,你可以进一步提高封装性,并确保你的代码更加健壮和可维护。
=====================
setter方法注入和字段注入
Setter方法注入和字段注入之所以能够修改对象状态,是因为它们提供了访问和修改对象内部状态的途径。具体来说,这两种注入方式允许外部代码更改对象的依赖项或字段值,从而影响对象的内部状态和行为。
Setter方法注入
Setter方法注入允许在对象创建后,通过调用对象的setter方法来动态地设置或更改依赖项。这种方式的问题主要在于:
- 部分初始化状态:
- 如果setter方法没有在对象创建后立即调用,或者在多线程环境中调用时序不正确,对象可能会在依赖项未完全设置的情况下被使用。这导致对象处于部分初始化的状态,可能引发
NullPointerException
、逻辑错误或其他运行时异常。
- 如果setter方法没有在对象创建后立即调用,或者在多线程环境中调用时序不正确,对象可能会在依赖项未完全设置的情况下被使用。这导致对象处于部分初始化的状态,可能引发
- 状态的不确定性:
- 由于依赖项可以在对象生命周期的任何时刻被更改,这增加了对象状态的不确定性。如果外部代码在不恰当的时机更改了依赖项,可能会导致对象行为的不一致和难以预测。
- 依赖管理复杂性:
- 允许动态更改依赖项意味着需要更复杂的依赖管理和状态同步机制,以确保在任何时候对象的依赖项都是有效和一致的。
字段注入
字段注入是通过在字段上直接使用注解来注入依赖关系。这种方式的问题包括:
- 封装性破坏:
- 字段注入直接暴露了类的内部字段,违反了面向对象编程的封装原则。任何能够访问这些字段的外部代码都可以修改它们,这可能导致对象状态的意外更改和不可预测的行为。
- 安全性风险:
- 暴露的字段可能引发安全性问题,因为恶意代码可能会利用这些暴露的字段来篡改对象状态或窃取数据。
- 可维护性下降:
- 当字段名称、类型或逻辑更改时,所有直接引用这些字段的代码也需要相应更新,这增加了代码的维护成本。
- 测试困难:
- 由于字段是公开的,编写单元测试时需要额外注意控制这些字段的状态,以确保测试的准确性和隔离性。这可能会使测试变得更加复杂和脆弱。
综上所述,Setter方法注入和字段注入都能修改对象状态,但它们各自带来的问题不同。Setter方法注入主要问题在于可能导致对象的部分初始化和状态的不确定性,而字段注入则主要破坏了封装性,增加了安全风险,并降低了代码的可维护性和可测试性。因此,在实际开发中需要谨慎使用这两种注入方式,并根据具体情况权衡利弊。
在Setter方法注入和字段注入中,提供访问和修改对象内部状态的途径
在Setter方法注入和字段注入中,提供访问和修改对象内部状态的途径分别是:
Setter方法注入
提供访问的途径:
- 通过公开的setter方法。这些方法通常被设计为public,允许外部代码调用以设置或更改对象的内部状态。
提供修改的途径:
- 同样是通过调用上述的setter方法,并传递新的依赖项或值作为参数,从而实现对对象内部状态的修改。
例如,如果有一个setService(Service service)
的setter方法,外部代码可以通过调用这个方法并传入一个新的Service
实例来更改对象所依赖的服务。
字段注入
提供访问的途径:
- 通过直接访问对象的公共字段或使用反射技术访问私有字段(尽管这通常不是推荐的做法)。如果字段是public的,那么任何能够访问到该对象的代码都可以直接读取字段的值。
提供修改的途径:
- 直接对公共字段赋值。如果字段是public的,外部代码可以直接修改字段的值,从而改变对象的内部状态。
- 使用反射来修改私有字段的值(尽管这种做法应该避免,因为它破坏了封装性并可能导致不可预知的副作用)。
例如,如果有一个public字段Service service
,外部代码可以直接通过object.service = newServiceInstance;
来更改服务依赖。
需要注意的是,尽管字段注入提供了直接访问和修改对象内部状态的途径,但这通常被认为是不良实践,因为它破坏了封装性,使得代码更加脆弱且难以维护。Setter方法注入虽然也提供了修改对象状态的途径,但相对于字段注入,它更好地维护了封装性,并允许在设置依赖项之前进行一些验证或初始化逻辑。
将字段注入和Setter方法注入中的字段或方法设置为private
将字段注入和Setter方法注入中的字段或方法设置为private
确实可以提高封装性,但这样做并不能完全解决问题,而且每种方式仍有其特有的考虑和问题。
字段注入(即使字段为private
)
即使你将注入的字段设置为private
,你仍然需要某种方式来设置这个字段的值,通常是通过构造函数、一个公开的setter方法或使用反射。如果你选择使用公开的setter方法,那么问题就与Setter方法注入相似了。如果你选择使用反射来设置私有字段,那么你将牺牲一部分性能和代码清晰度,并且反射操作通常比直接方法调用要慢。
此外,即使字段是私有的,如果你通过反射或其他非标准方式来设置它,你仍然可能破坏封装性,并引入难以追踪的bug和安全问题。
Setter方法注入(即使setter方法为private
)
将setter方法设置为private
将阻止外部代码直接调用它,但这通常不是依赖注入所期望的行为。依赖注入的目的是允许在运行时动态地更改依赖项,以提高代码的灵活性和可测试性。如果setter方法是私有的,那么你就需要在类内部提供另一种机制来允许依赖项的设置,这可能会使设计变得复杂。
在实际应用中,private
setter方法通常用于以下几种情况:
- 仅供类内部使用:有时你可能希望在类内部的不同方法之间共享某个状态,但不希望这个状态被外部类更改。在这种情况下,一个
private
setter方法是有意义的。 - 配合特定的设计模式使用,例如建造者模式(Builder Pattern),其中
private
setter方法用于在构建对象的过程中设置属性。 - 用于单元测试:在某些情况下,你可能希望为单元测试提供一个后门来设置或更改对象的内部状态。虽然这样做可以方便测试,但它也破坏了封装性,并可能导致测试与实现之间的紧密耦合。
潜在问题
- 封装性的破坏:即使字段或方法是
private
的,使用反射或内部机制来更改状态仍然可能破坏封装性。 - 代码清晰度:使用非标准方式来设置私有字段或调用私有方法可能会使代码难以理解和维护。
- 安全性和错误预防:私有字段和方法通常是为了防止外部错误操作而设计的。绕过这些限制可能会引入安全隐患和难以追踪的错误。
- 测试复杂性:虽然为测试提供后门可以方便测试,但这也可能导致测试与实现的紧密耦合,使得当实现更改时测试也需要相应更改。
- 性能开销:使用反射来访问或修改私有成员通常比直接访问或调用方法要慢得多。
综上所述,将字段或setter方法设置为private
可以提高封装性,但并不能完全解决所有问题。在设计时应该权衡各种因素,包括封装性、灵活性、可测试性和性能等。
相关文章:

001 IOC与DI(有点杂)
文章目录 IOC与DI区别联系总结 依赖注入解耦管理对象的生命周期提高配置灵活性三种注入方式不可变对象的设计 构造器注入Setter方法注入字段注入Setter方法注入为什么不破坏封装性字段注入为什么破坏封装性为什么将字段或setter方法设置为private?总结 setter方法注…...

Python语言自学:深入探索四个基础、五个进阶、六个实战及七个挑战
Python语言自学:深入探索四个基础、五个进阶、六个实战及七个挑战 Python,作为一种通用编程语言,其简洁的语法、丰富的库和强大的功能,使得越来越多的人选择自学Python。但自学之路并非坦途,本文将从四个方面、五个方…...

运维开发介绍
目录 1.什么是运维开发 2.作用 3.优点 4.缺点 5.应用场景 5.1.十个应用场景 5.2.网站和Web应用程序 6.案例 7.小结 1.什么是运维开发 运维开发(DevOps)是一种结合软件开发(Development)与信息技术运维(Opera…...

Mac版的Typora的安装和激活(亲测可用哦~~~)
星光下的赶路人star的个人主页 珍视生活中的苦与乐,悦纳生活的悲伤离合 文章目录 1.下载2.安装3.激活4.注意点 1.下载 直接官网下载即可!!! 官网地址:typora官网 2.安装 直接拖进去安装即可 3.激活 1.利用访达进入…...

【Python系列】Python 方法变量参数详解
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

生命在于学习——Python人工智能原理(3.2)
三、深度学习 (二)人工神经网络 人工神经网络是模仿人类大脑神经系统工作原理所创建的数学模型,有并行的分布处理能力、高容错性和自我学习等特征。 1、感知器 感知器由Frank Roseblatt于1957年提出,是一种广泛使用的线性分类…...

JAVA面试八股文----Mybatis
1、Mybatis 1.1#{}和${}的区别是什么? Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值; Mybatis在处理 0 时,就是把 0时,就是把 0时,就是把{}替换成变量的值。 有了#{}为什么还需要${}? #{}会被预编译处理,可以有效的防止SQL注…...

[论文笔记]MemGPT: Towards LLMs as Operating Systems
引言 今天介绍一篇论文MemGPT: Towards LLMs as Operating Systems。翻过过来就是把LLM看成操作系统。 大语言模型已经在人工智能领域引起了革命性的变革,但受到有限上下文窗口的限制,在扩展对话和文档分析等任务中的效用受到了阻碍。为了能够利用超出…...

Sentinel1.8.6更改配置同步到nacos(项目是Gateway)
本次修改的源码在:https://gitee.com/stonic-open-source/sentinel-parent 一 下载源码 地址:https://github.com/alibaba/Sentinel/releases/tag/1.8.6 二 导入idea,等待maven下载好各种依赖 三 打开sentile-dashboard这个模块…...

材料科学领域科技查新点提炼方法!---附案例
材料科学是研究材料的组织结构、性质、生产流程、使用效能及它们之间的相互关系的科学,集物理学、化学、冶金学等于一体。随着科技的发展,纳米技术和生物技术也广泛应用到该领域中。从材质上可以分为金属材料、无机非金属材料、有机高分子材料和复合材料…...

深入理解HTTP与TCP:应用层与传输层的区分
一、前言 在互联网协议栈中,应用层和传输层是两个重要的层级,分别承载了不同的功能。HTTP(HyperText Transfer Protocol)作为应用层协议,而TCP(Transmission Control Protocol)则是传输层协议&…...

Unity3D Delaunay德罗内三角算法详解
Unity3D是一款强大的游戏开发引擎,它提供了丰富的功能和工具,使开发者能够轻松创建出色的游戏和应用程序。其中,Delaunay德罗内三角算法是一种常用的计算几何算法,用于生成三角形网格,其在Unity3D中的应用也非常广泛。…...

JAVA小案例-输出100-150中能被3整除的数,每5个换行
JAVA小案例-输出100-150中能被3整除的数,每5个换行 代码如下: public class Continue {/*** continue练习,输出100-150中能被3整除的数,每5个换行* param args*/public static void main(String[] args) {int count 0;//计数器…...

论程序员的职业素养
文章目录 前言一、命名规范1. HTML命名规范2. CSS命名规范3. JavaScript命名规范4. 文件和文件夹命名规范5. 代码案例 二、代码注释规范1. 注释规范2. 案例代码HTMLCSS (styles/main.css)JavaScript (scripts/main.js) 三、代码逻辑规范1.逻辑规范2. 代码案例清晰的函数和模块化…...

前端canvas绘图,利用canvas在图片上面绘制标记以及给canvas添加点击事件。
前端canvas绘图,利用canvas在图片上面绘制标记以及给canvas添加点击事件。 需要实现的效果如下图: 首先需要一个承载的核心画布 <canvas id"canvas" width"800" height"600"></canvas>全部代码: <!DOCT…...

38、Flink 的 WindowAssigner 之 GlobalWindows 示例
1、注意 使用 GlobalWindows 需要自定义 Trigger,否则窗口中的数据不会被计算。 2、代码示例 import org.apache.flink.streaming.api.datastream.DataStreamSource; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org…...

同事仅靠着自己写的npm包跳槽去了大厂,羡慕了一整天
同事们之间总会悄悄聊一些话题,比如聊一些八卦啦,聊一些领导啦,也会偶尔说想跳槽,但这年头,跳槽多费劲啊,谁没事敢动。还别说,边上做了个同事,前两天还真要撤了,聊了半天…...

Yocto - bitbake任务中clean和cleanall的区别
在 BitBake 中,clean 和 cleanall 命令都用于删除构建工件,但它们的范围和执行的清理程度不同。 1. clean 命令: 目的:clean命令用于删除与特定任务或配方相关的临时构建文件和工件。 范围:它只清除指定任务或配方生…...

Spring 中如何控制 Bean 的加载顺序?
如果你脱口而出说添加 Order 注解或者是实现 Ordered 接口,那么恭喜,你掉坑了。 一 Order 注解和 Ordered 接口 在 Spring 框架中,Order 是一个非常实用的元注解,它位于 spring-core 包下,主要用于控制某些特定上下文…...

【学习笔记】Windows GDI绘图(十)Graphics详解(中)
文章目录 Graphics的方法AddMetafileComment添加注释BeginContainer和EndContainer新建、还原图形容器不指定指定源与目标矩形指定源与目标矩形 Clear清空并填充指定颜色CopyFromScreen截图CopyPixelOperation DrawImage绘制图像DrawImage的GraphicsDrawImageAbort回调ExcludeC…...

web学习笔记(六十二)
目录 1.键盘事件 2.KeepAlive 3.组件传值 3.1 兄弟组件传值 3.2 组件树传值 3.3 发布订阅者传值 1.键盘事件 keydown表示键盘事件,在不加修饰符的情况下,点击键盘上的任意位置都可以触发键盘事件, <template><div><!--…...

每天CTF小练一点--ctfshow年CTF
初一 题目: 2023是兔年,密码也是。聪明的小伙伴们,你能破解出下面的密码吗? 感谢大菜鸡师傅出题 flag格式是ctfshow{xxxxxx}.或许密码也有密码。 密文是: U2FsdGVkX1M7duRffUvQgJlESPfOTV2i4TJpc9YybgZ9ONmPk/RJje …...

Java Set接口 - TreeSet类
TreeSet 是 Java 集合框架中的一个类,它实现了 NavigableSet 接口,而 NavigableSet 是 SortedSet 接口的一个子接口。TreeSet 基于红黑树(一种自平衡的二叉搜索树)实现,因此它可以保证集合中的元素以升序排列。 以下是…...

css 理解了原理,绘制三角形就简单了
1.border-位置 注意:border-bottom/up/right/left 主要是以三角形的结构搭建而成,而border也是如此。而且从边框的外围开始计算像素尺寸。在理解了这一点之后,绘制三角形就简单多了。 1.transparent 注意:该属性主要是颜色透明…...

【JavaEE进阶】——MyBatis操作数据库 (#{}与${} 以及 动态SQL)
目录 🚩#{}和${} 🎈#{} 和 ${}区别 🎈${}使用场景 📝排序功能 📝like 查询 🚩数据库连接池 🎈数据库连接池使⽤ 🚩MySQL开发企业规范 🚩动态sql 🎈…...

电阻应变片的结构
电阻应变片的结构 常用的电阻应变片有金属应变片和半导体应变片两种。金属应变片分为体型和薄膜型。半导体应变片常见的有体型、薄膜型、扩散型、外延型、PN结及其他形式。图2—2所示为工程常见的应变片实物。 电阻应变片的典型结构如图2—3所示。它由敏感栅、基底、覆盖层和引…...

云原生时代:从 Jenkins 到 Argo Workflows,构建高效 CI Pipeline
作者:蔡靖 Argo Workflows Argo Workflows [ 1] 是用于在 Kubernetes 上编排 Job 的开源的云原生工作流引擎。可以轻松自动化和管理 Kubernetes 上的复杂工作流程。适用于各种场景,包括定时任务、机器学习、ETL 和数据分析、模型训练、数据流 pipline、…...

【数据库系统概论】事务
概述 在数据库系统中,事务(Transaction)是指一组作为单个逻辑工作单元执行的操作。这些操作要么全部成功(提交),要么全部失败(回滚)。事务的主要目的是确保数据库的完整性和一致性&…...

C++-排序算法详解
目录 一. 冒泡排序: 二. 插入排序: 三. 快速排序: 四. 选择排序 五, 归并排序 六, 堆排序. 排序算法是一种将一组数据按照特定顺序(如升序或降序)进行排列的算法。 其主要目的是对一组无序的数据进行整理&#…...

Kotlin 引用(双冒号::)
文章目录 双冒号::引用函数普通函数成员函数类构造函数 引用变量(很少用)普通变量成员变量 双冒号:: Kotlin 中可以使用双冒号::对某一变量、函数进行引用。 Note:MyClass::class可用于获取KClass<MyClass>,此时的双冒号::…...