抽象类和接口设计_如何设计类和接口

抽象类和接口设计

本文是我们名为“ 高级Java ”的学院课程的一部分。

本课程旨在帮助您最有效地使用Java。 它讨论了高级主题,包括对象创建,并发,序列化,反射等。 它将指导您完成Java掌握的旅程! 在这里查看 !

目录

1.简介 2.接口 3.标记接口 4.功能接口,默认方法和静态方法 5.抽象类 6.不可变的类 7.匿名类 8.可见度 9.继承 10.多重继承 11.继承与组成 12.封装 13.期末课程和方法 14.接下来是什么 15.下载源代码

1.简介

不管您使用哪种编程语言(这里Java也不例外),遵循良好的设计原则是编写干净,可理解,可测试的代码并提供长期有效且易于维护的解决方案的关键因素。 在本教程的这一部分中,我们将讨论Java语言提供的基本构建块,并介绍一些设计原则,以帮助您做出更好的设计决策。

更确切地说,我们将讨论与默认的方法 接口接口 (Java 8的新功能), 抽象final 类,不可变类,继承,组成和重温了一下可见性 (或可访问)的规则,我们有部分短暂触及本教程的第1部分, 如何创建和销毁对象

2.接口

在面向对象的编程中,接口的概念构成了契约驱动(或基于契约)开发的基础。 简而言之,接口定义方法的集合(契约),并且声称支持该特定接口的每个类都必须提供这些方法的实现:一个非常简单但功能强大的想法。

许多编程语言确实具有一种或另一种形式的接口,但是Java特别为此提供了语言支持。 让我们看一下Java中的简单接口定义。

package com.javacodegeeks.advanced.design;public interface SimpleInterface {void performAction();
}

在上面的代码片段中,我们命名为SimpleInterface的接口SimpleInterface声明了一个名为performAction方法。 接口相对于类的主要区别在于接口概述了联系方式(声明方法),但未提供其实现。

但是,Java中的接口可能比这更复杂:它们可以包括嵌套的接口,类,枚举,注释(该枚举和注释将在本教程的第5部分中详细介绍如何以及何时使用Enums和Annotations )和常量。 。 例如:

package com.javacodegeeks.advanced.design;public interface InterfaceWithDefinitions {String CONSTANT = "CONSTANT";enum InnerEnum {E1, E2;}class InnerClass {}interface InnerInterface {void performInnerAction();}void performAction();
}

在这个更复杂的示例中,存在一些关于嵌套构造和方法声明的接口隐式施加的约束,而Java编译器则强制执行这些约束。 首先,即使没有明确说明,该接口中的每个声明都是公共的 (并且只能是public ,有关可见性和可访问性规则的更多详细信息,请参阅Visibility部分)。 因此,以下方法声明是等效的:

public void performAction();
void performAction();

值得一提的是,接口中的每个方法都隐式声明为abstract ,甚至这些方法声明也是等效的:

public abstract void performAction();
public void performAction();
void performAction();

至于常量字段声明,除了是public ,它们是隐式staticfinal因此以下声明也等效:

String CONSTANT = "CONSTANT";
public static final String CONSTANT = "CONSTANT";

最后,除了public之外,嵌套类,接口或枚举还隐式声明为static 。 例如,这些类声明也等效:

class InnerClass {
}static class InnerClass {
}

您将选择哪种样式是个人喜好,但是了解这些简单的界面质量可以使您避免不必要的键入。

3.标记接口

标记接口是一种特殊的接口,没有定义方法或其他嵌套结构。 在本教程的第2部分中 ,我们已经看到了标记接口的一个示例,该接口使用所有对象共有的方法 ,即Cloneable接口。 这是在Java库中定义的方式:

public interface Cloneable {
}

标记接口本身并不是契约,而是某种有用的技术,用于“附加”或“绑定”班级的某些特定特征。 例如,对于Cloneable ,该类被标记为可用于克隆,但是应该或可以做的方式不是该接口的一部分。 标记器接口的另一个非常著名且广泛使用的示例是Serializable

public interface Serializable {
}

此接口将类标记为可用于序列化和反序列化,并且再次,它未指定可以或应该完成的方式。

标记器接口虽然不能满足作为合同的接口的主要目的,但它们在面向对象的设计中占有一席之地。

4.功能接口,默认方法和静态方法

随着Java 8的发布 ,接口获得了非常有趣的新功能:静态方法,默认方法和lambda(功能性接口)的自动转换。

在接口一节中,我们强调了以下事实:Java中的接口只能声明方法,而不能提供其实现。 使用默认方法不再是事实:接口可以使用default关键字标记方法并为其提供实现。 例如:

package com.javacodegeeks.advanced.design;public interface InterfaceWithDefaultMethods {void performAction();default void performDefaulAction() {// Implementation here}
}

作为实例级别,默认方法可以被每个接口实现者覆盖,但是从现在开始,接口可能还包括static方法,例如:

package com.javacodegeeks.advanced.design;public interface InterfaceWithDefaultMethods {static void createAction() {// Implementation here}
}

可能有人说在接口中提供实现会破坏基于契约的开发的全部目的,但是将这些功能引入Java语言有很多原因,无论它们多么有用或令人困惑,它们都可以为您提供帮助用。

功能接口是另外一个故事,并且事实证明它们是该语言的非常有用的附加组件。 基本上,功能接口是仅声明了一个抽象方法的接口。 Java标准库中的Runnable接口就是这个概念的一个很好的例子:

@FunctionalInterface
public interface Runnable {void run();
}

Java编译器以不同的方式对待功能接口,并且能够将lambda函数转换为有意义的功能接口实现。 让我们看一下以下函数定义:

public void runMe( final Runnable r ) {r.run();
}

要在Java 7及以下版本中调用此函数,应提供Runnable接口的实现(例如,使用Anonymous类 ),但是在Java 8中,只需使用lambda语法传递run()方法实现即可:

runMe( () -> System.out.println( "Run!" ) );

此外, @FunctionalInterface批注(批注将在本教程的第5部分“ 如何以及何时使用Enums和Annotations”中详细介绍 )提示编译器验证接口仅包含一种抽象方法,以便对接口中引入的任何更改未来将不会打破这一假设。

5.抽象类

Java语言支持的另一个有趣的概念是抽象类的概念。 抽象类在某种程度上类似于Java 7中的接口,并且与Java 8中具有默认方法的接口非常接近。与常规类相比,抽象类无法实例化,但是可以被子类化(请参阅继承一节以获取更多详细信息)。 更重要的是,抽象类可能包含抽象方法:没有实现的特殊方法,非常类似于接口。 例如:

package com.javacodegeeks.advanced.design;public abstract class SimpleAbstractClass {public void performAction() {// Implementation here}public abstract void performAnotherAction();
}

在此示例中,类SimpleAbstractClass被声明为abstract并且还具有一个abstract方法声明。 当实现细节的大部分甚至部分可以被许多子类共享时,抽象类非常有用。 但是,它们仍然敞开了大门,并允许通过抽象方法自定义每个子类的固有行为。

值得一提的是,与只能包含public声明的接口相反,抽象类可以使用可访问性规则的全部功能来控制抽象方法的可见性(有关更多详细信息,请参见“ 可见性和继承 ”部分)。

6.不可变的类

不可变性在当今的软件开发中变得越来越重要。 多核系统的兴起引起了很多与数据共享和并发相关的担忧(在第9部分并发最佳实践中 ,我们将详细讨论那些主题)。 但是,肯定会出现一件事:可变状态的更少(甚至不存在)导致更好的可伸缩性和关于系统的更简单的推理。

不幸的是,Java语言没有为类不变性提供强大的支持。 但是,结合使用多种技术,可以设计不可变的类。 首先,该类的所有字段都应该是final 。 这是一个好的开始,但不能单独保证不变性。

package com.javacodegeeks.advanced.design;import java.util.Collection;public class ImmutableClass {private final long id;private final String[] arrayOfStrings;private final Collection< String > collectionOfString;
}

其次,遵循正确的初始化:如果字段是对集合或数组的引用,请不要直接从构造函数参数中分配这些字段,而应创建副本。 这将确保集合或数组的状态不会从外部更改。

public ImmutableClass( final long id, final String[] arrayOfStrings,final Collection< String > collectionOfString) {this.id = id;this.arrayOfStrings = Arrays.copyOf( arrayOfStrings, arrayOfStrings.length );this.collectionOfString = new ArrayList<>( collectionOfString );
}

最后,提供适当的访问器(获取器)。 对于集合,不可变视图应使用Collections.unmodifiableXxx包装器公开。

public Collection<String> getCollectionOfString() {return Collections.unmodifiableCollection( collectionOfString );
}

对于数组,确保真正的不变性的唯一方法是提供副本,而不是返回对数组的引用。 从实际的角度来看,这可能是不可接受的,因为它在很大程度上取决于数组的大小,并可能给垃圾收集器带来很大压力。

public String[] getArrayOfStrings() {return Arrays.copyOf( arrayOfStrings, arrayOfStrings.length );
}

即使是这个很小的例子,也提供了一个很好的主意,即不变性还不是Java中的一等公民。 如果一个不可变的类具有引用另一个类实例的字段,那么事情就会变得非常复杂。 这些类也应该是不可变的,但是没有简单的方法可以强制执行。

有很多很棒的Java源代码分析器,例如FindBugsPMD ,它们可以通过检查代码并指出常见的Java编程缺陷来提供很多帮助。 这些工具是任何Java开发人员的好朋友。

7.匿名类

在Java 8之前的时代,匿名类是提供就地类定义和立即实例化的唯一方法。 匿名类的目的是减少样板,并提供简洁明了的方式将类表示为表达式。 让我们看一下在Java中产生新线程的典型老式方法:

package com.javacodegeeks.advanced.design;public class AnonymousClass {public static void main( String[] args ) {new Thread(// Example of creating anonymous class which implements// Runnable interfacenew Runnable() {@Overridepublic void run() {// Implementation here}}).start();}
}

在此示例中, Runnable接口的实现作为匿名类就地提供。 尽管匿名类存在一些限制,但是使用它们的基本缺点是Java强制将其作为语言使用的非常冗长的语法构造。 即使是最简单的不执行任何操作的匿名类,每次都至少需要编写5行代码。

new Runnable() {@Overridepublic void run() {}}

幸运的是,有了Java 8,lambda和功能接口,所有这些样板都将消失,最终使Java代码看起来非常简洁。

package com.javacodegeeks.advanced.design;public class AnonymousClass {public static void main( String[] args ) {new Thread( () -> { /* Implementation here */ } ).start();}
}

8.可见度

在教程的第1部分“ 如何设计类和接口”中 ,我们已经讨论了Java可见性和可访问性规则。 在这一部分中,我们将在子类化的背景下再次回到这个主题。

修饰符 子类 其他所有人
上市 无障碍 无障碍 无障碍
受保护的 无障碍 无障碍 无法访问
<无修饰符> 无障碍 无法访问 无法访问
私人的 无法访问 无法访问 无法访问

表格1

不同的可见性级别允许或不允许这些类查看其他类或接口(例如,如果它们位于不同的程序包中或彼此嵌套)或子类查看和访问其父级的方法,构造函数和字段。

在下一节Inheritance中 ,我们将看到它的作用。

9.继承

继承是面向对象编程的关键概念之一,它是建立类关系的基础。 与可见性和可访问性规则结合在一起,继承允许设计可扩展和可维护的类层次结构。

从概念上讲,Java中的继承是通过使用子类和extends关键字以及父类来实现的。 子类继承其父类的所有公共成员和受保护成员。 此外,如果子类都驻留在同一包中,则它们将继承父类的包私有成员。 话虽如此,无论您要设计什么,保持类公开或对其子类公开的最小方法集都是非常重要的。 例如,让我们看一下Parent类及其子类Child以演示不同的可见性级别及其效果:

package com.javacodegeeks.advanced.design;public class Parent {// Everyone can see itpublic static final String CONSTANT = "Constant";// No one can access itprivate String privateField;// Only subclasses can access itprotected String protectedField;// No one can see itprivate class PrivateClass {}// Only visible to subclassesprotected interface ProtectedInterface {}// Everyone can call itpublic void publicAction() {}// Only subclass can call itprotected void protectedAction() {}// No one can call itprivate void privateAction() {}// Only subclasses in the same package can call itvoid packageAction() {}
}
package com.javacodegeeks.advanced.design;// Resides in the same package as parent class
public class Child extends Parent implements Parent.ProtectedInterface {@Overrideprotected void protectedAction() {// Calls parent's method implementationsuper.protectedAction();}@Overridevoid packageAction() {// Do nothing, no call to parent's method implementation}public void childAction() {this.protectedField = "value";}
}

继承本身就是一个非常大的主题,其中包含许多特定于Java的细微细节。 但是,有一些易于遵循的规则可以对保持类层次结构简洁有很大帮助。 在Java中,每个子类都可以覆盖其父级的任何继承的方法,除非将其声明为final (请参阅Final类和方法部分 )。

但是,没有特殊的语法或关键字将方法标记为已重写,这可能会引起很多混乱。 这就是引入@Override批注的原因:每当您打算覆盖继承的方法时,请始终使用@Override批注进行指示。

Java开发人员在设计中经常面临的另一个难题是构建类层次结构(使用具体的或抽象的类)与接口实现。 强烈建议在可能的情况下,偏向类或抽象类的接口。 接口轻巧得多,易于测试(使用模拟)和维护,并且使实现更改的副作用最小化。 许多高级编程技术(例如在标准Java库中创建类代理)都严重依赖于接口。

10.多重继承

与C ++和其他一些语言相反,Java不支持多重继承:在Java中,每个类都只有一个直接父级(如我们在本教程第2部分中已经知道的, Object类位于层次结构的顶部, 使用通用方法)到所有对象 )。 但是,该类可以实现多个接口,因此,堆叠接口是在Java中实现(或模仿)多重继承的唯一方法。

package com.javacodegeeks.advanced.design;public class MultipleInterfaces implements Runnable, AutoCloseable {@Overridepublic void run() {// Some implementation here}@Overridepublic void close() throws Exception {// Some implementation here}
}

多个接口的实现实际上是非常强大的,但是重用实现的需求通常会导致深层次的类层次结构,从而克服Java中缺少多继承支持的一种方式。

public class A implements Runnable {@Overridepublic void run() {// Some implementation here}
}
// Class B wants to inherit the implementation of run() method from class A.
public class B extends A implements AutoCloseable {@Overridepublic void close() throws Exception {// Some implementation here}
}
// Class C wants to inherit the implementation of run() method from class A
// and the implementation of close() method from class B.
public class C extends B implements Readable {@Overridepublic int read(java.nio.CharBuffer cb) throws IOException {// Some implementation here}
}

依此类推...最近的Java 8版本通过引入默认方法在某种程度上解决了该问题。 由于使用默认方法,因此接口实际上已经开始不仅提供合同,而且还提供实现。 因此,实现这些接口的类也将自动继承这些实现的方法。 例如:

package com.javacodegeeks.advanced.design;public interface DefaultMethods extends Runnable, AutoCloseable {@Overridedefault void run() {// Some implementation here}@Overridedefault void close() throws Exception {// Some implementation here}
}// Class C inherits the implementation of run() and close() methods from the
// DefaultMethods interface.
public class C implements DefaultMethods, Readable {@Overridepublic int read(java.nio.CharBuffer cb) throws IOException {// Some implementation here}
}

请注意,多重继承是一种强大的功能,但同时又是一种危险的使用工具。 通常将众所周知的“死亡钻石”问题称为多重继承实现的基本缺陷,因此,敦促开发人员非常仔细地设计类层次结构。 不幸的是,具有默认方法的Java 8接口也正成为这些漏洞的受害者。

interface A {default void performAction() {}
}interface B extends A {@Overridedefault void performAction() {}
}interface C extends A {@Overridedefault void performAction() {}
}

例如,以下代码片段无法编译:

// E is not compilable unless it overrides performAction() as well
interface E extends B, C {
}

在这一点上,可以说Java作为一种语言总是试图逃避面向对象编程的极端情况,但是随着语言的发展,其中一些情况开始出现。

11.继承与组成

幸运的是,继承不是设计类的唯一方法。 许多开发人员认为比继承更好的另一种选择是组合。 这个想法很简单:这些类应该由其他类组成,而不是构建类层次结构。

让我们看一下这个例子:

public class Vehicle {private Engine engine;private Wheels[] wheels;// ...
}

Vehicle类由enginewheels (以及为简单起见而遗留的许多其他部件)组成。 但是,可以说Vehicle类也是一种引擎,因此可以使用继承进行设计。

public class Vehicle extends Engine {private Wheels[] wheels;// ...
}

哪个设计决定是正确的? 一般准则称为IS-AHAS-A原则。 IS-A是继承关系:子类还满足父类规范以及父类的此类IS-A变体。 因此, HAS-A是组成关系:该类拥有(或HAS-A )属于它的对象。 在大多数情况下, HAS-A原理比IS-A更好,其原因有两个:

  • 设计可以更改的方式更加灵活
  • 该模型更加稳定,因为更改不会通过类层次结构传播
  • 与继承紧密关联父级及其子类的继承相比,该类及其组合之间的关联松散
  • 关于类的推理更加简单,因为所有相关性都包含在其中

但是,继承有其自己的位置,以不同的方式解决实际的设计问题,因此不应忽略。 在设计面向对象的模型时,请牢记这两种选择。

12.封装

面向对象编程中的封装概念全是向外界隐藏实现细节(如状态,内部方法等)。 封装的好处是可维护性和易于更改。 内部细节类暴露的次数越少,开发人员对更改其内部实现的控制就越多,而不必担心破坏现有代码(如果您正在开发许多人使用的库或框架,这将是一个真正的问题)。

Java中的封装是使用可见性和可访问性规则实现的。 在Java中,最好不要使用getter和setter方法(如果未将字段声明为final )直接暴露字段,这是Java的最佳实践。 例如:

package com.javacodegeeks.advanced.design;public class Encapsulation {private final String email;private String address;public Encapsulation( final String email ) {this.email = email;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getEmail() {return email;}
}

此示例类似于Java语言中所谓的JavaBeans :通过遵循一组约定编写的常规Java类,其中一种仅允许使用getter和setter方法访问字段。

正如我们在“ 继承”部分中已强调的那样,请始终遵循封装原则,尝试使类公共协定保持最小。 无论什么都不应该是public ,而应该是private (或protected / package private ,取决于您要解决的问题)。 从长远来看,它将带来回报,使您可以自由开发设计而无需引入重大更改(或至少将更改减至最少)。

13.期末课程和方法

在Java中,有一种方法可以防止该类被其他任何类继承:应该将其声明为final

package com.javacodegeeks.advanced.design;public final class FinalClass {
}

方法声明中使用相同的final关键字可防止所讨论的方法在子类中被覆盖。

package com.javacodegeeks.advanced.design;public class FinalMethod {public final void performAction() {}
}

没有通用的规则来决定类或方法是否应该是final 。 最终的类和方法限制了可扩展性,并且很难预先考虑该类是否应该被子类化,或者方法是否应该被覆盖。 这对于库开发人员尤其重要,因为这样的设计决策可能会大大限制库的适用性。

Java标准库提供了一些final类的示例,其中最著名的是String类。 在早期阶段,已决定主动阻止任何开发人员尝试自己的,“更好”的字符串实现。

14.接下来是什么

在本教程的这一部分中,我们研究了Java中的面向对象设计概念。 我们还简要介绍了基于合同的开发,介绍了一些功能概念,并了解了该语言如何随着时间演变。 在本教程的下一部分中,我们将讨论泛型以及泛型如何改变我们处理类型安全编程的方式。

15.下载源代码

这是关于如何设计类和接口的课程。

  • 您可以在此处下载源代码: advanced-java-part-3

翻译自: https://www.javacodegeeks.com/2015/09/how-to-design-classes-and-interfaces.html

抽象类和接口设计

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

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

相关文章

详解C++异常

点击蓝字关注我们1、异常概念异常是一种处理错误的方式&#xff0c;当一个函数发现自己无法处理的错误时就可以抛出异常&#xff0c;让函数的直接或间接的调用者处理这个错误。throw: 当问题出现时&#xff0c;程序会抛出一个异常。这是通过使用 throw 关键字来完成的。catch: …

Python3 反转一个单链表

Python3 反转一个单链表反转一个单链表。示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL解题&#xff1a; # Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val x # …

python怎么改字体_python,tkinter_Tkinter Label 如何改变Label中的文字样式,例如给文字加删除线,python,tkinter - phpStudy...

Tkinter Label 如何改变Label中的文字样式&#xff0c;例如给文字加删除线 如题。未查到Tkinter下&#xff0c;促发条件后&#xff0c;是否能修改label中文字的样式 class Pomodoro_app(Tk): def add_task(self): global time time StringVar() time.set("Start") t…

使用所有对象共有的方法

本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题&#xff0c;包括对象创建&#xff0c;并发&#xff0c;序列化&#xff0c;反射等。 它将指导您完成Java掌握的旅程&#xff01; 在这里查看 &#xff01; 目录 1.简…

C语言基础知识:指针与数组的区别是什么

点击蓝字关注我们在C语言教程中我们使用通过数组名通过偏移和指针偏移都可以遍历数组&#xff0c;那么指针和数组到底有什么区别&#xff1f;&#xff1f;由于数组中的数据在内存中都是连续存放的&#xff0c;数组名默认就是数组的首地址&#xff0c;也是一个特殊的指针&#x…

Python3 三步爬楼梯问题

Python3 三步爬楼梯问题原题地址 https://leetcode-cn.com/problems/three-steps-problem-lcci/ 题目&#xff1a; 三步问题。有个小孩正在上楼梯&#xff0c;楼梯有n阶台阶&#xff0c;小孩一次可以上1阶、2阶或3阶。实现一种方法&#xff0c;计算小孩有多少种上楼梯的方式。…

python去重复功能_消除Python列表重复的几种方法,python,去,一些

做Python123平台上的列表去重题&#xff0c;复述题目&#xff1a; 去除列表中的重复元素&#xff0c;考虑以下几种情况&#xff1a; l [1, 1, 2, 3] l [[1], [1], [2], [3]] l [3, 2, 1, 1] 原文链接&#xff1a; 14025 总结一下网上的方法和我自己想的方法&#xff1a; 不考…

java java se_Java 8 SE可选,严格的方法

java java se大约两周前&#xff0c;Stephen Colebourne提出了使用Optional的实用方法 。 如果您阅读了它&#xff0c;您可能会从我以前的建议中猜到我不同意。 总览 我必须以免责声明开头&#xff0c;然后我将直接解释为什么我认为他的方法不那么理想。 所有不归因于他人的报…

std::thread 还有哪些使用“姿势”?

点击蓝字关注我们C11 线程创建每一个 C11 程序都包含一个主线程即 main() 函数。在 C11 中我们可以通过创建 std::thread 对象来创建新的线程。每个 std::thread 对象都可以与一个线程相关联。需要引用的头文件&#xff1a;1#include <thread>std::thread 的构造函数中接…

Python3反转字符串

Python3反转字符串原题 https://leetcode-cn.com/problems/reverse-string-ii/题目&#xff1a; 给定一个字符串和一个整数 k&#xff0c;你需要对从字符串开头算起的每个 2k 个字符的前k个字符进行反转。如果剩余少于 k 个字符&#xff0c;则将剩余的所有全部反转。如果有小于…

用python画皇冠_手把手教你用 Python 绘制酷炫的桑基图!

原标题&#xff1a;手把手教你用 Python 绘制酷炫的桑基图&#xff01;作者 | 周志鹏 责编 | 郭 芮 最近&#xff0c;不止一次收到小伙伴的截图追问&#xff1a;“这个图叫什么&#xff1f;&#xff1f;&#xff1f;” “这个图真好看&#xff01;&#xff01;&#xff01;怎么…

ejb能调用另一个ejb吗_异步EJB只是一个Gi头吗?

ejb能调用另一个ejb吗在之前的文章&#xff08; 此处和此处 &#xff09;中&#xff0c;我展示了当服务器负载沉重时&#xff0c;创建非阻塞异步应用程序可以提高性能。 EJB 3.1引入了Asynchronous批注&#xff0c;用于指定方法将在将来的某个时间返回其结果。 Javadocs声明必须…

为啥电脑从C盘开始?A、B盘去哪了?

点击蓝字关注我们前些天硬盘坏了&#xff0c;幸好不是系统盘&#xff0c;不然那些软件安装配置会把我折腾坏&#xff0c;或许这也是在暗示我该换电脑了。重要的数据部分没有遭到损坏&#xff0c;数据是无价的&#xff0c;还是要勤备份。于是换上了一张新的硬盘&#xff0c;当时…

Python3求最后一个单词长度

Python3求最后一个单词长度原题&#xff1a;https://leetcode-cn.com/problems/length-of-last-word/ 给定一个仅包含大小写字母和空格 ’ ’ 的字符串 s&#xff0c;返回其最后一个单词的长度。如果字符串从左向右滚动显示&#xff0c;那么最后一个单词就是最后出现的单词。 …

java 锁_Java之线程并发的各种锁、锁、锁

因为两周没更新了...也不是懒&#xff0c;这两周确实有些忙&#xff0c;赶项目进度赶的不亦乐乎...终于赶在工期前&#xff0c;可以进入内测了&#xff0c;我也有了些时间&#xff0c;可以更新啦...线程并发锁是很常见的问题&#xff0c;而且在Java中锁的类型、概念、使用场景等…

threadsafe_Agrona的Threadsafe堆缓冲区

threadsafe这篇博客文章通过说明我们如何轻松访问线程内存来进行线程安全操作&#xff0c;继续了我在Agrona库上进行的系列文章 。 在继续讨论这是一个相当高级的主题之前&#xff0c;我可能应该警告一下&#xff0c;并且我不尝试解释诸如内存屏障之类的概念&#xff0c;仅概述…

C语言编程中错误异常该如何统一处理?1.8万字总结

点击蓝字关注我们本文主要总结嵌入式系统C语言编程中&#xff0c;主要的错误处理方式。一、错误概念1.1 错误分类从严重性而言&#xff0c;程序错误可分为致命性和非致命性两类。对于致命性错误&#xff0c;无法执行恢复动作&#xff0c;最多只能在用户屏幕上打印出错消息或将其…

Python3实现最小栈

Python3实现最小栈原题 https://leetcode-cn.com/problems/min-stack/ 设计一个支持 push&#xff0c;pop&#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 push(x) – 将元素 x 推入栈中。 pop() – 删除栈顶的元素。 top() – 获取栈顶元素。 getMin…

pycharm remote 远程项目 同步 本地_利器:PyCharm本地连接服务器搭建深度学习实验环境的三重境界...

作为实验室社畜&#xff0c;常需要在本地使用Pycharm写代码&#xff0c;然后将代码同步到服务器上&#xff0c;使用远程登录服务器并运行代码做实验。这其中有很多事情如果没有好的工具&#xff0c;做起来会非常麻烦。比如如何快速同步本地与服务器的代码&#xff1f;如何优雅地…

防御性编程技巧

点击蓝字关注我们在防御性编程的大框架之下&#xff0c;有许多常识性的规则。人们在想到防御性编程的时候&#xff0c;通常都会想到“断言”&#xff0c;这没有错。我们将在后面对此进行讨论。但是&#xff0c;还是有一些简单的编程习惯可以极大地提高代码的安全性。尽管看上去…