Effective第三版 中英 | 第2章 创建和销毁对象 | 当面临多个参数的构造器时考虑使用构建器

news2024/11/24 20:38:30

文章目录

  • Effective第三版
    • 前言
    • 第2章 创建和销毁对象
      • 当面临多个参数的构造器时考虑使用构建器

Effective第三版

前言

大家好,这里是 Rocky 编程日记 ,喜欢后端架构及中间件源码,目前正在阅读 effective-java 书籍。同时也把自己学习该书时的笔记,代码分享出来,供大家学习交流,如若笔记中有不对的地方,那一定是当时我的理解还不够,希望你能及时提出。如果对于该笔记存在很多疑惑,可以先去翻阅《Java核心技术》也欢迎和我交流讨论,最后也感谢您的阅读,点赞,关注,收藏~

前人述备矣,我只是知识的搬运工,effective 书籍源码均在开源项目 java-diary 中的 code-effective-third 模块中

源代码仓库地址: https://gitee.com/Rocky-BCRJ/java-diary.git

第2章 创建和销毁对象

当面临多个参数的构造器时考虑使用构建器

在这里插入图片描述

  Static factories and constructors share a limitation: they do not scale well to large numbers of optional parameters. Consider the case of a class representing the Nutrition Facts label that appears on packaged foods. These labels have a few required fields—serving size, servings per container, and calories per serving—and more than twenty optional fields—total fat, saturated fat, trans fat, cholesterol, sodium, and so on. Most products have nonzero values for only a few of these optional fields.

  静态工厂和构造器有个共同的局限性:他们都不能很好地扩展到大量的可选参数。考虑用一个类表示包装食品外面显示的营养成分标签。这些标签中有几个域是必需的:每份的含量、每罐的含量以及每份的卡路里,还有超过 20 个可选域:总脂肪、饱和脂肪量、转化脂肪、胆固醇、钠等等。大多数产品在某几个可选域中都会有非零的值。

   What sort of constructors or static factories should you write for such a class? Traditionally, programmers have used the telescoping constructor pattern, in which you provide a constructor with only the required parameters, another with a single optional parameter, a third with two optional parameters, and so on, culminating in a constructor with all the optional parameters. Here’s how it looks in practice. For brevity’s sake, only four optional fields are shown:

  对于这样的类,应该采用哪种构造器或者静态方法来编写呢?程序猿一向习惯采用重叠构造器(telescoping constructor)模式,在这种模式下,提供一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个可选参数,以此类推,最后一个构造器包含所有可选参数。下面有个示例,为了简单起见,它显示四个可选域:

// Telescoping constructor pattern - does not scale well!
public class NutritionFacts {
    private final int servingSize; // (mL) required
    private final int servings; // (per container) required
    private final int calories; // (per serving) optional
    private final int fat; // (g/serving) optional
    private final int sodium; // (mg/serving) optional
    private final int carbohydrate; // (g/serving) optional

    public NutritionFacts(int servingSize, int servings) {
        this(servingSize, servings, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories) {
        this(servingSize, servings, calories, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories, int fat) {
        this(servingSize, servings, calories, fat, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) {
        this(servingSize, servings, calories, fat, sodium, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate) {
        this.servingSize = servingSize;
        this.servings = servings;
        this.calories = calories;
        this.fat = fat;
        this.sodium = sodium;
        this.carbohydrate = carbohydrate;
    }
}

  When you want to create an instance, you use the constructor with the shortest parameter list containing all the parameters you want to set:

  当你想要创建实例的时候,就利用参数列表最短的构造器,但该列表中包含了要设置的所有参数:
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);

  Typically this constructor invocation will require many parameters that you don’t want to set, but you’re forced to pass a value for them anyway. In this case, we passed a value of 0 for fat. With “only” six parameters this may not seem so bad, but it quickly gets out of hand as the number of parameters increases.

  这个构造器调用通常需要许多你本不想设置的参数,但还是不得不为它们传递值。在这个例子中,我们给 fat 传递了一个值为 0。如果”仅仅”是这 6 个参数,看起来还不算太糟,问题是随着参数数目的增加,它很快就失去了控制。

  In short, the telescoping constructor pattern works, but it is hard to write client code when there are many parameters, and harder still to read it. The reader is left wondering what all those values mean and must carefully count parameters to find out. Long sequences of identically typed parameters can cause subtle bugs. If the client accidentally reverses two such parameters, the compiler won’t complain, but the program will misbehave at runtime (Item 51).

  总的来说,使用重叠构造器模式是可行的,但是当有很多参数的时候就很难编写客户端代码,也很难去阅读它们。如果读者想要知道这些值代表什么意思,就必须仔细地数着这些参数来探个究竟。一长串类型相同的参数会导致一些微妙的错误,如果客户端不小心颠倒了其中两个参数的顺序,编译器也不会报错,但是程序在运行的时候就会出现错误的行为。

  A second alternative when you’re faced with many optional parameters in a constructor is the JavaBeans pattern, in which you call a parameterless constructor to create the object and then call setter methods to set each required parameter and each optional parameter of interest:

  遇到许多构造器参数的时候,还有第二种代替方法,即 JavaBean 模式,在这种模式下,调用一个无参构造器来创建对象,然后调用setter方法来设置每个必要的参数,以及每个相关的可选参数:

// JavaBeans Pattern - allows inconsistency, mandates mutability
public class NutritionFacts {
    // Parameters initialized to default values (if any)
    private int servingSize = -1; // Required; no default value
    private int servings = -1; // Required; no default value
    private int calories = 0;
    private int fat = 0;
    private int sodium = 0;
    private int carbohydrate = 0;
    public NutritionFacts() { }
    // Setters
    public void setServingSize(int val) { servingSize = val; }
    public void setServings(int val) { servings = val; }
    public void setCalories(int val) { calories = val; }
    public void setFat(int val) { fat = val; }
    public void setSodium(int val) { sodium = val; }
    public void setCarbohydrate(int val) { carbohydrate = val; }
}

  This pattern has none of the disadvantages of the telescoping constructor pattern. It is easy, if a bit wordy, to create instances, and easy to read the resulting code:

  这种模式弥补了重叠构造器模式的不足。说得明白一点,就是创建实例很容易,这样产生的代码读起来也很容易。

NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);

   Unfortunately, the JavaBeans pattern has serious disadvantages of its own. Because construction is split across multiple calls, a JavaBean may be in an inconsistent state partway through its construction.The class does not have the option of enforcing consistency merely by checking the validity of the constructor parameters. Attempting to use an object when it’s in an inconsistent state may cause failures that are far removed from the code containing the bug and hence difficult to debug. A related disadvantage is that the JavaBeans pattern precludes the possibility of making a class immutable(Item 17) and requires added effort on the part of the programmer to ensure thread safety.

  遗憾的是,这种 JavaBean 模式自身有很严重的缺点。因为构造过程被分到了几个调用中,在构造的过程中 JavaBean 可能处于不一致的状态。类无法通过检验构造器参数的有效性来保证一致性。试图使用处于不一致状态的对象,将会导致失败,这种失败与包含错误的代码大相径庭,因此它调试起来十分困难。与此相关的另一点不足在于,JavaBean 模式阻止了把类做成了不可变的可能(第 17 项),这就需要程序猿付出额外的努力来保证它的线程安全。

  It is possible to reduce these disadvantages by manually “freezing” the object when its construction is complete and not allowing it to be used until frozen, but this variant is unwieldy and rarely used in practice. Moreover, it can cause errors at runtime because the compiler cannot ensure that the programmer calls the freeze method on an object before using it.

  在构造器完成构造对象之前进行加锁,完成构造之后进行解锁,这就能弥补以上的不足之处,但是这种方式十分笨拙,在实践中很少使用。此外,它甚至会在运行时出现错误,因为编译器无法确保程序猿会在使用构造器之前进行加锁操作。

  Luckily, there is a third alternative that combines the safety of the telescoping constructor pattern with the readability of the JavaBeans pattern. It is a form of the _Builder _pattern [Gamma95].

  幸运的是,还有第三种替代方法,结合了重叠构造器的安全性和 JavaBean 模式的可读性。这就是 Builder 模式 [Gamma95] 的一种形式。

  Instead of making the desired object directly, the client calls a constructor (or static factory) with all of the required parameters and gets a builder object. Then the client calls setter-like methods on the builder object to set each optional parameter of interest. Finally, the client calls a parameterless build method to generate the object, which is typically immutable. The builder is typically a static member class (Item 24) of the class it builds. Here’s how it looks in practice:

  不直接生成想要的对象,而是让客户端调用一个带有所有必需参数的构造器方法(或者静态工厂方法)去获得一个 builder 对象,然后客户端在builder对象上调用类似于 setter 的方法来设置每个相关的可选参数。最后,客户端调用无参的build方法来生成不可变的对象。这个builder通常是它构建的类的静态成员类(第 24 项)。下面就是它的示例:

// Builder Pattern
public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder {
        // Required parameters
        private final int servingSize;
        private final int servings;
        // Optional parameters - initialized to default values
        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder calories(int val) {
            calories = val;
            return this;
        }

        public Builder fat(int val) {
            fat = val;
            return this;
        }

        public Builder sodium(int val) {
            sodium = val;
            return this;
        }

        public Builder carbohydrate(int val) {
            carbohydrate = val;
            return this;
        }

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }

    private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}

  The NutritionFacts class is immutable, and all parameter default values are in one place. The builder’s setter methods return the

  builder itself so that invocations can be chained, resulting in a fluent API. Here’s how the client code looks:

  NutritionFacts是不可变的,所有默认参数值都单独放在一个地方。buildersetter方法返回的是builder本身,以便可以把调用连接起来。下面是客户端代码:

NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();

  This client code is easy to write and, more importantly, easy to read. The Builder pattern simulates named optional parameters as found in Python and Scala.

  这样的客户端代码是很容易编写的,更重要的是,阅读起来很容易。Builder 模式模仿了 Python 和 Scala 中的命名可选参数。

   Validity checks were omitted for brevity. To detect invalid parameters as soon as possible, check parameter validity in the builder’s constructor and methods. Check invariants involving multiple parameters in the constructor invoked by the build method. To ensure these invariants against attack, do the checks on object fields after copying parameters from the builder (Item 50). If a check fails, throw an IllegalArgumentException (Item72) whose detail message indicates which parameters are invalid (Item 75).

  为简洁起见,省略了有效性检查。要尽快检测无效参数,请在构建器的构造函数和方法中检查参数有效性。检查构建方法调用的构造函数中涉及多个参数的不变量。要确保这些不变量不受攻击,请在从构建器复制参数后对对象字段执行检查(第 50 项)。如果检查失败,则抛出IllegalArgumentException(第 72 项),其详细消息指示哪些参数无效(第 75 项)。

  The Builder pattern is well suited to class hierarchies. Use a parallel hierarchy of builders, each nested in the corresponding class. Abstract classes have abstract builders; concrete classes have concrete builders. For example, consider an abstract class at the root of a hierarchy representing various kinds of pizza:

  Builder 模式非常适合类层次结构。使用并行的构建器层次结构,每个构建器都嵌套在相应的类中。抽象类有抽象构建器; 具体课程有混凝土建造者。例如,在代表各种批萨的层次结构的根部考虑使用一个抽象类:

// Builder pattern for class hierarchies
public abstract class Pizza {
    public enum Topping { HAM, MUSHROOM, ONION, PEPPER, SAUSAGE }
    final Set<Topping> toppings;
    abstract static class Builder<T extends Builder<T>> {
        EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);

        public T addTopping(Topping topping) {
            toppings.add(Objects.requireNonNull(topping));
            return self();
        }

        abstract Pizza build();
        // Subclasses must override this method to return "this"
        protected abstract T self();
    }

    Pizza(Builder<?> builder) {
        toppings = builder.toppings.clone(); // See Item 50
    }
}

  Note that Pizza.Builder is a generic type with a recursive type parameter (Item 30). This, along with the abstract self method, allows method chaining to work properly in subclasses, without the need for casts. This work around for the fact that Java lacks a self type is known as the simulated self-type idiom.

  注意下这个 Pizza 类,Builder 是具有递归类型参数的通用类型(第 30 项)。这与抽象方法 self 一起允许方法链在子类中正常工作,而不需要强制转换。Java 缺乏自我类型这一事实的解决方法被称为模拟自我类型习语。

   Here are two concrete subclasses of Pizza, one of which represents a standard New-York-style pizza, the other a calzone. The former has a required size parameter, while the latter lets you specify whether sauce should be inside or out:

  这是Pizza的两个具体子类,其中一个代表标准的纽约式披萨,另一个代表calzone。 前者具有所需的大小参数,而后者允许你指定酱汁应该在内部还是外部:

public class NyPizza extends Pizza {
    public enum Size { SMALL, MEDIUM, LARGE }
    private final Size size;
    public static class Builder extends Pizza.Builder<Builder> {
        private final Size size;

        public Builder(Size size) {
            this.size = Objects.requireNonNull(size);
        }

        @Override public NyPizza build() {
            return new NyPizza(this);
        }

        @Override protected Builder self() {
            return this;
        }
    }

    private NyPizza(Builder builder) {
        super(builder);
        size = builder.size;
    }
}

public class Calzone extends Pizza {
    private final boolean sauceInside;

    public static class Builder extends Pizza.Builder<Builder> {
        private boolean sauceInside = false; // Default
        public Builder sauceInside() {
            sauceInside = true;
            return this;
        }

        @Override public Calzone build() {
            return new Calzone(this);
        }

        @Override protected Builder self() {
            return this;
        }
    }

    private Calzone(Builder builder) {
        super(builder);
        sauceInside = builder.sauceInside;
    }
}

  Note that the build method in each subclass’s builder is declared to return the correct subclass: the build method of NyPizza.Builder returns NyPizza, while the one in Calzone.Builder returns Calzone. This technique, where in a subclass method is declared to return a subtype of the return type declared in the super-class, is known as covariant return typing. It allows clients to use these builders without the need for casting. The client code for these “hierarchical builders” is essentially identical to the code for the simple NutritionFacts builder. The example client code shown next assumes static imports on enum constants for brevity:

  请注意,每个子类的构建器中的构建方法被声明为返回正确的子类:NyPizza.Builder的构建方法返回NyPizza,而Calzone.Builder中的构建方法返回Calzone。这种技术,其中子类方法声明的返回类型是在超类中声明的返回类型的子类型,称为协变返回类型,它允许客户使用这些构建器而无需进行创建。

  这些“分层构建器”的客户端代码基本上与简单的NutritionFacts构建器的代码相同。为简洁起见,下面显示的示例客户端代码假定枚举常量上的静态导入:

NyPizza pizza = new NyPizza.Builder(SMALL).addTopping(SAUSAGE).addTopping(ONION).build();
Calzone calzone = new Calzone.Builder().addTopping(HAM).sauceInside().build();

   A minor advantage of builders over constructors is that builders can have multiple varargs parameters because each parameter is specified in its own method. Alternatively, builders can aggregate the parameters passed into multiple calls to a method into a single field, as demonstrated in the addTopping method earlier.

  构建器相对于构造函数的一个小优点是构建器可以有多个可变参数,因为每个参数都是在自己的方法中指定的。除此之外,构建器可以将传递给一个方法的多个参数通过多次调用方法的方式聚合到一个字段中,就如之前addTopping方法中所演示的那样。

  The Builder pattern is quite flexible. A single builder can be used repeatedly to build multiple objects. The parameters of the builder can be tweaked between invocations of the build method to vary the objects that are created. A builder can fill in some fields automatically upon object creation, such as a serial number that increases each time an object is created.

  Builder 模式非常灵活。可以重复使用单个构建器来构建多个对象。可以在构建方法的调用之间调整构建器的参数,以改变创建的对象。构建器可以在创建对象时自动填充某些字段,例如每次创建对象时增加的序列号。

  The Builder pattern has disadvantages as well. In order to create an object, you must first create its builder. While the cost of creating this builder is unlikely to be noticeable in practice, it could be a problem in performance-critical situations. Also, the Builder pattern is more verbose than the telescoping constructor pattern, so it should be used only if there are enough parameters to make it worthwhile, say four or more. But keep in mind that you may want to add more parameters in the future. But if you start out with constructors or static factories and switch to a builder when the class evolves to the point where the number of parameters gets out of hand, the obsolete constructors or static factories will stick out like a sore thumb. Therefore, it’s often better to start with a builder in the first place.

  Builder 模式也有缺点。要创建对象,必须先创建其构建器。虽然在实践中创建此构建器的成本可能不太明显,但在性能关键的情况下可能会出现问题。此外,Builder 模式比重叠构造函数的模式更冗长,因此只有在有足够的参数(例如四个或更多)时才值得去使用它。但请记住,你可能希望在将来添加更多的参数。但是如果你从构造函数或静态工厂开始并在类进化到参数数量失控时才切换到构建器,那些过时的构造器和静态工厂就会显得非常不协调。因此,最好一开始就考虑使用构造器。

   In summary, the Builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters, especially if many of the parameters are optional or of identical type. Client code is much easier to read and write with builders than with telescoping constructors, and builders are much safer than JavaBeans.

  简而言之,如果类的构造器或者静态工厂方法中具有多个参数,设计这种类时,Builder 模式就是种不错的选择,特别是当大多数参数都是可选的时候。与使用传统的重叠构造器模式相比,使用 Builder 模式的客户端代码更易于阅读和编写,构建器也比 JavaBean 更加安全。

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

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

相关文章

【KKT】∇f(x)+λ∇g(x)=0中λ的讨论

Karush-Kuhn-Tucker (KKT)条件 〇、问题背景 在阅读 Karush-Kuhn-Tucker (KKT)条件 时&#xff0c;不太能理解 ∇ f \nabla f ∇f 的方向&#xff0c;以及 ∇ g \nabla g ∇g 的方向&#xff1a; 为什么 ∇ f \nabla f ∇f 是指向可行域内部&#xff0c; ∇ g \nabla g ∇g…

Java多线程方面知识

目录 1.程序、进程、线程 2.进程与线程的内存解析 3.并发与并行 4.Java程序的线程 5.多线程的创建&#xff1a;方式一&#xff1a;继承于Thread类 6.start方法的作用 7.使用start()时要注意的问题 8.Thread类中的一些方法 9.线程的优先级 10.多线程的创建&#xff1a…

【JAVA】清缓存(打断点删除 / 新增表或字段无效)

一. 打断点无效 情景 新写了一个获取列表数据接口&#xff0c;前端调用的&#xff0c;获取到的数据为空数组。在数据库中查看&#xff0c;是有数据的&#xff0c;但是调用接口返回数据为空。接下来就打断点啦&#xff0c;发现无效&#xff01;表现如下 没有可执行的…

【Bio】牙的分类

文章目录 IncisorCentral IncisorLateral Incisor Canine / CuspidPremolarFirst PremolarSecond Premolar MolarFirst MolarSecond MolarThird Molar / Wisdom Tooth Ref Incisor Central Incisor Lateral Incisor Canine / Cuspid Premolar First Premolar Second Prem…

第六十二天学习记录:C语言进阶:C语言预处理2

带副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候&#xff0c;如果参数带有副作用&#xff0c;那么你在使用这个宏的时候就可能出现危险&#xff0c;导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。例如&#xff1a; x1;//不带副作用 x;//带有副作…

安全认证:

1. 认证概述 为什么要有认证&#xff1f; 防止非法路由器接入企业内网的ospf路由器&#xff0c;保护内网安全 2. 认证方式 认证方式分为接口认证和区域认证&#xff0c;接口认证和区域认证没有本质的区别&#xff0c;接口认证是当区域内链路过多的情况下&#xff0c;接口认证…

Java网络开发(Tomcat)—— Servlet学习 Web相关背景知识 JavaWeb项目初步

本文目录 引出一、软件架构BS和CS二、实现Web服务的条件和步骤三、Tomcat搭建Web项目初步1.pom.xml文件配置2.web.xml文件更新3.Tomcat运行环境配置4.项目文件层级解析 四、JavaWeb项目文件分类&#xff08;1&#xff09;静态文件—存放位置&#xff08;2&#xff09;动态文件-…

【用人话讲算法】leetcode无重复字符的最长子串

【用人话讲算法】leetcode无重复字符的最长子串 文章目录 【用人话讲算法】leetcode无重复字符的最长子串题目简单思路&#xff08;暴力&#xff09;优化思考怎么写代码&#xff1f;怎么到下一个&#xff1f;whilefor 思路总结while和for循环总结 题目 题目的意思是说&#xff…

一台电脑上安装多个版本的python,运行互不干扰,显示位置的一些命令,

首先需要知道一些命令&#xff1a; pip show 包名 可以使用pip show 包名的方式显示位置 pip list pip方式显示的是当前环境下的库 os.environ.get&#xff08;&#xff09; python中os模块获取环境变量的一个方法 Python os.environ.get&#xff08;&#xff09;的用法 …

使用Git LFS上传Unity大型资源文件

在使用Unity制作结课作业时&#xff0c;使用到git工具进行版本控制与多人协作。在提交项目至远程仓库的过程中&#xff0c;git bash提示了以下报错&#xff1a; remote: warning: File Assets/Models/Z_India_5.29.fbx is 57.31 MB; this is larger than GitHubs recommended m…

利用环回口建立IBGP邻居

利用环回口建立IBGP邻居 BGP的稳定性 IBGP : 1.一般使用环回口建立IBGP邻居 2.指定建立IBGP邻居的源地址为lookback地址 EBGP : 1.一般使用直连接口建立EBGP邻居关系 2.如果想使用环回口建立EBGP邻居&#xff0c;需要将TTL值修改为大于1&#xff0c;默认TTL1 修改命令…

在win10/11的右键菜单添加电源选项

前言&#xff1a; 今天&#xff0c;博主从网上找到了在右键菜单中添加电源选项的方法&#xff0c;觉得挺实用的所以来教大家 方法&#xff1a; 下载&#xff08;懒人专用&#xff0c;直接打开文件即可&#xff09;&#xff1a; csdn中下载&#xff08;启用和关闭文件都有&a…

基于 Docker_redis6.0.8 实现 Redis 集群扩缩容

文章目录 单机部署数据分区方案集群部署集群容错测试集群扩容测试集群缩容测试 LXL&#xff1a;这玩意太枯燥&#xff0c;看完需要耐心 ~~~ 单机部署 通过 dockerhub 查找 redis 镜像&#xff0c;选择 6.0.8 版本。创建挂载目录&#xff0c;并赋予权限。 mkdir -p /var/docker…

MicroPython应用基础-使用Thonny IDE

MicroPython应用基础-使用Thonny IDE 文章目录 MicroPython应用基础-使用Thonny IDE引言Thonny简介使用Thonny连接到MicroPython开发板使用Thonny的REPL窗口运行Python语句在Thonny中保存Python程序文件至MicroPython开发板中运行使用Thonny的注意要点 引言 在很长一段时间内&…

[论文分享]TimeMAE:解耦掩码自编码器时间序列的自监督表示

论文题目&#xff1a;TimeMAE: Self-Supervised Representations of Time Series with Decoupled Masked Autoencoders 论文地址&#xff1a;https://arxiv.org/abs/2303.00320 代码地址&#xff1a;https://github.com/Mingyue-Cheng/TimeMAE 1 摘要 利用自监督预训练增强基于…

Flume和Kafka的组合使用

一.安装Kafka 1.1下载安装包 通过百度网盘分享的文件&#xff1a;复制链接打开「百度网盘APP 即可获取」 链接&#xff1a;https://pan.baidu.com/s/1vC6Di3Pml6k1KMbnK0OE1Q?pwdhuan 提取码&#xff1a;huan 也可以访问官网&#xff0c;下载kafka2.4.0的安装文件 1.2解…

Hadoop3.1.3安装(单机、伪分布)

系列文章目录 Ubuntu常见基本问题 Hadoop3.1.3安装&#xff08;单机、伪分布&#xff09; Hadoop集群搭建 文章目录 系列文章目录一、环境1、创建hadoop用户 二、更新apt三、安装SSH、配置SSH无密码登陆四、安装Java环境五、安装 Hadoop3.1.3六、Hadoop单机配置(非分布式)七、…

chatgpt赋能python:Python为什么被吹得这么神?

Python为什么被吹得这么神&#xff1f; Python是一个开源、跨平台的高级编程语言&#xff0c;由Guido van Rossum于1989年在荷兰创造。Python在近几年因其方便易用、高效稳定和丰富的生态体系而备受欢迎。Python被广泛应用于数据科学、人工智能、机器学习、Web开发、自动化测试…

启动虚拟机并安装Linux系统

我们刚刚新建的虚拟机相当于一个裸机&#xff0c;还没有安装操作系统在里面&#xff0c;下面我们来看一下怎么进行Linux系统的安装。 在VMware Workstation工具的主界面选择虚拟机Spark01&#xff0c;单击鼠标右键在弹出的菜单中选择“设置”打开“虚拟机设置”对话框。如下图…

程序设计综合实习(C语言):学生成绩文件管理

一、目的 1&#xff0e;掌握文件指针的概念和运用 2&#xff0e;掌握文件的相关操作&#xff1a;打开、读、写、关闭 3&#xff0e;掌握文件的定位操作 二、实习环境 Visual Stdio 2022 三、实习内容与步骤 1&#xff0e;定义一个结构体数组&#xff0c;存放10个学生的学号&a…