mirror of
https://github.com/Jueee/effective-Java.git
synced 2025-03-14 03:10:42 +08:00
将源文件限制为单个顶级类
This commit is contained in:
parent
69043c55bc
commit
8bd23ac892
22
README.md
22
README.md
@ -16,3 +16,25 @@
|
||||
|
||||
#### ch03.[所有对象的通用方法](ch03所有对象的通用方法)
|
||||
|
||||
10. [重写equals方法时遵守通用约定](ch03所有对象的通用方法/10.重写equals方法时遵守通用约定.md)
|
||||
11. [重写equals方法时同时也要重写hashcode方法](ch03所有对象的通用方法/11.重写equals方法时同时也要重写hashcode方法.md)
|
||||
12. [始终重写toString方法](ch03所有对象的通用方法/12.始终重写toString方法.md)
|
||||
13. [谨慎地重写clone方法](ch03所有对象的通用方法/13.谨慎地重写clone方法.md)
|
||||
14. [考虑实现Comparable接口](ch03所有对象的通用方法/14.考虑实现Comparable接口.md)
|
||||
|
||||
#### ch04.[类和接口](ch04类和接口)
|
||||
|
||||
15. [使类和成员的可访问性最小化](ch04类和接口/15.使类和成员的可访问性最小化.md)
|
||||
16. [在公共类中使用访问方法而不是公共属性](ch04类和接口/16.在公共类中使用访问方法而不是公共属性.md)
|
||||
17. [最小化可变性](ch04类和接口/17.最小化可变性.md)
|
||||
18. [组合优于继承](ch04类和接口/18.组合优于继承.md)
|
||||
19. [要么设计继承并提供文档说明,要么禁用继承](ch04类和接口/19.要么设计继承并提供文档说明,要么禁用继承.md)
|
||||
20. [接口优于抽象类](ch04类和接口/20.接口优于抽象类.md)
|
||||
21. [为后代设计接口](ch04类和接口/21.为后代设计接口.md)
|
||||
22. [接口仅用来定义类型](ch04类和接口/22.接口仅用来定义类型.md)
|
||||
23. [类层次结构优于标签类](ch04类和接口/23.类层次结构优于标签类.md)
|
||||
24. [支持使用静态成员类而不是非静态类](ch04类和接口/24.支持使用静态成员类而不是非静态类.md)
|
||||
25. [将源文件限制为单个顶级](ch04类和接口/25.将源文件限制为单个顶级.md)
|
||||
|
||||
#### ch05.[泛型](ch05泛型)
|
||||
|
||||
|
7
ch04类和接口/23.类层次结构优于标签类.md
Normal file
7
ch04类和接口/23.类层次结构优于标签类.md
Normal file
@ -0,0 +1,7 @@
|
||||
## 类层次结构优于标签类
|
||||
|
||||
**示例代码**:[Item23Example01.java](ClassesAndInterfaces/src/main/java/com/jueee/item23/Item23Example01.java):标签类:它可以表示一个圆形或矩形。
|
||||
|
||||
这样的标签类具有许多缺点。 它们充斥着杂乱无章的样板代码,包括枚举声明,标签字段和 `switch` 语句。 可读性更差,因为多个实现在一个类中混杂在一起。 内存使用增加,因为实例负担属于其他风格不相关的领域。
|
||||
|
||||
**示例代码**:[Item23Example02.java](ClassesAndInterfaces/src/main/java/com/jueee/item23/Item23Example02.java):类层次:它可以表示一个圆形或矩形。
|
78
ch04类和接口/24.支持使用静态成员类而不是非静态类.md
Normal file
78
ch04类和接口/24.支持使用静态成员类而不是非静态类.md
Normal file
@ -0,0 +1,78 @@
|
||||
## 支持使用静态成员类而不是非静态类
|
||||
|
||||
嵌套类(nested class)是在另一个类中定义的类。 嵌套类应该只存在于其宿主类(enclosing class)中。
|
||||
|
||||
如果一个嵌套类在其他一些情况下是有用的,那么它应该是一个顶级类。
|
||||
|
||||
有四种嵌套类:
|
||||
|
||||
1. **静态成员类**
|
||||
2. **非静态成员类**
|
||||
3. **匿名类**
|
||||
4. **局部类**
|
||||
|
||||
除了第一种以外,剩下的三种都被称为内部类(inner class)。
|
||||
|
||||
### 静态成员类
|
||||
|
||||
静态成员类是最简单的嵌套类。
|
||||
|
||||
最好把它看作是一个普通的类,恰好在另一个类中声明,并且可以访问所有宿主类的成员,甚至是那些被声明为私有类的成员。
|
||||
|
||||
静态成员类是其宿主类的静态成员,并遵循与其他静态成员相同的可访问性规则。
|
||||
|
||||
如果它被声明为 `private`,则只能在宿主类中访问,等等。
|
||||
|
||||
静态成员类的一个常见用途是作为公共帮助类,仅在与其外部类一起使用时才有用。
|
||||
|
||||
例如,考虑一个描述计算器支持的操作的枚举类型(详见第 34 条)。 `Operation` 枚举应该是 `Calculator` 类的公共静态成员类。 `Calculator` 客户端可以使用 `Calculator.Operation.PLUS` 和 `Calculator.Operation.MINUS` 等名称来引用操作。
|
||||
|
||||
### 非静态成员类
|
||||
|
||||
在语法上,静态成员类和非静态成员类之间的唯一区别是静态成员类在其声明中具有 `static` 修饰符。
|
||||
|
||||
尽管句法相似,但这两种嵌套类是非常不同的。
|
||||
|
||||
非静态成员类的每个实例都隐含地与其包含的类的宿主实例相关联。 在非静态成员类的实例方法中,可以调用宿主实例上的方法,或者使用限定的构造获得对宿主实例的引用。
|
||||
|
||||
如果嵌套类的实例可以与其宿主类的实例隔离存在,那么嵌套类必须是静态成员类:不可能在没有宿主实例的情况下创建非静态成员类的实例。
|
||||
|
||||
非静态成员类实例和其宿主实例之间的关联是在创建成员类实例时建立的,并且之后不能被修改。
|
||||
|
||||
通常情况下,通过在宿主类的实例方法中调用非静态成员类构造方法来自动建立关联。 尽管很少有可能使用表达式 `enclosingInstance.new MemberClass(args)` 手动建立关联。 正如你所预料的那样,该关联在非静态成员类实例中占用了空间,并为其构建添加了时间开销。
|
||||
|
||||
非静态成员类的一个常见用法是定义一个 `Adapter` ,它允许将外部类的实例视为某个不相关类的实例。
|
||||
|
||||
例如,`Map` 接口的实现通常使用非静态成员类来实现它们的集合视图,这些视图由 `Map` 的 `keySet`,`entrySet` 和 `values` 方法返回。
|
||||
|
||||
**示例代码**:[Item23Example01.java](ClassesAndInterfaces/src/main/java/com/jueee/item24/Item23Example01.java):集合接口使用非静态成员类来实现它们的迭代器。
|
||||
|
||||
### 匿名类
|
||||
|
||||
一个匿名类没有名字。 它不是其宿主类的成员。 它不是与其他成员一起声明,而是在使用时同时声明和实例化。 在表达式合法的代码中,匿名类是允许的。 当且仅当它们出现在非静态上下文中时,匿名类才会封装实例。 但是,即使它们出现在静态上下文中,它们也不能有除常量型变量之外的任何静态成员,这些常量型变量包括 `final` 的基本类型,或者初始化常量表达式的字符串属性。
|
||||
|
||||
匿名类的适用性有很多限制。 除了在声明的时候之外,不能实例化它们。 你不能执行 `instanceof` 方法测试或者做任何其他需要你命名的类。 不能声明一个匿名类来实现多个接口,或者继承一个类并同时实现一个接口。 匿名类的客户端不能调用除父类型继承的成员以外的任何成员。 因为匿名类在表达式中出现,所以它们必须保持简短 —— 约十行或更少 —— 否则可读性将受到影响。
|
||||
|
||||
在将 lambda 表达式添加到 Java 之前,匿名类是创建小函数对象和处理对象的首选方法,但 lambda 表达式现在是首选。 匿名类的另一个常见用途是实现静态工厂方法(请参阅 [Item20Example02.java](ClassesAndInterfaces/src/main/java/com/jueee/item20/Item20Example02.java) )。
|
||||
|
||||
### 局部类
|
||||
|
||||
局部类是四种嵌套类中使用最少的。
|
||||
|
||||
一个局部类可以在任何可以声明局部变量的地方声明,并遵守相同的作用域规则。
|
||||
|
||||
局部类与其他类型的嵌套类具有共同的属性。 像成员类一样,他们有名字,可以重复使用。
|
||||
|
||||
就像匿名类一样,只有在非静态上下文中定义它们时,它们才会包含实例,并且它们不能包含静态成员。
|
||||
|
||||
像匿名类一样,应该保持简短,以免损害可读性。
|
||||
|
||||
### 总结
|
||||
|
||||
回顾一下,有四种不同的嵌套类,每个都有它的用途。
|
||||
|
||||
如果一个嵌套的类需要在一个方法之外可见,或者太长而不能很好地适应一个方法,使用一个成员类。
|
||||
|
||||
如果一个成员类的每个实例都需要一个对其宿主实例的引用,使其成为非静态的; 否则,使其静态。
|
||||
|
||||
假设这个类属于一个方法内部,如果你只需要从一个地方创建实例,并且存在一个预置类型来说明这个类的特征,那么把它作为一个匿名类;否则,把它变成局部类。
|
15
ch04类和接口/25.将源文件限制为单个顶级.md
Normal file
15
ch04类和接口/25.将源文件限制为单个顶级.md
Normal file
@ -0,0 +1,15 @@
|
||||
## 将源文件限制为单个顶级类
|
||||
|
||||
虽然 Java 编译器允许在单个源文件中定义多个顶级类,但这样做没有任何好处,并且存在重大风险。 风险源于在源文件中定义多个顶级类使得为类提供多个定义成为可能。 使用哪个定义会受到源文件传递给编译器的顺序的影响。
|
||||
|
||||
**示例代码**:[Item25Example01.java](ClassesAndInterfaces/src/main/java/com/jueee/item25/Item25Example01.java):【**反例**】包含一个引用其他两个顶级类的成员的 Main 类。
|
||||
|
||||
如果试图将多个顶级类放入单个源文件中,请考虑使用静态成员类(详见第 24 条)作为将类拆分为单独的源文件的替代方法。 如果这些类从属于另一个类,那么将它们变成静态成员类通常是更好的选择,因为它提高了可读性,并且可以通过声明它们为私有(详见第 15 条)来减少类的可访问性。
|
||||
|
||||
**示例代码**:[Item25Example02.java](ClassesAndInterfaces/src/main/java/com/jueee/item25/Item25Example02.java):使用静态成员类作为将类拆分为单独的源文件的替代方法。
|
||||
|
||||
永远不要将多个顶级类或接口放在一个源文件中。
|
||||
|
||||
遵循这个规则保证在编译时不能有多个定义。
|
||||
|
||||
这又保证了编译生成的类文件以及生成的程序的行为与源文件传递给编译器的顺序无关。
|
@ -0,0 +1,53 @@
|
||||
package com.jueee.item23;
|
||||
|
||||
public class Item23Example01 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Figure1 figure1 = new Figure1(5);
|
||||
System.out.println(figure1.area());
|
||||
|
||||
Figure1 figure2 = new Figure1(5, 3);
|
||||
System.out.println(figure2.area());
|
||||
}
|
||||
}
|
||||
|
||||
// 可以表示一个圆形或矩形
|
||||
class Figure1 {
|
||||
enum Shape {
|
||||
RECTANGLE, CIRCLE
|
||||
};
|
||||
|
||||
// Tag field - the shape of this figure
|
||||
final Shape shape;
|
||||
|
||||
// These fields are used only if shape is RECTANGLE
|
||||
double length;
|
||||
double width;
|
||||
|
||||
// This field is used only if shape is CIRCLE
|
||||
double radius;
|
||||
|
||||
// Constructor for circle
|
||||
Figure1(double radius) {
|
||||
shape = Shape.CIRCLE;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
// Constructor for rectangle
|
||||
Figure1(double length, double width) {
|
||||
shape = Shape.RECTANGLE;
|
||||
this.length = length;
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
double area() {
|
||||
switch (shape) {
|
||||
case RECTANGLE:
|
||||
return length * width;
|
||||
case CIRCLE:
|
||||
return Math.PI * (radius * radius);
|
||||
default:
|
||||
throw new AssertionError(shape);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.jueee.item23;
|
||||
|
||||
public class Item23Example02 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Circle circle = new Circle(5);
|
||||
System.out.println(circle.area());
|
||||
|
||||
Rectangle rectangle = new Rectangle(5, 3);
|
||||
System.out.println(rectangle.area());
|
||||
}
|
||||
}
|
||||
|
||||
// Class hierarchy replacement for a tagged class
|
||||
abstract class Figure2 {
|
||||
abstract double area();
|
||||
}
|
||||
|
||||
class Circle extends Figure2 {
|
||||
final double radius;
|
||||
|
||||
Circle(double radius) {
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
double area() {
|
||||
return Math.PI * (radius * radius);
|
||||
}
|
||||
}
|
||||
|
||||
class Rectangle extends Figure2 {
|
||||
final double length;
|
||||
final double width;
|
||||
|
||||
Rectangle(double length, double width) {
|
||||
this.length = length;
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
@Override
|
||||
double area() {
|
||||
return length * width;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.jueee.item24;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class Item24Example01<E> extends AbstractSet<E> {
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new MyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
private class MyIterator implements Iterator<E> {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.jueee.item25;
|
||||
|
||||
public class Item25Example01 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Utensil.NAME + Dessert.NAME);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Two classes defined in one file. Don't ever do this!
|
||||
class Utensil {
|
||||
static final String NAME = "pan";
|
||||
}
|
||||
|
||||
class Dessert {
|
||||
static final String NAME = "cake";
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.jueee.item25;
|
||||
|
||||
public class Item25Example02 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Utensil.NAME + Dessert.NAME);
|
||||
}
|
||||
|
||||
private static class Utensil {
|
||||
static final String NAME = "pan";
|
||||
}
|
||||
|
||||
private static class Dessert {
|
||||
static final String NAME = "cake";
|
||||
}
|
||||
}
|
32
ch05泛型/Generics/.gitignore
vendored
Normal file
32
ch05泛型/Generics/.gitignore
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**
|
||||
!**/src/test/**
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
/chromedriver.exe
|
25
ch05泛型/Generics/pom.xml
Normal file
25
ch05泛型/Generics/pom.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.github.jueee</groupId>
|
||||
<artifactId>Generics</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Generics</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,5 @@
|
||||
package com.jueee.example26;
|
||||
|
||||
public class Item26Example01 {
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user