【第四节】python面向对象

news2024/9/9 8:03:30

目录

一、类和对象

二、类的定义和数据属性

三、特殊的类属性

四、类的成员方法

五、类的访问控制

六、类的构造与析构

七、类的继承

7.1 单继承

7.2 多继承

7.3 多继承中的二义性问题

7.4 使用`super`


一、类和对象

        “高内聚,低耦合”是软件工程中追求的核心原则,其核心理念是每个模块或组件应专注于完成自己的任务,并尽量减少对外部代码的依赖。

在不同的编程范式中,这一原则都有所体现:
- **面向过程编程**:一个函数应尽可能独立地完成一项任务。
- **面向对象编程**:一个对象应尽量自主处理自己的事务,减少对其他对象的依赖。

        面向对象编程相较于面向过程编程的一个显著优势在于,它将数据和操作数据的方法封装在一起,自然地实现了高内聚。类作为面向对象编程的基本构建块,是这一思想的具体体现。

        类和对象的关系:类是对现实世界中实体的抽象,而对象是类在内存中的具体实例。Python作为一种支持面向对象编程的语言,同样引入了类的概念。在Python中:
        - 类中的变量被称为“成员变量”或“数据属性”。
        - 类中的函数被称为“成员函数”或“成员方法”。

        此外,Python中习惯将对象称为实例,强调了对象是类的一个具体实现。

二、类的定义和数据属性

        在 Python 中,可以通过class 关键字定义自己的类,然后通过自定义的类创建实例对象。

        类和实例都有自己的数据属性。类数据属性是属于类的,所有实例共享这些属性。实例数据属性是属于单个实例的,每个实例都有自己的副本。

class Student(object):
    count = 0  # 类数据属性
    books = []  # 类数据属性

    def __init__(self, name, age):
        self.name = name  # 实例数据属性
        self.age = age  # 实例数据属性

objStudent1 = Student("xiaoming", 19)

在这个例子中:

1. **类数据属性**:
   - `count`:这是一个类数据属性,所有`Student`类的实例共享这个属性。
   - `books`:这也是一个类数据属性,所有`Student`类的实例共享这个属性。

2. **实例数据属性**:
   - `name`:这是一个实例数据属性,每个`Student`实例都有自己的`name`属性。
   - `age`:这也是一个实例数据属性,每个`Student`实例都有自己的`age`属性。

类数据属性和实例数据属性的主要区别在于它们的共享方式和作用范围:

- **类数据属性**:这些属性在所有实例之间共享。如果你修改了一个类数据属性,所有实例都会看到这个修改。
- **实例数据属性**:这些属性是每个实例独有的。修改一个实例的实例数据属性不会影响其他实例。

        例如,如果你创建多个`Student`实例并修改它们的`name`或`age`属性,每个实例都会有自己独立的`name`和`age`值。但是,如果你修改了`Student`类的`count`或`books`属性,所有实例都会看到这个修改。

总结一下:

- `count` 和 `books` 是类数据属性。
- `name` 和 `age` 是实例数据属性。

在Python中,属性分为两种类型:实例属性和类属性。

实例数据属性

  • 在构造函数__init__中定义,并以self作为前缀。

  • 实例属性属于单个实例(对象),只能通过对象名来访问。

类数据属性

  • 在类内部直接定义,不以self作为前缀。

  • 类属性属于类本身,可以通过类名来访问和修改。

  • 尽管类属性也可以通过对象来访问,但不推荐这样做,因为这可能导致类属性值的不一致。

总结类数据属性和实例数据属性:

  • 类数据属性属于类本身,可以通过类名进行访问和修改。

  • 类数据属性也可以被类的所有实例访问和修改。

  • 在类定义之后,可以通过类名动态添加类数据属性,新增的类属性也被类和所有实例共享。

  • 实例数据属性只能通过实例来访问。

  • 在实例生成后,还可以动态添加实例数据属性,但这些实例数据属性只属于该实例。

三、特殊的类属性

        在Python中,类有一些特殊的属性,这些属性提供了关于类的额外信息或功能。以下是一些常见的特殊类属性:

1. **`__name__`**:
   - 返回类的名称。

   class MyClass:
       pass

   print(MyClass.__name__)  # 输出: MyClass

2. **`__module__`**:
   - 返回定义类的模块的名称。

   class MyClass:
       pass

   print(MyClass.__module__)  # 输出: __main__(如果在主模块中定义)

3. **`__dict__`**:
   - 返回类的命名空间,包含类的属性和方法。

   class MyClass:
       class_var = 1

       def __init__(self):
           self.instance_var = 2

   print(MyClass.__dict__)
   # 输出: {'__module__': '__main__', 'class_var': 1, '__init__': <function MyClass.__init__ at 0x...>, ...}

4. **`__bases__`**:
   - 返回一个包含类的所有基类的元组。

   class BaseClass:
       pass

   class MyClass(BaseClass):
       pass

   print(MyClass.__bases__)  # 输出: (<class '__main__.BaseClass'>,)

5. **`__doc__`**:
   - 返回类的文档字符串(如果定义了的话)。
 

class MyClass:
       """This is a docstring for MyClass."""
       pass

   print(MyClass.__doc__)  # 输出: This is a docstring for MyClass.

6. **`__class__`**:
   - 返回实例所属的类。

   class MyClass:
       pass

   obj = MyClass()
   print(obj.__class__)  # 输出: <class '__main__.MyClass'>

7. **`__mro__`**:
   - 返回一个包含类的继承顺序的元组,即方法解析顺序(Method Resolution Order)。

   class A:
       pass

   class B(A):
       pass

   class C(B):
       pass

   print(C.__mro__)  # 输出: (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

        这些特殊属性提供了关于类的结构和行为的详细信息,有助于更好地理解和操作类及其实例。

四、类的成员方法

        在Python中,类可以定义三种不同类型的方法:实例方法、静态方法和类方法。每种方法都有其特定的用途和行为。

1. **实例方法(Instance Methods)**:
   - 实例方法是类中最常见的方法类型。
   - 实例方法的第一个参数通常是`self`,它代表类的实例。
   - 实例方法可以访问和修改实例属性,并且可以调用其他实例方法。
   - 实例方法只能通过实例来调用。

class MyClass:
       def __init__(self, value):
           self.value = value

       def instance_method(self):
           print(f"Instance method called with value: {self.value}")

   obj = MyClass(10)
   obj.instance_method()  # 输出: Instance method called with value: 10

2. **静态方法(Static Methods)**:
   - 静态方法使用`@staticmethod`装饰器来定义。
   - 静态方法没有`self`参数,因此不能访问或修改实例属性。
   - 静态方法与类和实例无关,通常用于与类相关但不需要访问实例或类属性的功能。
   - 静态方法可以通过类或实例来调用。

 class MyClass:
       @staticmethod
       def static_method():
           print("Static method called")

   MyClass.static_method()  # 输出: Static method called
   obj = MyClass()
   obj.static_method()      # 输出: Static method called

3. **类方法(Class Methods)**:
   - 类方法使用`@classmethod`装饰器来定义。
   - 类方法的第一个参数通常是`cls`,它代表类本身。
   - 类方法可以访问和修改类属性,并且可以调用其他类方法。
   - 类方法可以通过类或实例来调用。

class MyClass:
       class_var = 0

       @classmethod
       def class_method(cls):
           print(f"Class method called with class var: {cls.class_var}")

   MyClass.class_method()  # 输出: Class method called with class var: 0
   obj = MyClass()
   obj.class_method()      # 输出: Class method called with class var: 0

总结:
- **实例方法**:用于操作实例属性,通过实例调用。
- **静态方法**:与类和实例无关,通过类或实例调用。
- **类方法**:用于操作类属性,通过类或实例调用。

        实例方法其实就是最为普通的成员函数。类方法与静态方法似乎没有什么差别,一般不需要访问类成员或者实例成员可以使用静态方法,需要访问类成员的使用类方法。这些方法类型提供了灵活性,使得代码更加模块化和易于维护。

 

五、类的访问控制

        在Python中,确实没有像其他一些编程语言那样的严格访问控制关键字(如`private`、`protected`)。但是,Python社区通过一些命名约定来实现类似的效果,以表明变量、函数或方法的访问级别。以下是这些约定的详细解释:

1. **单下划线(`_`)**:
        在模块级别,以单下划线开头的变量或函数通常被视为模块私有的。这意味着当你使用`from module import *`语句时,这些以单下划线开头的名称不会被导入。
   - 在类中,以单下划线开头的实例变量或方法通常被视为“受保护的”,即不鼓励外部直接访问,但技术上仍然可以访问。

 # 模块级别
   _private_var = 42

   def _private_function():
       return "This is a private function"

   # 类中
   class MyClass:
       def __init__(self):
           self._protected_var = 10

       def _protected_method(self):
           return "This is a protected method"

2. **双下划线(`__`)**:
        在类中,以双下划线开头的实例变量或方法会被Python解释器进行名称改写(name mangling),以实现一定程度的私有化。具体来说,解释器会在名称前加上`_ClassName`,从而使得这些成员在类外部难以直接访问。

class MyClass:
       def __init__(self):
           self.__private_var = 20

       def __private_method(self):
           return "This is a private method"

   obj = MyClass()
   # 以下访问方式会引发AttributeError
   # print(obj.__private_var)
   # print(obj.__private_method())

   # 但可以通过改写后的名称访问
   print(obj._MyClass__private_var)  # 输出: 20
   print(obj._MyClass__private_method())  # 输出: This is a private method

3. **特殊变量**:
        以双下划线开头和结尾的变量(如`__init__`、`__str__`)是Python中的特殊方法或属性,通常用于实现特定的语言功能(如构造函数、字符串表示等)。这些变量可以直接访问,并且不是私有变量。

   class MyClass:
       def __init__(self):
           self.__special_var__ = 30

   obj = MyClass()
   print(obj.__special_var__)  # 输出: 30

总结:
- **单下划线**:模块级别的私有化,类中的受保护成员。
- **双下划线**:类中的私有成员(通过名称改写实现)。
- **双下划线开头和结尾**:特殊变量,用于实现特定的语言功能。

        这些约定有助于提高代码的可读性和维护性,但它们并不提供真正的访问控制,因为Python解释器不会阻止你访问这些“私有”或“受保护”的成员。

六、类的构造与析构

        在Python中,类的构造函数和析构函数是两个特殊的方法,它们分别用于对象的初始化和资源释放。以下是关于这两个方法的详细解释:

### 构造函数
        **构造函数**:在Python中,构造函数是`__init__`方法。它用于在创建对象时初始化对象的属性。
        当用户定义一个类时,可以显式地定义`__init__`方法来设置对象的初始状态。
        如果用户没有定义`__init__`方法,Python会提供一个默认的构造函数,该构造函数不执行任何操作。
        构造函数属于类,而不是单个对象。每个对象在创建时都会调用类的构造函数。

class MyClass:
    def __init__(self, value):
        self.value = value

obj = MyClass(10)  # 调用构造函数 __init__
print(obj.value)   # 输出: 10

### 析构函数
        **析构函数**:在Python中,析构函数是`__del__`方法。它用于在对象被销毁之前释放对象占用的资源。
        当对象的引用计数变为零时,Python的垃圾回收机制会自动调用`__del__`方法。
        如果用户没有定义`__del__`方法,Python会提供一个默认的析构函数,该析构函数不执行任何操作。
        析构函数同样属于类,而不是单个对象。每个对象在销毁时都会调用类的析构函数。

class MyClass:
    def __init__(self, value):
        self.value = value

    def __del__(self):
        print(f"Object with value {self.value} is being destroyed")

obj = MyClass(10)
del obj  # 调用析构函数 __del__,输出: Object with value 10 is being destroyed

总结:
- **构造函数**:`__init__`方法,用于对象的初始化。
- **析构函数**:`__del__`方法,用于对象的资源释放。

        需要注意的是,虽然Python提供了默认的构造函数和析构函数,但在实际编程中,通常不需要显式地定义析构函数,因为Python的垃圾回收机制会自动处理对象的内存管理。只有在需要执行特定资源释放操作时,才需要定义`__del__`方法。

七、类的继承

        在Python中,继承是一种机制,允许一个类(子类)继承另一个类(父类)的属性和方法。Python支持单继承和多继承。以下是关于继承的一些详细解释和示例:

7.1 单继承

单继承是指一个子类只继承一个父类。语法如下:

class ParentClass:
    def __init__(self, parent_attr):
        self.parent_attr = parent_attr

    def parent_method(self):
        print(f"Parent method called with attribute: {self.parent_attr}")

class SubClass(ParentClass):
    def __init__(self, parent_attr, sub_attr):
        super().__init__(parent_attr)  # 调用父类的构造函数
        self.sub_attr = sub_attr

    def sub_method(self):
        print(f"Sub method called with attribute: {self.sub_attr}")

# 实例化子类
obj = SubClass("parent_value", "sub_value")
obj.parent_method()  # 输出: Parent method called with attribute: parent_value
obj.sub_method()     # 输出: Sub method called with attribute: sub_value

7.2 多继承

多继承是指一个子类继承多个父类。语法如下:

class ParentClassA:
    def __init__(self, attr_a):
        self.attr_a = attr_a

    def method_a(self):
        print(f"Method A called with attribute: {self.attr_a}")

class ParentClassB:
    def __init__(self, attr_b):
        self.attr_b = attr_b

    def method_b(self):
        print(f"Method B called with attribute: {self.attr_b}")

class SubClass(ParentClassA, ParentClassB):
    def __init__(self, attr_a, attr_b, sub_attr):
        ParentClassA.__init__(self, attr_a)  # 调用父类A的构造函数
        ParentClassB.__init__(self, attr_b)  # 调用父类B的构造函数
        self.sub_attr = sub_attr

    def sub_method(self):
        print(f"Sub method called with attribute: {self.sub_attr}")

# 实例化子类
obj = SubClass("value_a", "value_b", "sub_value")
obj.method_a()  # 输出: Method A called with attribute: value_a
obj.method_b()  # 输出: Method B called with attribute: value_b
obj.sub_method()  # 输出: Sub method called with attribute: sub_value

7.3 多继承中的二义性问题

        在多继承中,如果多个父类有同名的方法或属性,Python会按照方法解析顺序(Method Resolution Order, MRO)来决定调用哪个方法。Python使用C3线性化算法来确定MRO,通常是广度优先的顺序。

class A:
    def method(self):
        print("A's method")

class B(A):
    def method(self):
        print("B's method")

class C(A):
    def method(self):
        print("C's method")

class D(B, C):
    pass

obj = D()
obj.method()  # 输出: B's method

        在这个例子中,`D`类继承自`B`和`C`,而`B`和`C`都继承自`A`。由于`D`的MRO是`[D, B, C, A]`,所以`obj.method()`会调用`B`类的方法。

7.4 使用`super`

        在子类中,可以使用`super()`函数来调用父类的方法,这样可以避免直接引用父类的名称,使代码更加灵活和可维护。

class ParentClass:
    def __init__(self, parent_attr):
        self.parent_attr = parent_attr

    def parent_method(self):
        print(f"Parent method called with attribute: {self.parent_attr}")

class SubClass(ParentClass):
    def __init__(self, parent_attr, sub_attr):
        super().__init__(parent_attr)  # 调用父类的构造函数
        self.sub_attr = sub_attr

    def sub_method(self):
        print(f"Sub method called with attribute: {self.sub_attr}")
        super().parent_method()  # 调用父类的方法

# 实例化子类
obj = SubClass("parent_value", "sub_value")
obj.sub_method()  # 输出: Sub method called with attribute: sub_value
                  # 输出: Parent method called with attribute: parent_value

        通过使用`super()`,可以确保在多继承的情况下,正确地调用父类的方法。

总结:

        在Python中,继承机制允许一个类(子类)继承另一个或多个类(父类)的属性和方法。Python支持单继承和多继承。

        通过继承,子类可以继承父类的属性,并且可以使用内置函数`issubclass()`来判断一个类是否是另一个类的子类或子孙类。

### 继承后的构造函数
        在处理继承时,需要特别注意初始化函数`__init__`的行为。如果子类没有定义自己的`__init__`函数,父类的`__init__`函数会被自动调用。然而,如果子类定义了自己的`__init__`函数,但没有显式调用父类的`__init__`函数,父类的属性将不会被初始化。

        如果子类定义了自己的`__init__`函数并显式调用了父类的`__init__`函数,那么子类和父类的属性都会被正确初始化。

### 使用`super`
        在子类中,通常会定义与父类相同的属性(数据属性和方法),以实现子类特有的行为。子类会继承父类的所有属性和方法,并且可以覆盖父类中同名的属性和方法。

        有时需要在子类中访问父类的属性,这时可以使用`super()`函数。`super()`函数提供了一种方便的方式来调用父类的方法,而不需要直接引用父类的名称。

### 多继承问题
        Python允许使用多继承,只需在子类定义时列出所有父类即可:

class CTest(CA, CB):
    pass

        通过这种方式,一个类可以同时继承自多个类。然而,多继承可能会导致二义性问题,例如:

- 当两个父类有同名函数或变量时。
- 当出现菱形继承时。

        Python通过广度优先的顺序来解决这些二义性问题,即按照方法解析顺序(Method Resolution Order, MRO)来寻找同名的函数或变量。Python使用C3线性化算法来确定MRO,确保方法调用的顺序是明确的。

        总结来说,Python的继承机制提供了灵活的方式来构建类之间的关系,但需要注意构造函数的调用、使用`super()`函数以及处理多继承时的二义性问题。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

揭秘住宅IP代理:原理、用途以及应用分析

在大数据时代&#xff0c;互联网成为我们生活与工作中不可或缺的一部分。然而&#xff0c;随着网络环境的日益复杂&#xff0c;隐私保护、网络访问限制等问题也逐渐凸显&#xff1b;以及跨境业务蓬勃发展。在这样的背景下&#xff0c;住宅IP代理作为一种技术解决方案&#xff0…

6、指针

6 指针 6.1 指针的本质&#xff08;间接访问的原理&#xff09; 指针&#xff1a;变量的地址 指针变量&#xff1a;用一个变量来存放另一个变量的地址&#xff0c;该变量即为指针变量 指针变量占内存大小&#xff0c;32位程序占4字节&#xff0c;64位占8字节 取地址操作符、取…

数据结构_study(三)

栈 先进后出&#xff0c;LIFO&#xff08;last in first out&#xff09;&#xff0c;只能在表尾做插入删除操作的线性表 栈顶&#xff1a;允许插入和删除的一端 栈底&#xff1a;最先进栈 空栈&#xff1a;没有数据元素 压栈、入栈&#xff1a;插入操作 弹栈、出栈&#xf…

ubuntu20复现NBV探索

官网代码 后退地平线下一个最佳景观规划师 这个代码有些久远&#xff0c;issue里面有人已经在ubuntu20里面使用了3dmr&#xff0c;但是他那个代码我也运行不成功&#xff0c;docker网络一直也不佳&#xff0c;所以还是自己重新修改源码靠谱。 最终实现的代码等有时间上传到gi…

Day26 | 贪心算法 134. 加油站 135. 分发糖果 860.柠檬水找零 406.根据身高重建队列

语言 Java 134. 加油站 题目链接&#xff1a;加油站 题目 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发…

【每日一题】【map和set】RC-v7 熊猫血 C++

2024 睿抗机器人开发者大赛CAIP-编程技能赛-高职组&#xff08;省赛&#xff09; RC-v7 熊猫血 题目描述 在“一年一度喜剧大赛”上有一部作品《少爷和我》&#xff0c;讲的是霸道管家龙傲天和憨厚少爷刘波的故事。管家有着霸总文学主人公所有的毛病&#xff0c;包括会咳出熊…

服务运营 | NRL:疫苗供应链优化建模:综述与未来机遇(上)

编者按&#xff1a; 本次推文将解读近期发表在Naval Research Logistics中的Optimization modeling for pandemic vaccine supply chain management: A review and future research opportunities一文。这篇文章总结与反思了大流行时期的疫苗供应链管理&#xff0c;具体包括疫…

C#基于SkiaSharp实现印章管理(5)

印章中最常见的特殊形状通常是五角星&#xff0c;空心、实心的都可能存在&#xff0c;本文学习并实现在印章内部绘制五角星形状。   百度五角星的绘制方法&#xff0c;主要分为三种&#xff1a;   1&#xff09;五角星各点坐标固定&#xff0c;直接调用编程语言的绘制线条或…

线性结构、线性表、顺序表、链表、头插法、尾插法、中间插入或删除一个节点

梳理几个名词&#xff1a; 逻辑地址&#xff1a;就是说是第几个元素。 物理地址&#xff1a;也就是存储地址&#xff0c;在计算机里具体存放的位置。 线性表的存储结构分为&#xff1a; &#xff08;1&#xff09;顺序存储结构&#xff1a;将数据依次存储在连续的整块物理空…

综合项目部署——eleme前端部署(eighteen day)

显示没有空格没有注释的内容&#xff1a; [rootstatic-server ~]# grep -Ev "#|^$" /usr/local/nginx/conf/nginx.conf 1、多虚拟主机的配置 [rootstatic-server ~]# vim /usr/local/nginx/conf/nginx.conf [rootstatic-server ~]# /usr/local/nginx/sbin/nginx #启…

如何破解绩效管理的难题?

绩效管理的核心问题 &#x1f4bc; 在现代企业运营中&#xff0c;绩效管理一直被视为提升工作效率和实现公司战略目标的重要手段。然而&#xff0c;实际操作中&#xff0c;我们经常会遇到一系列棘手的问题&#xff0c;这些问题不仅影响了绩效管理的有效性&#xff0c;还常常让…

winform程序中拷贝文件夹最快速方法

1、先将一个项目的文件夹拷贝到另一个项目的目录下 下图将ParameterSetting文件夹拷贝到Datalib文件夹下 2、直接复制该文件&#xff0c;然后到vs界面去粘贴 复制ParameterSetting文件夹&#xff0c;然后在Datalib项目这里鼠标右键单击&#xff0c;然后点击“粘贴”&#xff0…

机器学习(五) -- 无监督学习(2) --降维2

系列文章目录及链接 上篇&#xff1a;机器学习&#xff08;五&#xff09; -- 无监督学习&#xff08;2&#xff09; --降维1 下篇&#xff1a; 前言 tips&#xff1a;标题前有“***”的内容为补充内容&#xff0c;是给好奇心重的宝宝看的&#xff0c;可自行跳过。文章内容被…

《动手做科研》06. 如何产生新的研究想法

地址链接:《动手做科研》06. 如何产生新的研究想法 欢迎加入我的知识星球&#xff0c;定期分享AI论文干货知识&#xff01; 导读: 提出好的研究想法是相当困难的&#xff0c;特别是当你刚接触一个领域时——这需要对文献中的空白有所了解。然而&#xff0c;产生研究想法的过程可…

数学建模--智能算法之模拟退火算法

目录 算法原理 应用场景 实现方法 代码示例&#xff1a; MATLAB&#xff1a; Python&#xff1a; 总结 模拟退火算法在数学建模中的具体应用案例有哪些&#xff1f; 如何选择模拟退火算法的参数&#xff08;如初始温度、冷却率等&#xff09;以优化求解过程&#xff1…

根据json构建uml类图代码工具实现

文章目录 1.UML简介1.1 什么是UML建模1.2 使用UML建模的好处 2.当前UML在研发场景下痛点3.UML工具的优化实现3.1 json结构设计3.2 json类图解析器实现3.3 在线uml类图渲染实现3.3.1 前端渲染页面3.3.2 后端数据接口 3.4 在线渲染效果 4. 总结 【摘要】本文介绍UML基本概念及相关…

Linux中安装C#的.net,创建运行后端或控制台项目

安装脚本命令&#xff1a; 创建一个sh文件并将该文件更改权限运行 sudo apt update wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb sudo apt-get upd…

科普文:Spring Cloud Alibaba在GraalVM上的性能测试

GraalVM 介绍 GraalVM概述 - Spring Cloud Alibaba官网 科普文&#xff1a;GraalVM简介-CSDN博客 科普文&#xff1a;OpenJDK vs. GraalVM vs. Amazon Corretto性能测试-CSDN博客 科普文&#xff1a;【方向盘】OpenJDK生态圈-CSDN博客 科普文&#xff1a;Oracle JDK收费后…

【32单片机篇】项目:实时时钟

一、项目需求 1. OLED屏幕显示当前时间、日期、闹钟等信息&#xff1b; 2. 正常模式下&#xff0c;按下 KEY1 &#xff0c;进入时间设置模式&#xff0c;此时按下 KEY2 则可以循环跳转修改秒、分、时、日、月、年&#xff1b; 3. 时间设置模式下&#xff0c;KEY3 增加数值&…

【Redis】如何利用 Redis 实现一个分布式锁?

&#x1f44f;大家好&#xff01;我是和风coding&#xff0c;希望我的文章能给你带来帮助&#xff01; &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;点击 我的主页 还可以看到和风的其他内容噢&#x…