Java 中文官方教程 2022 版(七)(1)

本文涉及的产品
.cn 域名,1个 12个月
简介: Java 中文官方教程 2022 版(七)

问题和练习:泛型

原文:docs.oracle.com/javase/tutorial/java/generics/QandE/generics-questions.html

  1. 编写一个通用方法来计算集合中具有特定属性的元素数量(例如,奇数、质数、回文数)。
  2. 以下类会编译吗?如果不会,为什么?
public final class Algorithm {
    public static <T> T max(T x, T y) {
        return x > y ? x : y;
    }
}
  1. 编写一个通用方法来交换数组中两个不同元素的位置。
  2. 如果编译器在编译时擦除所有类型参数,为什么应该使用泛型?
  3. 在类型擦除后,以下类被转换为什么?
public class Pair<K, V> {
    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
    public K getKey() { return key; }
    public V getValue() { return value; }
    public void setKey(K key)     { this.key = key; }
    public void setValue(V value) { this.value = value; }
    private K key;
    private V value;
}
  1. 以下方法在类型擦除后会转换为什么?
public static <T extends Comparable<T>>
    int findFirstGreaterThan(T[] at, T elem) {
    // ...
}
  1. 以下方法会编译吗?如果不会,为什么?
public static void print(List<? extends Number> list) {
    for (Number n : list)
        System.out.print(n + " ");
    System.out.println();
}
  1. 编写一个通用方法来查找列表范围begin, end)中的最大元素。
  2. 以下类会编译吗?如果不会,为什么?
public class Singleton<T> {
    public static T getInstance() {
        if (instance == null)
            instance = new Singleton<T>();
        return instance;
    }
    private static T instance = null;
}
  1. 给定以下类:
class Shape { /* ... */ }
class Circle extends Shape { /* ... */ }
class Rectangle extends Shape { /* ... */ }
class Node<T> { /* ... */ }
  1. 以下代码会编译吗?如果不会,为什么?
Node<Circle> nc = new Node<>();
Node<Shape>  ns = nc;
  1. 考虑这个类:
class Node<T> implements Comparable<T> {
    public int compareTo(T obj) { /* ... */ }
    // ...
}
  1. 以下代码会编译吗?如果不会,为什么?
Node<String> node = new Node<>();
Comparable<String> comp = node;
  1. 如何调用以下方法来找到列表中与指定整数列表互质的第一个整数?
public static <T>
    int findFirst(List<T> list, int begin, int end, UnaryPredicate<T> p)
  1. 注意,两个整数ab互质,如果 gcd(a, b) = 1,其中 gcd 是最大公约数的缩写。

[检查你的答案。

课程:包(Packages)

原文:docs.oracle.com/javase/tutorial/java/package/index.html

这节课讲解了如何将类和接口打包成包,如何使用在包中的类,以及如何安排文件系统以便编译器能够找到你的源文件。

创建和使用包

原文:docs.oracle.com/javase/tutorial/java/package/packages.html

为了使类型更容易找到和使用,避免命名冲突,并控制访问权限,程序员将相关类型的组合打包成包。


定义: 是提供访问保护和命名空间管理的相关类型的分组。请注意,类型 指的是类、接口、枚举和注解类型。枚举和注解类型是类和接口的特殊种类,因此在本课程中,类型 经常简称为类和接口


Java 平台中的类型是通过功能将类打包在一起的各种包的成员:基本类在java.lang中,用于读写(输入和输出)的类在java.io中,依此类推。你也可以将你的类型放在包中。

假设你编写了一组表示图形对象的类,比如圆、矩形、线条和点。你还编写了一个接口,Draggable,如果类可以被鼠标拖动,则实现该接口。

//*in the Draggable.java file*
public interface Draggable {
    ...
}
//*in the Graphic.java file*
public abstract class Graphic {
    ...
}
//*in the Circle.java file*
public class Circle extends Graphic
    implements Draggable {
    . . .
}
//*in the Rectangle.java file*
public class Rectangle extends Graphic
    implements Draggable {
    . . .
}
//*in the Point.java file*
public class Point extends Graphic
    implements Draggable {
    . . .
}
//*in the Line.java file*
public class Line extends Graphic
    implements Draggable {
    . . .
}

你应该将这些类和接口打包到一个包中,原因包括以下几点:

  • 你和其他程序员可以轻松确定这些类型是相关的。
  • 你和其他程序员知道在哪里找到可以提供与图形相关功能的类型。
  • 你的类型名称不会与其他包中的类型名称冲突,因为包会创建一个新的命名空间。
  • 你可以允许包内的类型彼此之间具有无限制的访问,但仍然限制包外类型的访问。

创建一个包

原文:docs.oracle.com/javase/tutorial/java/package/createpkgs.html

要创建一个包,你需要为包选择一个名称(命名约定将在下一节讨论),并在包含你想要放入包中的类型(类、接口、枚举和注解类型)的每个源文件的顶部放置一个带有该名称的package语句。

包语句(例如,package graphics;)必须是源文件中的第一行。每个源文件中只能有一个包语句,并且它适用于文件中的所有类型。


**注意:**如果你在单个源文件中放入多个类型,只能有一个是public的,并且它必须与源文件同名。例如,你可以在文件Circle.java中定义public class Circle,在文件Draggable.java中定义public interface Draggable,在文件Day.java中定义public enum Day,等等。

你可以在同一个文件中包含非公共类型和一个公共类型(这是强烈不推荐的,除非非公共类型很小并且与公共类型密切相关),但只有公共类型可以从包外访问。所有顶级的非公共类型将是包私有的。


如果你将前面部分列出的图形接口和类放在一个名为graphics的包中,你将需要六个源文件,如下所示:

//*in the Draggable.java file*
package graphics;
public interface Draggable {
    . . .
}
//*in the Graphic.java file*
package graphics;
public abstract class Graphic {
    . . .
}
//*in the Circle.java file*
package graphics;
public class Circle extends Graphic
    implements Draggable {
    . . .
}
//*in the Rectangle.java file*
package graphics;
public class Rectangle extends Graphic
    implements Draggable {
    . . .
}
//*in the Point.java file*
package graphics;
public class Point extends Graphic
    implements Draggable {
    . . .
}
//*in the Line.java file*
package graphics;
public class Line extends Graphic
    implements Draggable {
    . . .
}

如果你不使用package语句,你的类型将会进入一个无名包。一般来说,无名包只适用于小型或临时应用程序,或者当你刚开始开发过程时。否则,类和接口应该放在命名包中。

包命名

原文:docs.oracle.com/javase/tutorial/java/package/namingpkgs.html

全球范围内的程序员使用 Java 编程语言编写类和接口,很可能许多程序员会为不同类型使用相同的名称。事实上,前面的例子就是这样做的:它定义了一个 Rectangle 类,而 java.awt 包中已经有一个 Rectangle 类。尽管如此,如果它们位于不同的包中,编译器仍允许两个类具有相同的名称。每个 Rectangle 类的完全限定名称包括包名。也就是说,graphics 包中的 Rectangle 类的完全限定名称是 graphics.Rectangle,而 java.awt 包中的 Rectangle 类的完全限定名称是 java.awt.Rectangle

这种方法很有效,除非两个独立的程序员使用相同的包名。如何避免这个问题?约定。

命名约定

包名全部小写以避免与类或接口的名称冲突。

公司使用其反转的互联网域名作为其包名的起始部分—例如,com.example.mypackage 表示由 example.com 的程序员创建的名为 mypackage 的包。

公司内部发生的名称冲突需要在公司内部通过约定处理,也许可以在公司名称后面加上地区或项目名称(例如,com.example.region.mypackage)。

Java 语言中的包以 java.javax. 开头。

在某些情况下,互联网域名可能不是有效的包名。如果域名包含连字符或其他特殊字符,如果包名以数字或其他 Java 名称不允许用作 Java 名称开头的字符开头,或者包名包含保留的 Java 关键字,例如 “int”。在这种情况下,建议的约定是添加下划线。例如:

合法化包名

域名 包名前缀
hyphenated-name.example.org org.example.hyphenated_name
example.int int_.example
123name.example.com com.example._123name

使用包成员

原文:docs.oracle.com/javase/tutorial/java/package/usepkgs.html

组成包的类型被称为包成员

要从其包外部使用public包成员,你必须执行以下操作之一:

  • 通过其完全限定名称引用成员
  • 导入包成员
  • 导入成员的整个包

每种情况都适用于不同的情况,如下面的部分所解释的。

通过其限定名称引用包成员

到目前为止,在本教程中的大多数示例都通过其简单名称引用类型,如RectangleStackOfInts。如果你编写的代码与该成员在同一个包中,或者已经导入了该成员,你可以使用包成员的简单名称。

但是,如果你尝试使用来自不同包的成员,并且该包尚未被导入,你必须使用成员的完全限定名称,其中包括包名称。以下是在前面示例中声明的graphics包中的Rectangle类的完全限定名称。

graphics.Rectangle

你可以使用这个限定名称来创建graphics.Rectangle的实例:

graphics.Rectangle myRect = new graphics.Rectangle();

对于不经常使用的限定名称是可以的。然而,当一个名称被重复使用时,反复输入名称变得乏味,代码变得难以阅读。作为替代方案,你可以导入成员或其包,然后使用其简单名称。

导入包成员

要将特定成员导入当前文件,请在文件开头放置一个import语句,在任何类型定义之前,但在package语句之后(如果有的话)。以下是如何从前一节中创建的graphics包中导入Rectangle类。

import graphics.Rectangle;

现在你可以通过其简单名称引用Rectangle类。

Rectangle myRectangle = new Rectangle();

如果你只从graphics包中使用少量成员,这种方法很有效。但如果你从一个包中使用许多类型,你应该导入整个包。

导入整个包

要导入特定包中包含的所有类型,请使用带有星号(*)通配符的import语句。

import graphics.*;

现在你可以通过其简单名称引用graphics包中的任何类或接口。

Circle myCircle = new Circle();
Rectangle myRectangle = new Rectangle();

import语句中的星号只能用于指定包中的所有类,如下所示。它不能用于匹配包中的一部分类。例如,以下内容不匹配以A开头的graphics包中的所有类。

// *does not work*
import graphics.A*;

相反,它会生成编译器错误。通常情况下,使用import语句只导入单个包成员或整个包。


注意: 另一种不太常见的 import 形式允许你导入封闭类的公共嵌套类。例如,如果 graphics.Rectangle 类包含有用的嵌套类,比如 Rectangle.DoubleWideRectangle.Square,你可以通过以下两个语句导入 Rectangle 及其嵌套类。

import graphics.Rectangle;
import graphics.Rectangle.*;

请注意,第二个导入语句不会导入 Rectangle

另一种不太常见的 import 形式,即静态导入语句,将在本节末尾讨论。


为了方便起见,Java 编译器会自动为每个源文件导入两个完整的包:(1)java.lang 包和(2)当前包(当前文件的包)。

包的表面层次结构

起初,包看起来是分层的,但实际上并非如此。例如,Java API 包括一个 java.awt 包,一个 java.awt.color 包,一个 java.awt.font 包,以及许多以 java.awt 开头的其他包。然而,java.awt.color 包、java.awt.font 包和其他 java.awt.xxxx不包含java.awt 包中。前缀 java.awt(Java 抽象窗口工具包)用于一些相关的包,以明确显示它们之间的关系,而不是表示包含关系。

导入 java.awt.* 导入了 java.awt 包中的所有类型,但不会导入 java.awt.colorjava.awt.font 或任何其他 java.awt.xxxx 包。如果你计划使用 java.awt.color 中的类以及 java.awt 中的类,你必须导入这两个包及其所有文件:

import java.awt.*;
import java.awt.color.*;

名称歧义

如果一个包中的成员与另一个包中的成员同名,并且两个包都被导入,你必须通过其限定名称引用每个成员。例如,graphics 包定义了一个名为 Rectangle 的类。java.awt 包也包含一个 Rectangle 类。如果 graphicsjava.awt 都被导入,以下内容是模棱两可的。

Rectangle rect;

在这种情况下,你必须使用成员的完全限定名称来指示你想要的确切 Rectangle 类。例如,

graphics.Rectangle rect;

静态导入语句

有些情况下,你需要频繁访问一个或两个类的静态 final 字段(常量)和静态方法。反复添加这些类的名称可能会导致代码混乱。静态导入语句为你提供了一种导入你想要使用的常量和静态方法的方式,这样你就不需要为它们的类名添加前缀。

java.lang.Math 类定义了 PI 常量和许多静态方法,包括用于计算正弦、余弦、正切、平方根、最大值、最小值、指数等的方法。例如,

public static final double PI 
    = 3.141592653589793;
public static double cos(double a)
{
    ...
}

通常,要从另一个类中使用这些对象,你需要添加类名前缀,如下所示。

double r = Math.cos(Math.PI * theta);

使用静态导入语句可以导入 java.lang.Math 的静态成员,这样就不需要在类名Math前加前缀了。Math的静态成员可以单独导入:

import static java.lang.Math.PI;

或者作为一个组:

import static java.lang.Math.*;

一旦它们被导入,静态成员可以无需限定地使用。例如,前面的代码片段将变为:

double r = cos(PI * theta);

显然,你可以编写自己的类,其中包含你经常使用的常量和静态方法,然后使用静态导入语句。例如,

import static mypackage.MyConstants.*;

注意: 静态导入要非常谨慎使用。过度使用静态导入会导致代码难以阅读和维护,因为代码读者无法知道哪个类定义了特定的静态对象。正确使用静态导入可以通过消除类名重复使代码更易读。


管理源文件和类文件

原文:docs.oracle.com/javase/tutorial/java/package/managingfiles.html

Java 平台的许多实现依赖于分层文件系统来管理源文件和类文件,尽管Java 语言规范并不要求这样做。策略如下。

将一个类、接口、枚举或注解类型的源代码放在一个文本文件中,文件名为类型的简单名称,扩展名为.java。例如:

//in the Rectangle.java file 
package graphics;
public class Rectangle {
   ... 
}

然后,将源文件放在一个反映类型所属包名的目录中:

.....\graphics\Rectangle.java

包成员的限定名称和文件的路径名称是平行的,假设使用 Microsoft Windows 文件名分隔符反斜杠(对于 UNIX,请使用正斜杠)。

  • 类名graphics.Rectangle
  • 文件路径graphics\Rectangle.java

正如你应该记得的那样,按照惯例,公司使用其反转的互联网域名作为其包名。例如,其互联网域名为example.com的 Example 公司将在其所有包名之前加上com.example。包名的每个组件对应一个子目录。因此,如果 Example 公司有一个包含Rectangle.java源文件的com.example.graphics包,它将包含在一系列子目录中,如下所示:

....\com\example\graphics\Rectangle.java

当你编译一个源文件时,编译器为其中定义的每个类型创建一个不同的输出文件。输出文件的基本名称是类型的名称,其扩展名是.class。例如,如果源文件如下所示

//in the Rectangle.java file
package com.example.graphics;
public class Rectangle {
      . . . 
}
class Helper{
      . . . 
}

然后编译后的文件将位于:

<path to the parent directory of the output files>\com\example\graphics\Rectangle.class
<path to the parent directory of the output files>\com\example\graphics\Helper.class

.java源文件一样,编译后的.class文件应该在反映包名的一系列目录中。然而,.class文件的路径不一定要与.java源文件的路径相同。你可以将源文件和类文件目录分开管理,如:

<path_one>\sources\com\example\graphics\Rectangle.java
<path_two>\classes\com\example\graphics\Rectangle.class

Java 中文官方教程 2022 版(七)(2)https://developer.aliyun.com/article/1486321

相关文章
|
4天前
|
前端开发 Java Maven
【前端学java】全网最详细的maven安装与IDEA集成教程!
【8月更文挑战第12天】全网最详细的maven安装与IDEA集成教程!
21 2
【前端学java】全网最详细的maven安装与IDEA集成教程!
|
9天前
|
存储 网络协议 Oracle
java教程
java教程【8月更文挑战第11天】
14 5
|
1月前
|
SQL 安全 Java
「滚雪球学Java」教程导航帖(更新2024.07.16)
《滚雪球学Spring Boot》是一个面向初学者的Spring Boot教程,旨在帮助读者快速入门Spring Boot开发。本专通过深入浅出的方式,将Spring Boot开发中的核心概念、基础知识、实战技巧等内容系统地讲解,同时还提供了大量实际的案例,让读者能够快速掌握实用的Spring Boot开发技能。本书的特点在于注重实践,通过实例学习的方式激发读者的学习兴趣和动力,并引导读者逐步掌握Spring Boot开发的实际应用。
42 1
「滚雪球学Java」教程导航帖(更新2024.07.16)
WXM
|
25天前
|
Oracle Java 关系型数据库
Java JDK下载安装及环境配置超详细图文教程
Java JDK下载安装及环境配置超详细图文教程
WXM
129 3
|
1月前
|
测试技术 API Android开发
《手把手教你》系列基础篇(九十七)-java+ selenium自动化测试-框架设计篇-Selenium方法的二次封装和页面基类(详解教程)
【7月更文挑战第15天】这是关于自动化测试框架中Selenium API二次封装的教程总结。教程中介绍了如何设计一个支持不同浏览器测试的页面基类(BasePage),该基类包含了对Selenium方法的二次封装,如元素的输入、点击、清除等常用操作,以减少重复代码。此外,页面基类还提供了获取页面标题和URL的方法。
44 2
|
1月前
|
Web App开发 XML Java
《手把手教你》系列基础篇(九十六)-java+ selenium自动化测试-框架之设计篇-跨浏览器(详解教程)
【7月更文挑战第14天】这篇教程介绍了如何使用Java和Selenium构建一个支持跨浏览器测试的自动化测试框架。设计的核心是通过读取配置文件来切换不同浏览器执行测试用例。配置文件中定义了浏览器类型(如Firefox、Chrome)和测试服务器的URL。代码包括一个`BrowserEngine`类,它初始化配置数据,根据配置启动指定的浏览器,并提供关闭浏览器的方法。测试脚本`TestLaunchBrowser`使用`BrowserEngine`来启动浏览器并执行测试。整个框架允许在不同浏览器上运行相同的测试,以确保兼容性和一致性。
47 3
|
1月前
|
存储 Web App开发 Java
《手把手教你》系列基础篇(九十五)-java+ selenium自动化测试-框架之设计篇-java实现自定义日志输出(详解教程)
【7月更文挑战第13天】这篇文章介绍了如何在Java中创建一个简单的自定义日志系统,以替代Log4j或logback。
135 5
|
1月前
|
Java 数据安全/隐私保护
Java无模版导出Excel 0基础教程
经常写数据导出到EXCEL,没有模板的情况下使用POI技术。以此作为记录,以后方便使用。 2 工具类 样式工具: 处理工具Java接口 水印工具 导出Excel工具类 3 测试代码 与实际复杂业务不同 在此我们只做模拟 Controller Service 4 导出测试 使用Postman进行接口测试,没接触过Postman的小伙伴可以看我这篇博客Postman导出excel文件保存为文件可以看到导出很成功,包括水印 sheet页名称自适应宽度。还有一些高亮……等功能可以直接搜索使用
Java无模版导出Excel 0基础教程
|
1月前
|
设计模式 测试技术 Python
《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
【7月更文挑战第10天】Page Object Model (POM)是Selenium自动化测试中的设计模式,用于提高代码的可读性和维护性。POM将每个页面表示为一个类,封装元素定位和交互操作,使得测试脚本与页面元素分离。当页面元素改变时,只需更新对应页面类,减少了脚本的重复工作和维护复杂度,有利于团队协作。POM通过创建页面对象,管理页面元素集合,将业务逻辑与元素定位解耦合,增强了代码的复用性。示例展示了不使用POM时,脚本直接混杂了元素定位和业务逻辑,而POM则能解决这一问题。
43 6
|
1月前
|
设计模式 Java 测试技术
《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
【7月更文挑战第12天】在本文中,作者宏哥介绍了如何在不使用PageFactory的情况下,用Java和Selenium实现Page Object Model (POM)。文章通过一个百度首页登录的实战例子来说明。首先,创建了一个名为`BaiduHomePage1`的页面对象类,其中包含了页面元素的定位和相关操作方法。接着,创建了测试类`TestWithPOM1`,在测试类中初始化WebDriver,设置驱动路径,最大化窗口,并调用页面对象类的方法进行登录操作。这样,测试脚本保持简洁,遵循了POM模式的高可读性和可维护性原则。
27 2