Java:性能优化细节01-10
Java:性能优化细节01-10
在Java程序开发过程中,性能优化是一个重要的考虑因素。常见的误解是将性能问题归咎于Java语言本身,然而实际上,性能瓶颈更多地源于程序设计和代码实现方式的不当。因此,培养良好的编码习惯不仅对提升程序性能至关重要,同时也有助于增强代码的可读性和可维护性。
1、尽量在合适的场合使用单例
使用单例模式是一种有效的设计策略,用于在整个应用程序中管理资源的使用、实例的创建以及数据的共享。这种模式通过确保一个类只有一个实例,并提供一个全局访问点来访问该实例,可以在多种情况下提高效率和性能。不过,单例模式的应用需要根据具体场景谨慎考虑,因为不恰当的使用可能会带来一些问题,如过度使用可能会导致代码的耦合度增高,测试难度加大等。下面是单例模式主要适用场景的扩展和优化说明:
-
控制资源的使用:在许多应用场景中,某些资源如数据库连接、线程池等是稀缺资源,过度创建和销毁不仅消耗大量系统资源,还可能导致性能瓶颈。单例模式通过确保这类资源在应用程序中仅有一个实例,可以有效地控制资源的使用,通过线程同步机制控制对这些资源的并发访问,从而确保资源使用的高效性和安全性。
-
控制实例的产生:单例模式限制了类的实例化次数,帮助节约系统资源。在一些场景下,如配置管理器、连接池等,确保全局只有一个实例不仅可以节省资源,还可以避免潜在的冲突和错误。此外,单例也有助于实现延迟初始化,即实例在首次使用时才被创建,进一步优化资源的使用和程序启动时间。
-
控制数据共享:在分布式系统或多线程环境中,需要在不同的进程或线程间共享数据时,单例模式提供了一个简洁有效的解决方案。通过共享的单例实例,可以方便地在各个组件之间共享和访问状态信息或配置数据,而无需建立复杂的通信机制或直接依赖。这种方式简化了数据共享的逻辑,降低了系统的复杂度。
然而,单例模式并非万能钥匙,其使用场景应当根据具体需求仔细考量。例如,在需要考虑扩展性和灵活性时,单例可能会限制系统设计的灵活度。此外,单例模式在多线程环境下可能会遇到同步问题,需要通过额外的同步机制来确保线程安全,这可能会影响到系统的性能。因此,设计时应权衡单例模式的优点与潜在的限制,确保其最终能够为系统带来预期的收益。
2、尽量避免随意使用静态变量
在Java编程中,静态变量因其全局访问性和持久存储特性而被广泛使用。静态变量存储在JVM的方法区中,与类的加载和卸载周期相同。正因为此,静态变量提供了在应用程序的整个生命周期中共享数据的便利方式。然而,不恰当的使用静态变量可能会导致内存泄漏和资源管理问题,尤其是在大型应用程序中,这些问题可能会导致严重的性能下降。
当某个对象被定义为static变量所引用,那么GC通常是不会回收这个对象所占有的内存,如
public class A{
private static B b = new B();
}
静态变量使用注意事项
-
内存管理:正如例子中所示,静态变量
b的生命周期与类A相绑定。如果A类始终不被卸载,那么b也将常驻内存,即使它在实际应用中已不再需要。这种情况在使用第三方库、框架或长时间运行的应用中尤为常见。 -
设计选择:在设计软件时,应优先考虑实例变量而非静态变量,除非有明确的理由需要将数据或状态与类本身而非其实例关联。使用实例变量可以帮助更好地管理资源,因为它们的生命周期与对象实例相关联,可以通过垃圾收集器有效回收。
-
内存泄漏风险:静态变量如果引用了大型数据结构或其他资源密集型对象,而且在应用程序的生命周期内不再需要这些对象,就可能导致内存泄漏。即使是小型对象,随着时间的推移,也可能累积成为显著的内存占用。
解决策略
-
使用弱引用:对于必须使用静态变量但又想避免内存泄漏的情况,可以考虑使用
WeakReference或SoftReference。这样,当JVM需要回收内存时,即使这些变量还有引用,也可以被垃圾回收器回收。 -
及时清理:在不再需要持有静态变量时,应显式将其设置为
null,这可以帮助垃圾收集器回收那些不再需要的对象,减少内存占用。 -
审慎设计:在使用静态变量之前,应仔细考虑是否有其他更适合的设计方案。例如,可以使用依赖注入等设计模式来管理对象的生命周期,而不是依赖静态变量。
3. 尽量避免过多过地创建Java对象
在Java中,对象的创建和垃圾回收(GC)是两个影响性能的关键因素。虽然现代JVM的垃圾回收机制非常高效,但频繁创建和销毁大量对象仍然会对性能产生负面影响,尤其是在需要高效执行的代码块,如频繁调用的方法和循环体内。遵循“尽量避免过多过常地创建Java对象”的原则有助于优化性能,减少GC的压力,以下是一些具体策略:
对象重用
- 对象池:对于创建成本高昂的对象,如数据库连接、线程等,可以采用对象池技术。对象池允许复用一组已经初始化的对象,避免了频繁创建和销毁对象的开销。
- 缓存实例:对于经常被重复使用的对象,可以考虑将这些对象缓存起来以供重用,特别是当对象的状态不变或可预测时。
使用基本数据类型和数组
- 基本类型代替包装类:在可能的情况下,使用基本数据类型(如
int,double,boolean等)而不是它们的包装类(如Integer,Double,Boolean等),因为基本类型存储在栈上,更加高效。 - 数组和集合:在处理大量数据时,合理选择数据结构也很重要。数组相比于对象集合(如
ArrayList或LinkedList),在存储和访问效率上通常更优。但是,如果需要频繁的插入、删除操作,选择正确的集合类型(如ArrayList、LinkedList)可能更合适。
延迟初始化
- 按需创建:对于一些不一定会被用到的对象,可以采用延迟初始化的策略,即只有在真正需要时才创建这些对象。这种策略不仅可以节省资源,还可以加快程序的启动速度。
循环内部优化
- 减少循环内对象创建:在循环结构中,应尽量避免在每次迭代时创建新的对象。如果需要,可以在循环外创建对象,并在循环内部重用。
函数式编程
- 利用流和Lambda表达式:Java 8 引入的流(Stream)API和Lambda表达式可以在某些情况下减少对象的创建。通过流的链式调用,可以在内部优化迭代和数据处理,尽量减少不必要的对象创建。
4. 尽量使用final修饰符
使用final修饰符在Java编程中是一个提升性能的技巧,尤其在关键路径(hot paths)或性能敏感的应用中。final可以用于变量、方法、和类,具有不同的效果:
-
对变量:
final变量一旦被初始化后其值就不能被改变。对于基本类型,这意味着数值常量不变;对于引用类型,这意味着引用不变,但被引用的对象的状态是可以改变的。 -
对方法:将方法声明为
final意味着该方法不能在子类中被重写。这对于编译器优化很有帮助,因为这样编译器就知道这个方法的实现是不会改变的,可以安全地应用内联优化。方法内联是一种常用的优化手段,可以减少方法调用的开销,因为它避免了调用过程中的一些额外操作(如跳转指令),直接在调用处展开方法体。 -
对类:用
final修饰类表示这个类不能被继承。这样做的一个好处是安全性,如String类就是一个很好的例子,通过防止继承来避免破坏其不可变性。从性能角度看,这同样允许编译器对该类的所有方法应用内联优化,因为这些方法不会被子类重写。
通过将简单的getter和setter方法声明为final,你可以向编译器明确表示这些方法不会被进一步修改或重写。这种明确性允许编译器进行方法内联优化,例如,将方法调用直接替换为字段访问。这种优化减少了方法调用的开销,尤其是在这些方法非常频繁被调用的情况下,可以显著提升性能。
然而,使用final修饰符也应该是有选择的。过度使用final可能会限制代码的灵活性和可扩展性。例如,将类声明为final可能会阻碍继承和多态的使用,这在需要扩展或修改现有类的行为时会是一个限制。因此,决定何时使用final修饰符应该基于对性能、安全性、以及代码维护灵活性需求的综合考虑。
如:让访问实例内变量的getter/setter方法变成”final,简单的getter/setter方法应该被置成final,这会告诉编译器,这个方法不会被重载,所以,可以变成”inlined”内联,例子:
class MAF {
public void setSize (int size) {
_size = size;
}
private int _size;
}
// 更正
class DAF_fixed {
final public void setSize (int size) {
_size = size;
}
private int _size;
}
5. 尽量使用局部变量
尽量使用局部变量的建议源于Java内存管理机制的工作方式。Java虚拟机(JVM)中的内存主要分为堆内存(Heap)和栈内存(Stack),它们在功能和目的上有所不同,这直接影响到变量存取速度和效率。
堆(Heap)
- 堆内存用于存储Java运行时数据区,主要存放对象实例和数组。
- 访问速度相对较慢,因为堆内存是线程共享的,对堆内存的操作需要更多的时间来管理内存和垃圾回收。
- 堆内存的对象生命周期较长,可能导致更频繁的垃圾回收活动,从而影响性能。
栈(Stack)
- 栈内存用于执行线程,存储局部变量、方法调用和基本类型变量(包括方法的局部变量和方法调用时的参数)。
- 访问速度快,因为每个线程都有自己的栈,避免了线程间的竞争。
- 栈内存中的变量生命周期短暂,随着方法的结束而消失,这使得栈内存的管理效率更高,几乎无需垃圾回收。
使用局部变量的好处
- 提高性能:由于局部变量存储在栈上,它们的访问速度快于堆内存中的变量。这对于性能敏感的应用尤其重要。
- 减少内存开销:局部变量随着方法的结束而被清除,这有助于减少内存使用,避免了长时间占用堆内存和潜在的内存泄漏问题。
- 提高代码清晰度:使用局部变量可以提高方法的自封闭性和独立性,使得代码更容易理解和维护。
实践建议
- 尽可能将变量的作用域限制在最小范围内。例如,如果一个变量仅在方法内部使用,就应该将其声明为局部变量。
- 考虑在性能关键的代码段中使用基本类型而不是包装类,因为基本类型可以存储在栈上。
- 避免在循环或频繁调用的方法中创建不必要的对象,以减少对堆内存的使用和垃圾回收的压力。
6、尽量处理好包装类型和基本类型两者的使用场所
Java中的基本类型(如int, double, boolean等)和它们的包装类(如Integer, Double, Boolean等)在使用上确实有着不同的内存和性能特性。基本类型的数据直接存储在栈上,而包装类型的实例则存储在堆上。这个区别导致了它们在性能和使用场景上的不同考虑。
基本类型
- 性能优势:基本类型存储在栈上,访问速度快,且没有额外的内存开销,因为它们存储的是实际的值,不涉及对象的构造和垃圾回收。
- 使用场景:适用于数值运算、逻辑操作等场景,尤其是性能敏感的环境中。在不需要对象特性的情况下,应优先考虑使用基本类型。
包装类型
- 功能丰富:包装类型是类,提供了许多有用的方法,如转换、比较等。此外,包装类型支持null值,可以表示缺失或未定义的状态。
- 使用场景:在需要使用对象特性的场景中使用,如需要将数值作为对象存储在集合中(Java集合库中的类如
ArrayList,HashMap等不支持基本类型);或者在需要利用包装类型提供的方法时。在处理可能为null的数值时也需要使用包装类型。
自动装箱与拆箱
Java提供了自动装箱(autoboxing)和拆箱(unboxing)机制,允许基本类型和包装类型之间的自动转换。但是,这种便利性并不是没有代价的:
- 性能考虑:自动装箱和拆箱虽然在代码中提供了便利,但会带来额外的性能开销,因为这涉及到在基本类型和包装类型之间转换时的对象创建和解包。
- 隐藏的对象创建:频繁的自动装箱操作可能会导致大量的临时对象被创建,增加垃圾回收的负担。
最佳实践
- 在性能敏感的环境中,尽量使用基本类型以减少内存消耗和提高性能。
- 在需要使用集合、或者可能有
null值的场景中,使用包装类型。 - 明智地使用自动装箱和拆箱:了解代码中的自动装箱和拆箱操作,避免在循环或频繁执行的代码段中进行无意识的自动装箱/拆箱,以减少不必要的性能开销。
7、慎用synchronized,尽量减小synchronize的方法
正确地使用synchronized关键字对于确保Java多线程程序的线程安全至关重要。synchronized可以确保在同一时刻,只有一个线程能够访问同步的方法或代码块,从而防止多线程环境下的数据一致性和完整性问题。然而,过度或不当使用synchronized确实会引入显著的性能开销,并有可能导致死锁等问题。因此,合理地使用synchronized,并采取措施减少需要同步的代码量是提高多线程程序性能的关键。
尽量减小同步范围
-
使用同步代码块代替同步方法:在可能的情况下,优先考虑同步关键的代码段而不是整个方法。这可以通过将
synchronized关键字应用于代码块来实现,而不是方法。同步代码块可以减少锁定的范围,从而减少线程等待的时间,提高程序的并发性和性能。public void method() {// 非同步区域synchronized(this) {// 需要同步的区域}// 非同步区域 }
减少锁的粒度
- 使用更细粒度的锁:考虑使用不同的锁对象对数据进行更细粒度的控制。这样可以减少不同线程间的竞争,允许更高的并发度。例如,如果有多个资源或数据结构需要同步,为每个资源或数据结构提供独立的锁对象。
避免死锁
- 小心锁的顺序:在多个线程需要获取多个锁时,确保所有线程以相同的顺序获取锁,这是避免死锁的一种简单而有效的策略。
使用其他并发控制工具
- 利用
java.util.concurrent包:Java平台提供了丰富的并发工具类,如ReentrantLock、ReadWriteLock、Semaphore等,它们提供了比synchronized更灵活的锁定机制和更高级的并发控制功能。这些工具可以提供更细粒度的锁控制,并且在某些情况下比synchronized更高效。
精心设计对象的并发访问
- 最小化锁持有时间:尽量确保持有锁的时间尽可能短,这样可以减少线程阻塞的可能性,提高系统的响应性和吞吐量。
- 考虑使用不可变对象:不可变对象天生是线程安全的,因为它们的状态在创建之后不能改变,因此不需要同步控制。在多线程环境中,尽可能使用不可变对象可以简化程序设计,减少同步需求。
8、尽量不要使用finalize方法
Java的finalize()方法曾经被用作在对象被垃圾回收器回收之前执行清理工作的一种机制。然而,依赖finalize()方法进行资源清理确实有几个显著的缺点,这也是为什么现代Java开发中强烈建议避免使用它:
不确定性
finalize()的调用时机非常不确定,取决于垃圾回收器的执行时机,这可能导致资源过长时间未被释放,比如文件句柄或数据库连接等,从而可能耗尽资源。- 由于
finalize()执行时间的不可预测性,可能导致对象的清理延迟,增加了内存泄露和资源耗尽的风险。
性能影响
- 当垃圾回收器执行
finalize()方法时,会延迟对象的回收,因为需要将这些对象放入一个称为finalization queue的队列中,等待下一轮垃圾回收。这不仅增加了垃圾回收的负担,还可能导致更频繁的垃圾回收,影响程序性能。 - 使用
finalize()可能导致显著的性能下降,尤其是在需要快速回收资源的高性能应用中。
安全风险
- 在
finalize()方法中,如果抛出异常且未被捕获,会导致垃圾回收过程中的异常终止,而这个异常不会被打印或警告,可能导致难以发现和调试的错误。 finalize()还可以被恶意用于对象复活(在finalize()方法中重新赋予对象引用),这可能导致安全漏洞或逻辑错误。
替代方案
- 对于需要清理的资源,最佳实践是使用
try-with-resources语句(Java 7及以上版本),这确保了每个资源在用完后立即被正确关闭,而无需依赖垃圾回收器的调度。 - 对于非自动关闭资源的清理,推荐显式地管理资源的生命周期,例如在使用完资源后立即手动释放它们,使用
try/finally块确保资源在所有情况下都被释放。
9、尽量使用基本数据类型代替对象
在Java中,基本数据类型(如int, double, boolean等)与对象(如String,以及包装类如Integer, Double, Boolean等)之间的选择对性能有显著影响。基本数据类型直接存储值,而对象则需要在堆上分配内存来存储数据和对象的元数据,这不仅增加了内存使用,还增加了垃圾回收的负担。因此,尽可能使用基本数据类型而不是它们的包装类,可以提高性能。
字符串对象示例
您提到的两种创建String对象的方式,展示了如何通过字面量和构造函数创建字符串,并且它们在内存使用上有显著的不同:
-
使用字面量创建字符串:
String str = "hello";这种方式首先检查字符串池中是否已经包含了一个等于此字符串的字符串(即值为"hello")。如果存在,则返回引用到池中的现有字符串;否则,新的字符串将被创建,并放入池中。这种方式避免了重复创建相同的字符串对象,节省了内存。
-
使用
new关键字创建字符串对象:String str = new String("hello");这种方式实际上创建了两个字符串对象(如果"hello"不在字符串池中的话)。首先是字面量"hello"会被添加到字符串池(如果它还不在池中的话),然后
new表达式创建了一个新的String对象在堆上,该对象包含一个指向内部字符数组(char[])的引用,这个数组存储了字符串的实际字符。这不仅消耗了更多的内存,而且在创建过程中增加了性能开销。
性能建议
-
优先使用字符串字面量:在创建字符串时,尽可能使用字面量的方式,以利用Java字符串池的优势,避免不必要的对象创建。
-
基本类型 vs 包装类型:对于基本数据类型,应尽量使用它们而不是它们的包装类,尤其是在需要大量数值操作的场景中。这样做可以减少堆内存的使用和垃圾回收的开销,从而提高性能。
-
显式使用
intern()方法:如果确实需要通过new String()创建新的字符串对象,并希望后续利用字符串池的优势,可以调用intern()方法。这个方法会确保字符串被加入到池中,并返回池中字符串的引用。不过,需要注意的是,intern()方法的使用也应该是有选择的,因为维护字符串池本身也是有成本的。
10、多线程在未发生线程安全前提下应尽量使用HashMap、ArrayList
在Java中,确实存在多种集合类,它们在性能和线程安全方面各有特点。当你的应用场景中不存在线程安全问题时,优先选择非同步的集合类是提高性能的一个好策略。
HashMap vs Hashtable
- HashMap是非同步的,因此在没有外部同步机制的情况下不保证线程安全。这意味着如果多个线程同时访问一个HashMap,并且至少有一个线程从结构上修改了映射,它必须保持外部同步。由于缺少同步机制,HashMap在单线程环境下或在读多写少的并发环境中使用时,性能要优于Hashtable。
- Hashtable是线程安全的,每个方法都是同步的,这会带来额外的性能开销。因此,当不需要线程安全的保证时,使用Hashtable会导致不必要的性能损失。
ArrayList vs Vector
- ArrayList是非同步的,提供了快速的迭代和随机访问能力。由于它不是线程安全的,所以在多线程环境下使用时需要注意。但在单线程或读多写少的并发控制下,其性能通常优于Vector。
- Vector是同步的,这意味着它在多线程环境下是安全的,但这种线程安全是以牺牲性能为代价的。Vector的每个操作几乎都是同步的,这使得在高并发场景下可能会成为瓶颈。
并发集合作为替代
在需要线程安全的并发访问时,Java的java.util.concurrent包提供了一系列性能更好的线程安全集合,如ConcurrentHashMap、CopyOnWriteArrayList等。这些集合使用了更先进的并发控制策略,如分段锁和写时复制,旨在减少锁竞争,从而提供比Hashtable和Vector更高的性能。
最佳实践
- 在非线程安全的场景下,优先使用
HashMap和ArrayList以获得更好的性能。 - 当需要线程安全的集合时,考虑使用
java.util.concurrent包中的集合,如ConcurrentHashMap,而不是旧的线程安全集合如Hashtable和Vector。 - 如果确实需要在多线程环境中使用
HashMap和ArrayList,确保访问这些集合的操作是适当同步的,或者考虑使用Collections.synchronizedMap(Map)和Collections.synchronizedList(List)来包装非同步的集合,提供线程安全的访问。
相关文章:
Java:性能优化细节01-10
Java:性能优化细节01-10 在Java程序开发过程中,性能优化是一个重要的考虑因素。常见的误解是将性能问题归咎于Java语言本身,然而实际上,性能瓶颈更多地源于程序设计和代码实现方式的不当。因此,培养良好的编码习惯不仅…...
CVE-2022-24652 漏洞复现
CVE-2022-24652 开题 后台管理是thinkphp的,但是工具没检测出漏洞。 登陆后界面如下,上传头像功能值得引起注意 这其实就是CVE-2022-24652,危险类型文件的不加限制上传,是文件上传漏洞。漏洞路由/user/upload/upload 参考文章&a…...
LeetCode、338. 比特位计数【简单,位运算】
文章目录 前言LeetCode、338. 比特位计数【中等,位运算】题目链接与分类思路位运算移位处理前缀思想实现 资料获取 前言 博主介绍:✌目前全网粉丝2W,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java…...
借助Aspose.BarCode条码控件,C# 中的文本转 QR 码生成器
二维码用于在较小的空间内存储大量数据。它们易于使用,可以通过智能手机或其他设备扫描来打开网站、观看视频或访问其他编码信息。在这篇博文中,我们将学习如何使用 C# 以编程方式生成基于文本的 QR 码。我们将提供分步指南和代码片段,帮助您…...
vue打包优化,webpack的8大配置方案
vue-cli 生成的项目通常集成Webpack ,在打包的时候,需要webpack来做一些事情。这里我们希望它可以压缩代码体积,提高运行效率。 文章目录 (1)代码压缩:(2)图片压缩:&…...
B端系统从0到1:有几步,其中需求分析要做啥?
一款B系统从无到有都经历了啥,而其中的需求分析又要做什么?贝格前端工场给老铁们做一下分析,文章写作不易,如果咱们有界面设计和前端开发需求,别忘了私信我呦,开始了。 一、B端系统从0到1都有哪些要走的步骤…...
django中查询优化
在Django中,查询优化是一个重要的主题,因为不正确的查询可能会导致性能问题,尤其是在处理大量数据时。以下是一些在Django中进行查询优化的建议: 一:使用select_related和prefetch_related: select_related用于优化一…...
【JavaScript】输入输出语法
目录 一、输出语法 二、输入语法 一、输出语法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>D…...
多模态基础--- word Embedding
1 word Embedding 原始的单词编码方式: one-hot,维度太大,不同单词之间相互独立,没有远近关系区分。 wordclass,将同一类单词编码在一起,此时丢失了类别和类别间的相关信息,比如class1和class3…...
Mysql 日志
0 引言 MySQL日志主要分为4类,使用这些日志文件,可以查看MySQL内部发生的事情。这4类日志分别是: ● 错误日志:记录MySQL服务的启动、运行或停止MySQL服务时出现的问题。 ● 查询日志:记录建立的客户端连接和执行的…...
【开源】SpringBoot框架开发服装店库存管理系统
目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 角色管理模块2.3 服装档案模块2.4 服装入库模块2.5 服装出库模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 角色表3.2.2 服装档案表3.2.3 服装入库表3.2.4 服装出库表 四、系统展示五、核心代码5.…...
云原生之容器编排实践-在K8S集群中使用Registry2搭建私有镜像仓库
背景 基于前面搭建的3节点 Kubernetes 集群,今天我们使用 Registry2 搭建私有镜像仓库,这在镜像安全性以及离线环境下运维等方面具有重要意义。 Note: 由于是测试环境,以下创建了一个 local-storage 的 StorageClass ,并使用本地…...
标准IO 2月4日学习笔记
IO输入输出,操作对象是文件 Linux文件类型: b block 块设备文件 按块扫描设备信息的文件 存储设备 c character 字符设备文件 按字符扫描设备信息的文件 d direct…...
如何在1Panel上偷渡HTTP/3
本文 首发于 Anyeの小站,转载请取得作者同意。 前言 简介 HTTP/3 的基础即谷歌多年探索的基于 UDP 的 QUIC 协议。与 TCP 相比,使用 UDP 可以提供更大的灵活性,并且可以使 QUIC 完全于用户空间中实现——对协议实现的更新不像 TCP 那样需要绑…...
Qt实用技巧:QCustomPlot做北斗GPS显示绝对位置运动轨迹和相对位置运动轨迹图的时,使图按照输入点顺序连曲线
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/136131310 红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…...
116 C++ 可变参数函数,initializer_list (初始化列表), 省略号形参
一 可变参数函数 有时候我们传递的参数是不固定的。 这种能接受非固定个数参数的函数就是可变参数函数 怎么实现呢?就要用到 initializer_list 标准库类型 该类型能够使用的前提条件是:所有的实参类型相同。 二,initializer_list(初始化列…...
强国有我社会实践公益活动在合肥市庐阳区开展
2月18日是开工第一天,阳光灿烂、春光明媚。合肥市四十五中2022级星辰(5)班部分同学在监护人的陪伴下来到庐阳区双岗街道万小店社区残疾人工作站,和工作站兄弟姐妹们共同开展“强国复兴有我”社会实践公益活动。合肥市庐阳区为民社…...
Nginx 正向代理、反向代理
文章目录 前言1. 正向代理1.1 概念1.2 逻辑图1.3 使用场景 2. 反向代理2.1 概念2.2 逻辑图2.3 使用场景 前言 正向代理主要是用来解决访问限制问题;反向代理则是提供负载均衡、安全防护等作用 1. 正向代理 1.1 概念 正向代理是一个位于客户端和目标服务器之间的代理…...
软考学习--计算机组成原理与体系结构
计算机组成原理与体系结构 数据的表示 进制转换 R 进制转换为 10 进制–按权展开法 10进制转换为2进制 原码 反码 补码 移码 原码 :数字的二进制表示反码 : 正数的反码等于原码,负数的反码等于原码取反补码: 正数的补码等…...
fish终端下conda activate失败
【问题】fish终端下激活conda环境报错: >> conda activate base CondaError: Run conda init before conda activate ## 然而运行 conda init fish 仍旧无法解决【解决】 参考:https://github.com/conda/conda/issues/11079 方法一…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
Python学习(8) ----- Python的类与对象
Python 中的类(Class)与对象(Object)是面向对象编程(OOP)的核心。我们可以通过“类是模板,对象是实例”来理解它们的关系。 🧱 一句话理解: 类就像“图纸”,对…...
DeepSeek越强,Kimi越慌?
被DeepSeek吊打的Kimi,还有多少人在用? 去年,月之暗面创始人杨植麟别提有多风光了。90后清华学霸,国产大模型六小虎之一,手握十几亿美金的融资。旗下的AI助手Kimi烧钱如流水,单月光是投流就花费2个亿。 疯…...
