- 博客(392)
- 收藏
- 关注
原创 Java网络编程之Cookie 和 Session
Cookie和Session是解决HTTP无状态问题的重要手段,各有优劣,开发者应根据具体需求合理选择使用。
2024-08-10 16:32:43 425
原创 《Java核心技术卷Ⅰ》读书笔记(第一——五章)
JIT和AOT编译器各有优缺点,具体选择哪种方式需要根据具体应用场景和需求进行权衡。现代Java虚拟机(如HotSpot)通常结合两者的优点,在不同阶段和场景下灵活使用这两种编译方式,以达到最佳性能。JDK是开发Java应用程序的工具包,包含JRE和开发工具。JRE是运行Java应用程序的环境,包含JVM和核心类库。JVM是执行Java字节码的虚拟机,实现了Java的跨平台特性。了解这些基本概念有助于更好地掌握Java开发和运行环境,合理选择和配置开发工具,提高开发效率。
2024-08-10 16:22:35 654
原创 Chapter-6-Item-41-使用标记接口定义类型
标记接口是一种不包含任何方法声明的接口,它只是指定(或「标记」)一个类,该类实现了具有某些属性的接口。例如,考虑 Serializable 接口(Chapter 12)。通过实现此接口,表示类的实例可以写入 ObjectOutputStream(或「序列化」)。你可能听过一个说法:标记接口已经过时,更好的方式是标记注解(Item-39这个言论是错误的。与标记注解相比,标记接口有两个优点。首先,标记接口定义的类型由标记类的实例实现;标记注解不会。
2024-07-30 09:51:33 424
原创 Chapter-6-Item-40-坚持使用 @Override 注解n
你必须定义一个 equals 方法,它的参数是 Object 类型的,但是 Bigram 的 equals 方法的参数不是 Object 类型的,所以 Bigram 从 Object 继承 equals 方法。但是,你可能希望让类中覆盖超类方法的所有方法更加引人注目,在这种情况下,你也可以自由选择是否注解这些方法。然而,在抽象类或接口中,标记覆盖超类或超接口方法的所有方法是值得的,无论是具体的还是抽象的。在 IDE 和编译器的帮助下,你可以确保在任何你想要实施覆盖的地方都覆盖了,而没有遗漏。
2024-07-30 09:50:21 415
原创 Chapter-6-Item-39-注解优于命名模式
这段代码与我们用来处理 Test 注解的代码类似,只有一个不同:这段代码提取注解参数的值,并使用它来检查测试抛出的异常是否是正确的类型。编译的测试程序保证其注解参数表示有效的异常类型,但有一点需要注意:如果注解参数在编译时有效,但表示指定异常类型的类文件在运行时不再存在,那么测试运行程序将抛出 TypeNotPresentException。在没有这样的代码注释处理程序的情况下,如果你将 Test 注解放在实例方法的声明上,或者放在带有一个或多个参数的方法上,测试程序仍然会编译,让测试工具在运行时处理。
2024-07-30 09:49:13 836
原创 Chapter-6-Item-38-使用接口模拟可扩展枚举
因为在大多数情况下,枚举的可扩展性被证明是一个坏主意,主要在于:扩展类型的元素是基类的实例,而基类的实例却不是扩展类型的元素。枚举类型(BasicOperation)是不可扩展的,而接口类型(Operation)是可扩展的,它是用于在 API 中表示操作的接口类型。假设 API 是根据接口编写的,那么这些类型的实例可以在任何可以使用基本枚举类型的实例的地方使用。不仅可以在需要「基枚举」的任何地方传递「扩展枚举」的单个实例,还可以传入整个扩展枚举类型,并在基类型的元素之外使用或替代基类型的元素。
2024-07-30 09:46:04 397
原创 Chapter-6-Item-37-使用 EnumMap 替换序数索引
这个程序比原来的版本更短,更清晰,更安全,速度也差不多。EnumMap 在速度上与有序索引数组相当的原因是,EnumMap 在内部使用这样的数组,但是它向程序员隐藏了实现细节,将 Map 的丰富的功能和类型安全性与数组的速度结合起来。例如,如果花园包含一年生和多年生植物,但没有两年生植物,plantsByLifeCycle 的大小在 EnumMap 版本中为 3,在基于流的版本中为 2。在内部,Map 的映射是用一个数组来实现的,因此你只需花费很少的空间或时间成本就可以获得更好的清晰度、安全性并易于维护。
2024-07-30 09:44:11 306
原创 Chapter-6-Item-36-用 EnumSet 替代位字段
如果底层枚举类型有 64 个或更少的元素(大多数都是),则整个 EnumSet 用一个 long 表示,因此其性能与位字段的性能相当。最后,你必须预测在编写 API 时需要的最大位数,并相应地为位字段(通常是 int 或 long)选择一种类型。一旦选择了一种类型,在不更改 API 的情况下,不能超过它的宽度(32 或 64 位)。中描述的枚举类型的许多优点。EnumSet 的一个真正的缺点是,从 Java 9 开始,它不能创建不可变的 EnumSet,在未来发布的版本中可能会纠正这一点。
2024-07-30 09:43:16 413
原创 Chapter-6-Item-35-使用实例字段替代序数
Many enums are naturally associated with a single int value. All enums have an ordinal method, which returns the numerical position of each enum constant in its type. You may be tempted to derive an associated int value from the ordinal:许多枚举天然地与单个 int 值相关联
2024-07-30 09:42:14 265
原创 Chapter-6-Item-34-用枚举类型代替 int 常量
你可以在枚举类型中添加或重新排序常量,而无需重新编译其客户端,因为导出常量的字段在枚举类型及其客户端之间提供了一层隔离:常量值不会像在 int 枚举模式中那样编译到客户端中。如果你添加了一个新的枚举常量,但忘记向 switch 添加相应的 case,则枚举仍将编译,但在运行时尝试应用新操作时将失败。尝试传递错误类型的值将导致编译时错误,将一个枚举类型的表达式赋值给另一个枚举类型的变量,或者使用 == 运算符比较不同枚举类型的值同样会导致错误。如果不重新编译,客户端仍然可以运行,但是他们的行为将是错误的。
2024-07-29 11:02:17 753
原创 Chapter-5-Item-33-考虑类型安全的异构容器
它只是检查它的参数是否是类对象表示的类型的实例。该方法称为 asSubclass,它将类对象强制转换为它所调用的类对象,以表示由其参数表示的类的子类。确保 Favorites 不会违反其类型不变量的方法是让 putFavorite 方法检查实例是否是 type 表示的类型的实例,我们已经知道如何做到这一点。需要注意的是,通配符类型是嵌套的:通配符类型不是 Map 的类型,而是。因此,getFavorite 的实现通过使用 Class 的 cast 方法,将对象引用类型动态转化为所代表的 Class 对象。
2024-07-25 21:38:10 820
原创 Chapter-5-Item-32-明智地合用泛型和可变参数
这段代码分配了 type Object[] 的一个数组,这是保证保存这些实例的最特定的类型,无论调用站点上传递给 pickTwo 的是什么类型的对象。换句话说,如果可变参数数组仅用于将可变数量的参数从调用方传输到方法(毕竟这是可变参数的目的),那么该方法是安全的。如果方法是在其推断类型不可具体化的可变参数上调用的,编译器也会在调用时生成警告。,只有两个例外:将数组传递给另一个使用 @SafeVarargs 正确注释的可变参数方法是安全的,将数组传递给仅计算数组内容的某个函数的非可变方法也是安全的。
2024-07-25 21:37:34 940
原创 Chapter-5-Item-31-使用有界通配符增加 API 的灵活性
因此,它知道它从这个列表中得到的任何值都是 E 类型的,并且将 E 类型的任何值放入这个列表中都是安全的。如果输入参数既是生产者又是消费者,那么通配符类型对你没有任何好处:你需要一个精确的类型匹配,这就是在没有通配符的情况下得到的结果。popAll 的输入参数的类型不应该是「E 的集合」,而应该是「E 的某个超类型的集合」(其中的超类型定义为 E 本身是一个超类型[JLS, 4.10])。和 Object 类型的变量。同样,如果目标集合的元素类型与堆栈的元素类型完全匹配,那么这种方法可以很好地编译。
2024-07-25 21:36:43 905
原创 Chapter-5-Item-30-优先使用泛型方法
要做到这些,需要集合中的每个元素与集合中的每个其他元素相比较,换句话说,就是列表中的元素相互比较。要修复这些警告并使方法类型安全,请修改其声明,以声明表示三个集合(两个参数和返回值)的元素类型的类型参数,并在整个方法中使用该类型参数。)实现的,所以你可以为所有需要的类型参数化使用单个对象,但是你需要编写一个静态工厂方法,为每个请求的类型参数化重复分配对象。的类型的元素可以与之进行比较的类型。,但是恒等函数是特殊的:它会返回未修改的参数,所以我们知道,无论 T 的值是多少,都可以将其作为。
2024-07-25 21:36:01 608
原创 Chapter-5-Item-29-优先使用泛型
这个类一开始就应该是参数化的,但是因为它不是参数化的,所以我们可以在事后对它进行泛化。在这种情况下,有一个类型参数,表示堆栈的元素类型,这个类型参数的常规名称是 E(编译器可能无法证明你的程序是类型安全的,但你可以。数组中存储的惟一元素是传递给 push 方法的元素,它们属于 E 类型,因此 unchecked 的转换不会造成任何损害。中所解释的,你不能创建非具体化类型的数组,例如 E。在这种情况下,构造函数只包含 unchecked 的数组创建,因此在整个构造函数中取消警告是合适的。
2024-07-25 21:35:23 817
原创 Chapter-5-Item-29-优先使用泛型
这个类一开始就应该是参数化的,但是因为它不是参数化的,所以我们可以在事后对它进行泛化。在这种情况下,有一个类型参数,表示堆栈的元素类型,这个类型参数的常规名称是 E(编译器可能无法证明你的程序是类型安全的,但你可以。数组中存储的惟一元素是传递给 push 方法的元素,它们属于 E 类型,因此 unchecked 的转换不会造成任何损害。中所解释的,你不能创建非具体化类型的数组,例如 E。在这种情况下,构造函数只包含 unchecked 的数组创建,因此在整个构造函数中取消警告是合适的。
2024-07-25 21:34:47 303
原创 Chapter-5-Item-28-list 优于数组
因此,数组提供了运行时类型安全,而不是编译时类型安全,对于泛型反之亦然。编译器自动将检索到的元素转换为 String 类型,但它是一个 Integer 类型的元素,因此我们在运行时得到一个 ClassCastException。这个听起来很吓人的单词的意思很简单,如果 Sub 是 Super 的一个子类型,那么数组类型 Sub[] 就是数组类型 Super[] 的一个子类型。要使用这个类,每次使用方法调用时,必须将 choose 方法的返回值从对象转换为所需的类型,如果类型错误,转换将在运行时失败。
2024-07-25 21:34:08 614
原创 Chapter-5-Item-27-消除 unchecked 警告
如果不能消除 unchecked 警告,并且可以证明引发该警告的代码是类型安全的,那么可以在尽可能狭窄的范围内使用 @SuppressWarnings(“unchecked”) 注释来禁止警告。如果你在没有首先证明代码是类型安全的情况下禁止警告,那么你是在给自己一种错误的安全感。但是,如果你忽略了你知道是安全的 unchecked 警告(而不是抑制它们),那么当出现一个代表真正问题的新警告时,你将不会注意到。如果你消除了所有警告,你就可以确信你的代码是类型安全的,这是一件非常好的事情。一些警告会更难消除。
2024-07-25 21:33:08 680
原创 Chapter-5-Item-26-不要使用原始类型
将参数化类型的实例传递给设计用于原始类型的方法必须是合法的,反之亦然。这种方法是可行的,但是它使用的是原始类型,这是很危险的。每个泛型定义了一组参数化类型,这些参数化类型包括类名或接口名,以及带尖括号的参数列表,参数列表是与泛型的形式类型参数相对应的实际类型 [JLS, 4.4, 4.5]。无可否认,这个错误消息让人不满意,但是编译器已经完成了它的工作,防止你无视它的元素类型而破坏集合的类型一致性。是一个通配符类型,表示只能包含某种未知类型的对象的集合,Set 是一个原始类型,它选择了泛型系统。
2024-07-25 21:32:20 567
原创 Chapter-4-Item-25-源文件仅限有单个顶层类
这反过来保证了编译所生成的类文件,以及程序的行为,与源代码文件传递给编译器的顺序无关。修复这个问题非常简单,只需将顶层类(在我们的示例中是 Utensil 和 Dessert)分割为单独的源文件即可。如果(多个顶层类)隶属于另一个类,那么将它们转换成静态成员类通常是更好的选择,因为它增强了可读性,并通过声明它们为私有(因此,程序的行为受到源文件传递给编译器的顺序的影响,这显然是不可接受的。,当它看到对 Utensil 的引用(在对 Dessert 的引用之前)时,它将在。),降低了类的可访问性。
2024-07-25 21:31:03 1010
原创 Chapter-4-Item-25-源文件仅限有单个顶层类
这反过来保证了编译所生成的类文件,以及程序的行为,与源代码文件传递给编译器的顺序无关。修复这个问题非常简单,只需将顶层类(在我们的示例中是 Utensil 和 Dessert)分割为单独的源文件即可。如果(多个顶层类)隶属于另一个类,那么将它们转换成静态成员类通常是更好的选择,因为它增强了可读性,并通过声明它们为私有(因此,程序的行为受到源文件传递给编译器的顺序的影响,这显然是不可接受的。,当它看到对 Utensil 的引用(在对 Dessert 的引用之前)时,它将在。),降低了类的可访问性。
2024-07-22 15:06:25 890
原创 Chapter-4-Item-24-静态成员类优于非静态成员类
如果嵌套类的实例可以独立于外部类的实例存在,那么嵌套类必须是静态成员类:如果没有外部实例,就不可能创建非静态成员类的实例。最好把它看做是一个普通的类,只是碰巧在另一个类中声明而已,并且可以访问外部类的所有成员,甚至那些声明为 private 的成员。嵌套类是在另一个类中定义的类。如果所讨论的类是导出类的公共成员或受保护成员,那么在静态成员类和非静态成员类之间正确选择就显得尤为重要。在本例中,成员类是导出的 API 元素,在后续版本中,不能在不违反向后兼容性的情况下将非静态成员类更改为静态成员类。
2024-07-22 15:05:45 949
原创 Chapter-4-Item-23-类层次结构优于带标签的类
编译器确保每个类的构造函数初始化它的数据字段,并且每个类对于根类中声明的抽象方法都有一个实现。每种样式都有一个单独的数据类型,允许程序员指出变量的样式,并将变量和输入参数限制为特定的样式。要将已标签的类转换为类层次结构,首先为标签类中的每个方法定义一个包含抽象方法的抽象类,其行为依赖于标签值。类层次结构的另一个优点是,可以反映类型之间的自然层次关系,从而提高灵活性和更好的编译时类型检查。有时候,你可能会遇到这样一个类,它的实例有两种或两种以上的样式,并且包含一个标签字段来表示实例的样式。
2024-07-22 15:05:01 793
原创 Chapter-4-Item-22-接口只用于定义类型
当一个类实现了一个接口时,这个接口作为一种类型,可以用来引用类的实例。因此,实现接口的类应该说明使用者可以对类的实例做什么。为其他任何目的定义接口都是不合适的。不满足上述条件的一种接口是所谓的常量接口。这样的接口不包含任何方法;它仅由静态 final 字段组成,每个字段导出一个常量。使用这些常量的类实现接口,以避免用类名修饰常量名。常量接口模式是使用接口的糟糕方式。类内部会使用一些常量,这是实现细节。然而,实现常量接口会导致这个实现细节泄漏到类的导出 API 中。
2024-07-22 15:04:16 886
原创 Chapter-4-Item-21-为后代设计接口
默认方法的声明包括一个默认实现,所有实现接口但不实现默认方法的类都使用这个默认实现。默认方法被「注入」到现有的实现中,而无需实现者的知情或同意。返回的包私有类)中发生这种情况,JDK 维护人员必须覆盖默认的 removeIf 实现和其他类似的方法,以便在调用默认实现之前执行必要的同步。在有默认方法的情况下,接口的现有实现可以在没有错误或警告的情况下通过编译,但是在运行时出错。这是为 removeIf 方法编写的最好的通用实现,但遗憾的是,它在实际使用的一些 Collection 实现中导致了问题。
2024-07-22 15:03:19 1000
原创 Chapter-4-Item-20-接口优于抽象类
Java 有两种机制来定义允许多种实现的类型:接口和抽象类。由于 Java 8 [JLS 9.4.3]中引入了接口的默认方法,这两种机制都允许你为一些实例方法提供实现。一个主要区别是,一个类要实现抽象类定义的类型,该类必须是抽象类的子类。因为 Java 只允许单一继承,这种限制对抽象类而言严重制约了它们作为类型定义的使用。任何定义了所有必需的方法并遵守通用约定的类都允许实现接口,而不管该类驻留在类层次结构中何处。译注:1、抽象类的局限:一个类要实现抽象类定义的类型,该类必须是抽象类的子类。
2024-07-22 15:01:31 858
原创 Chapter-4-Item-19-继承要设计良好并且具有文档,否则禁止使用
如果你确实决定在为继承而设计的类中实现 Cloneable 或 Serializable,那么你应该知道,由于 clone 和 readObject 方法的行为与构造函数非常相似,因此存在类似的限制:clone 和 readObject 都不能直接或间接调用可覆盖的方法。传统上,它们既不是最终的,也不是为子类化而设计和记录的,但这种状态是危险的。是的,它确实违背了!为了允许程序员编写高效的子类而不受不必要的痛苦,类可能必须以明智地选择受保护的方法或(在很少的情况下)受保护的字段的形式为其内部工作提供挂钩。
2024-07-22 15:00:06 612
原创 Chapter-4-Item-18-优先选择复合而不是继承
包装器类的缺点很少。此外,你的方法是否能够完成新的超类方法的约定是值得怀疑的,因为在你编写子类方法时,该约定还没有被写入。它相当于重新实现超类方法,这可能会导致「自用」,也可能不会,这是困难的、耗时的、容易出错的,并且可能会降低性能。为了优化程序的性能,我们需要查询 HashSet,以确定自创建以来添加了多少元素(不要与当前的大小混淆,当元素被删除时,当前的大小会递减)。如果答案是否定的,通常情况下,B 应该包含 A 的私有实例并暴露不同的 API:A 不是 B 的基本组成部分,而仅仅是其实现的一个细节。
2024-07-22 14:57:21 993
原创 Chapter-4-Item-17-减少可变性
如果你选择让不可变类实现 Serializable,并且该类包含一个或多个引用可变对象的字段,那么你必须提供一个显式的 readObject 或 readResolve 方法,或者使用 ObjectOutputStream.writeUnshared 或 ObjectInputStream.readUnshared 方法,即使默认的序列化形式是可以接受的。同样,如果在没有同步的情况下,引用新创建的实例并从一个线程传递到另一个线程,那么就有必要确保正确的行为,就像内存模型中描述的那样 [JLS, 17.5;
2024-07-22 14:56:32 731
原创 Chapter-4-Item-16-在公共类中,使用访问器方法,而不是公共字段
但是,如果一个类是包级私有的或者是私有嵌套类,那么公开它的数据字段并没有什么本质上的错误(假设它们能够很好地描述类提供的抽象)。你不能在不更改该类的 API 的情况下更改该类的表现形式,也不能在读取字段时采取辅助操作,但是你可以实施不变量。当然,当涉及到公共类时,强硬派是正确的:如果类可以在包之外访问,那么提供访问器方法来保持更改类内部表示的灵活性。然而,有时候包级私有或私有嵌套类需要公开字段,无论这个类是可变的还是不可变的。因为这些类的数据字段是直接访问的,所以这些类没有提供封装的好处(
2024-07-22 14:55:11 888
原创 Chapter-4-Item-15-尽量减少类和成员的可访问性
通过将其设置为包私有,可以使其成为实现的一部分,而不是导出的 API 的一部分,并且可以在后续版本中修改、替换或删除它,而不必担心损害现有的客户端。如果将模块的 JAR 文件放在应用程序的类路径上,而不是模块路径上,模块中的包将恢复它们的非模块行为:包的公共类的所有公共成员和保护成员都具有正常的可访问性,而不管模块是否导出包 [Reinhold,1.2]。但是,降低公共类的可访问性比减少包级私有顶级类的可访问性重要得多:公共类是包 API 的一部分,而包级私有顶级类已经是实现的一部分。
2024-07-22 14:54:05 746
原创 Chapter-3-Item-14-考虑实现 Comparable 接口
Chapter 3. Methods Common to All Objects(对象的通用方法)Item 14: Consider implementing Comparable(考虑实现 Comparable 接口)Unlike the other methods discussed in this chapter, the compareTo method is not declared in Object. Rather, it is the sole method in the Compara
2024-07-15 10:03:36 565
原创 Chapter-3-Item-13-明智地覆盖 clone 方法
克隆复杂可变对象的最后一种方法是调用 super.clone(),将结果对象中的所有字段设置为初始状态,然后调用更高级别的方法重新生成原始对象的状态。在我们的 HashTable 示例中,buckets 字段将初始化为一个新的 bucket 数组,并且对于克隆的 hash 表中的每个键值映射将调用 put(key, value) 方法(未显示)。否则,最好提供对象复制的替代方法。如果 clone 调用一个在子类中被重写的方法,这个方法将在子类有机会修复其在克隆中的状态之前执行,很可能导致克隆和原始的破坏。
2024-07-15 10:02:23 778
原创 Chapter-3-Item-12-始终覆盖 toString 方法
指定格式的优点是,它可以作为对象的标准的、明确的、人类可读的表示。因此,例如,对于 PhoneNumber 类使用自动生成的 toString 方法是不合适的(因为电话号码具有标准的字符串表示形式),但是对于 Potion 类来说它是完全可以接受的。也就是说,一个自动生成的 toString 方法要比从对象继承的方法好得多,对象继承的方法不会告诉你对象的值。指定 toString 返回值的格式的缺点是,一旦指定了它,就会终生使用它,假设你的类被广泛使用。),因为 Java 为你提供了一个非常好的方法。
2024-07-15 10:01:06 641
原创 Chapter-3-Item-11-当覆盖 equals 方法时,总要覆盖 hashCode 方法
在步骤 2.b 中使用的乘法将使结果取决于字段的顺序,如果类有多个相似的字段,则会产生一个更好的散列算法。因为这个方法返回一个简单的确定的计算结果,它的唯一输入是 PhoneNumber 实例中的三个重要字段,所以很明显,相等的 PhoneNumber 实例具有相等的散列码。它们的质量可与 Java 库的值类型中的散列算法相媲美,对于大多数用途来说都是足够的。根据类的 equals 方法,两个不同的实例在逻辑上可能是相等的,但是对于对象的 hashCode 方法来说,它们只是两个没有共同之处的对象。
2024-07-15 10:00:29 714
原创 Chapter-3-Item-10-Obey-覆盖 equals 方法时应遵守的约定
IDE 也有生成 equals 和 hashCode 方法的功能,但是生成的源代码比使用 AutoValue 的代码更冗长,可读性更差,不会自动跟踪类中的变化,因此需要进行测试。手动编写和测试这些方法的一个很好的替代方法是使用谷歌的开源 AutoValue 框架,它会自动为你生成这些方法,由类上的一个注释触发。通常,正确的类型是方法发生的类。这可能看起来不是很糟糕,但其后果是不可接受的:Point 的子类的实例仍然是一个 Point,并且它仍然需要作为一个函数来工作,但是如果采用这种方法,它就不会这样做!
2024-07-15 09:58:52 633
原创 Chapter-2-Item-9-使用 try-with-resources 优于 try-finally
例如,在 firstLineOfFile 方法中,由于底层物理设备发生故障,对 readLine 的调用可能会抛出异常,而关闭的调用也可能出于同样的原因而失败。异常堆栈跟踪中没有第一个异常的记录,这可能会使实际系统中的调试变得非常复杂(而这可能是希望出现的第一个异常,以便诊断问题)。使用 try-with-resources 语句可以很容易地为必须关闭的资源编写正确的代码,而使用 try-finally 几乎是不可能的。事实上,2007 年发布的 Java 库中三分之二的 close 方法使用都是错误的。
2024-07-12 11:32:25 634
原创 Chapter-2-Item-8-避免使用终结器和清除器
如果使用清除器清除的所有实例(在我的机器上每个实例大约 500ns),那么清除器的速度与终结器相当,但是如果只将它们作为安全网来使用,清除器的速度要快得多,如下所述。在这种情况下,在我的机器上创建、清理和销毁一个对象需要花费 66ns 的时间,这意味着如果你不使用它,你需要多出五倍(而不是五十倍)的保障成本。在这方面,清洁器比终结器要好一些,因为类作者可以自己控制是否清理线程,但是清洁器仍然在后台运行,在垃圾收集器的控制下运行,所以不能保证及时清理。清除器没有这个问题,因为使用清除器的库可以控制它的线程。
2024-07-12 11:31:21 783
原创 Chapter-2-Item-7-排除过时的对象引用
存储池包含元素数组的元素(对象引用单元,而不是对象本身)数组的活动部分(如前面所定义的)中的元素被分配,而数组其余部分中的元素是空闲的。你可以对它进行详尽的测试,它会以优异的成绩通过所有的测试,但是有一个潜在的问题。简单地说,该程序有一个「内存泄漏」问题,由于垃圾收集器活动的增加或内存占用的增加,它可以悄无声息地表现为性能的降低。用 null 处理过时引用的另一个好处是,如果它们随后被错误地关联引用,程序将立即失败,出现 NullPointerException,而不是悄悄地做错误的事情。
2024-07-12 11:30:43 668
原创 Chapter-2-Item-6避免创建不必要的对象
天真的是,对 keySet 的每次调用都必须创建一个新的 Set 实例,但是对给定 Map 对象上的 keySet 的每次调用都可能返回相同的 Set 实例。虽然返回的 Set 实例通常是可变的,但所有返回的对象在功能上都是相同的:当返回的对象之一发生更改时,所有其他对象也会发生更改,因为它们都由相同的 Map 实例支持。虽然创建 keySet 视图对象的多个实例基本上是无害的,但这是不必要的,也没有好处。当一个对象是不可变的,很明显,它可以安全地复用,但在其他情况下,它远不那么明显,甚至违反直觉。
2024-07-12 11:29:40 735
免费的Java开发的迷宫小游戏
2024-05-05
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人