<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path> </svg> <blockquote>
讯享网
原文:
原文:
要声明一个实现接口的类,你需要在类声明中包含一个子句。你的类可以实现多个接口,因此关键字后面跟着一个逗号分隔的接口列表。按照惯例,如果有子句,则子句跟在其后。
考虑一个定义如何比较对象大小的接口。
讯享网
如果你想要比较相似对象的大小,无论它们是什么,实例化它们的类应该实现。
任何类都可以实现,只要有一种方法可以比较从该类实例化的对象的相对“大小”。对于字符串,可以是字符数;对于书籍,可以是页数;对于学生,可以是体重;等等。对于平面几何对象,面积是一个不错的选择(参见下面的类),而对于三维几何对象,体积也可以工作。所有这些类都可以实现方法。
如果你知道一个类实现了,那么你就知道可以比较从该类实例化的对象的大小。
这里是在创建对象部分中介绍的类,重写以实现。
因为实现了,所以可以比较任意两个对象的大小。
注意: 在接口中定义的方法接受一个类型的对象。在前面的示例中加粗显示的代码行将强制转换为实例。类型转换告诉编译器对象的真实类型。直接在实例上调用()将无法编译通过,因为编译器不知道实际上是的实例。
原文:
当你定义一个新接口时,你正在定义一个新的引用数据类型。你可以在任何可以使用其他数据类型名称的地方使用接口名称。如果你定义一个类型为接口的引用变量,那么你分配给它的任何对象必须是实现了该接口的类的实例。
举例来说,这里有一种方法可以找到一对对象中最大的对象,适用于任何从实现了接口的类实例化的对象:
讯享网
通过将强制转换为类型,它可以调用方法。
如果你坚持在各种类中实现,那么从任何这些类实例化的对象都可以使用方法进行比较——前提是这两个对象属于同一类。同样,它们也可以使用以下方法进行比较:
这些方法适用于任何“可比较”的对象,无论它们的类继承关系如何。当它们实现了接口时,它们可以是自己类(或超类)类型和类型。这使它们具有多重继承的一些优势,可以同时具有来自超类和接口的行为。
原文:
考虑您开发的名为的接口:
讯享网
假设以后,您想要向添加第三个方法,使接口现在变成:
如果您进行此更改,则所有实现旧接口的类都将中断,因为它们不再实现旧接口。依赖于此接口的程序员将会强烈**。
尽量预见接口的所有用途并从一开始完全指定它。如果要向接口添加其他方法,您有几个选项。您可以创建一个扩展的接口:
讯享网
现在,您的代码用户可以选择继续使用旧接口或升级到新接口。
或者,您可以将新方法定义为默认方法。以下示例定义了一个名为的默认方法:
请注意,您必须为默认方法提供实现。您还可以为现有接口定义新的静态方法。实现增强了新默认或静态方法的接口的类的用户无需修改或重新编译它们以适应额外的方法。
原文:
接口部分描述了一个涉及计算机控制汽车制造商发布行业标准接口的示例,描述了可以调用哪些方法来操作他们的汽车。如果这些计算机控制汽车制造商为他们的汽车添加新功能,比如飞行,会怎么样?这些制造商需要指定新的方法来使其他公司(如电子导航仪制造商)能够调整他们的软件以适应飞行汽车。这些汽车制造商会在哪里声明这些新的与飞行相关的方法?如果他们将它们添加到原始接口中,那么已经实现这些接口的程序员将不得不重新编写他们的实现。如果将它们添加为静态方法,那么程序员会将它们视为实用方法,而不是必要的核心方法。
默认方法使您能够向库的接口添加新功能,并确保与为旧版本接口编写的代码的二进制兼容性。
考虑下面的接口,,如问题和练习的答案:接口中所述:
讯享网
下面的类,,实现了:
假设您想要向接口添加新功能,比如通过对象(类似于对象,但它存储时区信息)指定时区的能力:
讯享网
对接口进行这种修改后,您还需要修改类并实现方法。但是,与其将留空(如前面的例子中),您可以定义一个默认实现。(请记住,抽象方法是声明而没有实现的方法。)
您可以在接口中的方法签名开头使用关键字来指定一个方法定义是默认方法。接口中的所有方法声明,包括默认方法,都隐式地是的,因此您可以省略修饰符。
使用这个接口,你不需要修改类,而这个类(以及任何实现接口的类)将已经定义好方法。下面的例子,,调用了实例的方法:
讯享网
当您扩展包含默认方法的接口时,可以执行以下操作:
- 完全不提及默认方法,让您扩展的接口继承默认方法。
- 重新声明默认方法,使其为。
- 重新定义默认方法,覆盖它。
假设您扩展了接口如下:
任何实现接口的类都将具有默认方法指定的实现。
假设您扩展了接口如下:
讯享网
任何实现接口的类都必须实现方法;这个方法是一个方法,就像接口中的所有其他非默认(非静态)方法一样。
假设您扩展了接口如下:
任何实现接口的类都将使用此接口指定的实现,而不是接口指定的实现。
除了默认方法之外,您还可以在接口中定义静态方法。(静态方法是与定义它的类相关联的方法,而不是与任何对象相关联的方法。类的每个实例共享其静态方法。)这使您更容易在库中组织辅助方法;您可以将特定于接口的静态方法保留在同一接口中,而不是在单独的类中。以下示例定义了一个静态方法,用于检索与时区标识符对应的对象;如果没有与给定标识符对应的对象,则使用系统默认时区。(因此,您可以简化方法):
讯享网
就像类中的静态方法一样,您可以在接口中的方法定义之前使用关键字指定一个方法是静态方法。接口中的所有方法声明,包括静态方法,都隐式为,因此您可以省略修饰符。
默认方法使您可以向现有接口添加新功能,并确保与为旧版本接口编写的代码具有二进制兼容性。特别是,默认方法使您可以向现有接口添加接受 lambda 表达式作为参数的方法。本节演示了如何通过默认方法和静态方法增强了接口。
将和类视为问题和练习:类中描述的那样。此示例将和类重写为接口。接口包含两个类型(和)和两个抽象方法(和):
接口包含各种操作牌组中卡片的方法:
讯享网
类实现了接口,而类实现了接口。
类按如下方式实现了抽象方法:
方法对实现接口的元素类型为的实例进行排序。成员是一个的实例,其元素类型为扩展了的类型。类按如下方式实现了方法:
讯享网
方法导致方法首先按花色,然后按等级对牌组进行排序。
如果你想先按等级,然后按花色对牌组进行排序怎么办?你需要实现接口来指定新的排序标准,并使用方法(包含参数的方法版本)。你可以在类中定义以下方法:
有了这个方法,你可以指定方法如何对类的实例进行排序。一种方法是实现接口来指定你希望如何对牌进行排序。示例就是这样做的:
讯享网
以下调用首先按等级,然后按花色对扑克牌组进行排序:
然而,这种方法太啰嗦了;如果你可以只指定排序标准而避免创建多个排序实现,那将更好。假设你是编写接口的开发人员。你可以向接口添加哪些默认或静态方法,以使其他开发人员更容易指定排序标准?
首先,假设你想按等级对扑克牌组进行排序,而不考虑花色。你可以如下调用方法:
讯享网
因为接口是一个函数式接口,您可以使用 lambda 表达式作为方法的参数。在这个例子中,lambda 表达式比较两个整数值。
如果您的开发人员只需调用方法就能创建一个实例,那将更简单。特别是,如果您的开发人员可以创建一个比较任何可以从或等方法返回数值的对象的实例,那将很有帮助。接口已经通过静态方法增强了这种能力:
在这个例子中,您可以使用方法引用:
讯享网
这种调用更好地演示了如何指定不同的排序标准并避免创建多个排序实现。
接口已经通过其他版本的静态方法(如和)进行了增强,使您能够创建比较其他数据类型的实例。
假设您的开发人员想要创建一个可以根据多个标准比较对象的实例。例如,如何先按等级,然后按花色对扑克牌进行排序?与以前一样,您可以使用 lambda 表达式来指定这些排序标准:
如果您的开发人员可以从一系列实例构建一个实例,那将更简单。接口已经通过默认方法增强了这种能力:
讯享网
接口已经通过其他版本的默认方法(如和)进行了增强,使您能够构建比较其他数据类型的实例。
假设您的开发人员想要创建一个实例,使他们能够以相反的顺序对对象集合进行排序。例如,如何按照牌面从大到小的顺序对扑克牌进行排序,从 A 到 2(而不是从 2 到 A)?与以前一样,您可以指定另一个 lambda 表达式。但是,如果开发人员可以通过调用方法来反转现有的,那将更简单。接口已经通过默认方法增强了这种能力:
这个例子演示了如何通过默认方法、静态方法、lambda 表达式和方法引用增强了接口,以创建更具表现力的库方法,程序员可以通过查看它们的调用方式快速推断出其功能。使用这些构造来增强您的库中的接口。
接口声明可以包含方法签名、默认方法、静态方法和常量定义。唯一有实现的方法是默认方法和静态方法。
实现接口的类必须实现接口中声明的所有方法。
接口名称可以在任何需要类型的地方使用。
原文:
- 一个实现接口的类需要实现哪些方法?
- 以下接口有什么问题?
讯享网
- 修复问题 2 中的接口。
- 以下接口是否有效?
- 编写一个实现包中接口的类。你的实现应该将字符串倒序返回。从本书中选择一句话作为数据。编写一个小的方法来测试你的类;确保调用所有四个方法。
- 假设你已经编写了一个定期通知其客户端当前日期和时间的时间服务器。编写一个接口,服务器可以使用它来强制执行特定的协议。
检查你的答案。
原文:
在前面的课程中,您已经多次看到继承的提及。在 Java 语言中,类可以从其他类派生,从而继承那些类的字段和方法。
定义: 从另一个类派生的类称为子类(也称为派生类、扩展类或子类)。从子类派生的类称为超类(也称为基类或父类)。
除了没有超类之外,每个类只有一个直接超类(单继承)。在没有其他显式超类的情况下,每个类都隐式地是的子类。
类可以从派生自其他类的类派生,而这些类又从其他类派生,依此类推,最终都是从顶级类派生而来。这样的类被称为继承自继承链中一直延伸到的所有类。
继承的概念简单而强大:当您想要创建一个新类,并且已经有一个包含您想要的一些代码的类时,您可以从现有类派生您的新类。通过这样做,您可以重用现有类的字段和方法,而无需自己编写(和调试!)它们。
子类从其超类继承所有成员(字段、方法和嵌套类)。构造函数不是成员,因此它们不会被子类继承,但是可以从子类中调用超类的构造函数。
类,定义在包中,定义并实现了所有类共有的行为,包括您编写的类。在 Java 平台中,许多类直接从派生,其他类从其中一些类派生,依此类推,形成一个类的层次结构。
Java 平台中的所有类都是 Object 的子类
在层次结构的顶部,是所有类中最通用的类。层次结构底部附近的类提供更专业化的行为。
这是一个可能实现的类的示例代码,该代码在类和对象课程中提供:
讯享网
一个类的类声明,它是的子类,可能如下所示:
继承了的所有字段和方法,并添加了字段和一个设置它的方法。除了构造函数外,就好像你完全从头开始编写了一个新的类,有四个字段和五个方法。但是,你不必做所有的工作。如果类中的方法很复杂并且花费了大量时间来调试,这将特别有价值。
子类继承其父类的所有public和protected成员,无论子类位于何种包中。如果子类与其父类在同一包中,它还会继承父类的package-private成员。你可以直接使用继承的成员,替换它们,隐藏它们,或者用新成员补充它们:
- 继承的字段可以直接使用,就像任何其他字段一样。
- 你可以在子类中声明一个与超类中相同名称的字段,从而隐藏它(不建议)。
- 你可以在子类中声明超类中没有的新字段。
- 继承的方法可以直接使用。
- 你可以在子类中编写一个新的实例方法,其签名与超类中的方法相同,从而覆盖它。
- 你可以在子类中编写一个新的静态方法,其签名与超类中的方法相同,从而隐藏它。
- 你可以在子类中声明超类中没有的新方法。
- 你可以编写一个子类构造函数,隐式地或使用关键字调用超类的构造函数。
本课程的以下部分将扩展这些主题。
子类不继承其父类的成员。但是,如果超类有用于访问其私有字段的公共或受保护方法,子类也可以使用这些方法。
嵌套类可以访问其封闭类的所有私有成员—包括字段和方法。因此,一个由子类继承的公共或受保护的嵌套类间接访问了超类的所有私有成员。
我们已经看到,一个对象的数据类型是它实例化的类的数据类型。例如,如果我们写
讯享网
那么的类型是。
是从和继承而来的。因此,是一个,也是一个,可以在需要或对象的任何地方使用。
反之未必成立:可能是,但不一定。同样,可能是或,但不一定。
转型展示了在继承和实现允许的对象之间使用一个类型的对象代替另一个类型的对象。例如,如果我们写
那么既是一个,也是一个(直到被分配为不是的另一个对象为止)。这被称为隐式转换。
另一方面,如果我们写
讯享网
我们会得到一个编译时错误,因为编译器不知道是一个。然而,我们可以告诉编译器,我们承诺将一个分配给,通过显式转换:
这个转换插入了一个运行时检查,以确保被分配为,这样编译器可以安全地假定是一个。如果在运行时不是,则会抛出异常。
注意: 您可以使用运算符对特定对象的类型进行逻辑测试。这可以避免由于不正确的转换而导致运行时错误。例如:
讯享网
这里的运算符验证指向一个,这样我们可以进行转换,并确保不会抛出运行时异常。
原文:
类和接口之间的一个重要区别是类可以有字段,而接口不能。此外,您可以实例化一个类来创建一个对象,而接口不能这样做。正如在什么是对象?一节中所解释的,对象将其状态存储在字段中,这些字段在类中定义。Java 编程语言不允许您扩展多个类的一个原因是为了避免状态的多重继承问题,即从多个类继承字段的能力。例如,假设您能够定义一个新类,该类扩展多个类。当您通过实例化该类创建对象时,该对象将从所有超类继承字段。如果不同超类的方法或构造函数实例化相同字段会怎样?哪个方法或构造函数将优先?由于接口不包含字段,您不必担心由于状态的多重继承而导致的问题。
实现的多重继承是从多个类继承方法定义的能力。这种类型的多重继承会引发问题,例如名称冲突和模糊性。当支持这种类型多重继承的编程语言的编译器遇到包含相同名称方法的超类时,有时无法确定要访问或调用哪个成员或方法。此外,程序员可能会通过向超类添加新方法无意中引入名称冲突。默认方法引入了一种实现的多重继承形式。一个类可以实现多个接口,这些接口可以包含具有相同名称的默认方法。Java 编译器提供了一些规则来确定特定类使用哪个默认方法。
Java 编程语言支持类型的多重继承,即一个类可以实现多个接口的能力。一个对象可以有多种类型:它自己类的类型以及类实现的所有接口的类型。这意味着如果一个变量声明为接口的类型,那么它的值可以引用任何实例化自实现该接口的任何类的对象。这在将接口用作类型一节中讨论。
与多重继承实现一样,一个类可以继承在其扩展的接口中定义的方法的不同实现(作为默认或静态)。在这种情况下,编译器或用户必须决定使用哪一个。
原文:
子类中具有与超类中实例方法相同签名(名称,以及其参数的数量和类型)和返回类型的实例方法覆盖了超类的方法。
子类覆盖方法的能力允许一个类从一个行为“足够接近”的超类继承,然后根据需要修改行为。覆盖方法具有与其覆盖的方法相同的名称、参数数量和类型以及返回类型。覆盖方法还可以返回被覆盖方法返回类型的子类型。这个子类型被称为协变返回类型。
在覆盖方法时,您可能希望使用注解,指示编译器您打算覆盖超类中的方法。如果由于某种原因,编译器检测到该方法在任何一个超类中不存在,则会生成一个错误。有关的更多信息,请参见。
如果一个子类定义了一个与超类中静态方法相同签名的静态方法,则子类中的方法隐藏超类中的方法。
隐藏静态方法和覆盖实例方法之间的区别具有重要的影响:
- 调用的覆盖实例方法的版本是在子类中的版本。
- 调用的隐藏静态方法的版本取决于它是从超类还是从子类调用的。
考虑一个包含两个类的示例。第一个是,包含一个实例方法和一个静态方法:
第二个类,,是的一个子类:
讯享网
类覆盖了中的实例方法,并隐藏了中的静态方法。这个类中的方法创建了一个的实例,并在类上调用,在实例上调用。
这个程序的输出如下:
如约定,调用的隐藏静态方法的版本是在超类中的版本,调用的覆盖实例方法的版本是在子类中的版本。
默认方法和抽象方法在接口中像实例方法一样被继承。然而,当一个类或接口的超类型提供了多个具有相同签名的默认方法时,Java 编译器遵循继承规则来解决名称冲突。这些规则受以下两个原则驱动:
- 实例方法优先于接口默认方法。
考虑以下类和接口:
讯享网
讯享网
方法返回字符串
- 已经被其他候选方法覆盖的方法将被忽略。当超类型共享一个共同的祖先时,就会出现这种情况。
考虑以下接口和类:
讯享网
讯享网
方法返回字符串
如果两个或更多独立定义的默认方法冲突,或者默认方法与抽象方法冲突,则 Java 编译器会产生编译错误。您必须显式覆盖超类型方法。
考虑一下关于现在可以飞行的计算机控制汽车的例子。您有两个接口(和),它们为相同方法()提供默认实现:
讯享网
实现和的类必须覆盖方法。您可以使用关键字调用任何默认实现中的任何一个。
讯享网
在之前的名称(在本例中为或)必须引用直接定义或继承了被调用方法的超接口。这种形式的方法调用不仅限于区分包含具有相同签名的默认方法的多个实现接口。您可以使用关键字在类和接口中调用默认方法。
从类中继承的实例方法可以覆盖抽象接口方法。考虑以下接口和类:
讯享网
方法返回字符串 类继承自类的方法,该方法覆盖了接口中同名的抽象方法。
注意:接口中的静态方法不会被继承。
覆盖方法的访问修饰符可以允许更多的访问权限,但不能少于被覆盖方法的访问权限。例如,超类中的受保护实例方法可以在子类中变为公共方法,但不能变为私有方法。
如果您尝试将超类中的实例方法更改为子类中的静态方法,或者反之,则会收到编译时错误。
以下表格总结了当您定义一个与超类中方法具有相同签名的方法时会发生什么。
定义一个与超类方法具有相同签名的方法
注意:在子类中,您可以重载从超类继承的方法。这样重载的方法既不隐藏也不覆盖超类实例方法——它们是子类独有的新方法。
原文:
多态性的词典定义指的是生物学中的一个原则,即一个生物体或物种可以具有许多不同的形式或阶段。这个原则也可以应用于面向对象编程和像 Java 语言这样的语言中。类的子类可以定义自己独特的行为,同时共享父类的一些功能。
多态性可以通过对类进行微小修改来演示。例如,可以向类中添加一个方法,该方法显示实例中当前存储的所有数据。
讯享网
要在 Java 语言中演示多态特性,请使用和类扩展类。对于,添加一个字段,这是一个值,指示自行车是否有前减震器,。或者,自行车有前后减震器,。
这是更新后的类:
请注意覆盖的方法。除了之前提供的信息外,输出还包括有关悬架的额外数据。
接下来,创建类。因为公路或赛车自行车有细轮胎,所以添加一个属性来跟踪轮胎宽度。这是类:
讯享网
请注意,方法再次被覆盖。这次,显示了有关轮胎宽度的信息。
总结一下,有三个类:,和。这两个子类覆盖了方法并打印了独特的信息。
这是一个创建三个变量的测试程序。每个变量分配给三个自行车类中的一个。然后打印每个变量。
以下是测试程序的输出:
讯享网
Java 虚拟机(JVM)调用与每个变量引用的对象相对应的方法。它不调用变量类型定义的方法。这种行为称为虚拟方法调用,展示了 Java 语言中重要的多态性特性的一个方面。
原文:
在一个类中,如果一个字段与超类中的字段同名,即使它们的类型不同,该字段也会隐藏超类的字段。在子类中,无法通过简单名称引用超类中的字段。相反,必须通过来访问该字段,这将在下一节中介绍。一般来说,我们不建议隐藏字段,因为这会使代码难以阅读。
原文:
如果您的方法覆盖了其超类的方法之一,您可以通过关键字调用被覆盖的方法。您还可以使用来引用隐藏字段(尽管不建议隐藏字段)。考虑这个类,:
这里是一个名为的子类,覆盖了:
讯享网
在中,简单名称指的是在中声明的那个,它覆盖了中的那个。因此,要引用从继承的,必须使用一个限定名称,使用如所示。编译和执行将打印以下内容:
以下示例说明了如何使用关键字调用超类的构造函数。回想一下示例中是的子类。这是(子类)构造函数,它调用超类构造函数,然后添加自己的初始化代码:
讯享网
调用超类构造函数必须是子类构造函数中的第一行。
调用超类构造函数的语法是
或者:
讯享网
使用时,将调用超类的无参数构造函数。使用时,将调用具有匹配参数列表的超类构造函数。
注意:如果构造函数没有显式调用超类的构造函数,Java 编译器会自动插入对超类的无参数构造函数的调用。如果超类没有无参数构造函数,您将会得到一个编译时错误。确实有这样一个构造函数,所以如果是唯一的超类,就不会有问题。
如果子类构造函数显式或隐式地调用其超类的构造函数,您可能会认为会有一整个构造函数链被调用,一直回溯到的构造函数。事实上,情况确实如此。这被称为构造函数链,当存在长串的类继承时,您需要注意这一点。
原文:
类,位于包中,位于类层次结构树的顶部。每个类都是类的后代,直接或间接的。你使用或编写的每个类都继承了的实例方法。你不需要使用这些方法中的任何一个,但是如果选择这样做,可能需要用特定于你的类的代码重写它们。本节讨论的从继承的方法有:
-
创建并返回此对象的副本。
-
指示某个其他对象是否"等于"这个对象。
-
垃圾回收器在对象上调用的方法
集合确定没有更多引用指向该对象
-
返回对象的运行时类。
-
为对象返回一个哈希码值。
-
返回对象的字符串表示形式。
的、和方法在程序中独立运行的线程的活动同步中起着作用,这将在后面的课程中讨论,这里不会涉及。这些方法有五个:
注意: 这些方法中有一些微妙的方面,特别是方法。
如果一个类或其父类实现了接口,你可以使用方法从现有对象创建一个副本。要创建一个克隆,你需要编写:
的这个方法的实现会检查调用的对象是否实现了接口。如果对象没有实现,该方法会抛出一个异常。异常处理将在后面的课程中介绍。目前,你需要知道必须声明为
讯享网
或:
如果你要编写一个方法来覆盖中的方法。
如果调用的对象确实实现了接口,的方法的实现会创建一个与原始对象相同类的对象,并初始化新对象的成员变量为与原始对象对应的成员变量相同的值。
使你的类可克隆的最简单方法是在类的声明中添加,然后你的对象可以调用方法。
对于一些类, 的 方法的默认行为就很好用。然而,如果一个对象包含对外部对象的引用,比如 ,你可能需要重写 来获得正确的行为。否则,一个对象对 的更改也会在其克隆中可见。这意味着原始对象和其克隆不是独立的—为了解耦它们,你必须重写 ,使其克隆对象和 。然后原始对象引用 ,而克隆引用 的克隆,这样对象和其克隆就是真正独立的。
方法用于比较两个对象是否相等,如果它们相等则返回 。 类中提供的 方法使用身份运算符 () 来确定两个对象是否相等。对于基本数据类型,这会给出正确的结果。然而,对于对象来说,这并不适用。 提供的 方法测试对象的引用是否相等—也就是说,如果比较的对象是完全相同的对象。
要测试两个对象是否在等价性意义上相等(包含相同的信息),你必须重写 方法。下面是一个重写 的 类的示例:

讯享网
考虑下面这段代码,用于测试 类的两个实例是否相等:
即使 和 引用了两个不同的对象,这个程序会显示 。它们被认为是相等的,因为比较的对象包含相同的 ISBN 号码。
如果身份运算符对于你的类不合适,你应该始终重写 方法。
注意:如果你重写了 ,你必须同时重写 。
类提供了一个回调方法 ,当对象变为垃圾时可能会被调用。 的 实现什么也不做—你可以重写 来进行清理,比如释放资源。
方法可能会被系统自动调用,但是何时调用,甚至是否调用都是不确定的。因此,不要依赖这个方法来清理资源。例如,如果在执行 I/O 操作后没有关闭文件描述符,并且期望 为您关闭它们,那么可能会耗尽文件描述符。相反,使用 -with 资源语句来自动关闭应用程序的资源。参见 The try-with-resources Statement 和 Finalization and Weak, Soft, and Phantom References 中的 Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide。
你不能重写 。
方法返回一个对象,该对象有一些方法可以获取关于类的信息,比如它的名称()、它的父类()和它实现的接口()。例如,下面的方法获取并显示对象的类名:
讯享网
类,位于包中,有大量的方法(超过 50 个)。例如,你可以测试类是否为注解()、接口()或枚举()。你可以查看对象的字段()或方法(),等等。
返回的值是对象的哈希码,是由哈希算法生成的整数值。
根据定义,如果两个对象相等,它们的哈希码也必须相等。如果你重写了方法,改变了两个对象相等的方式,那么的实现就不再有效。因此,如果你重写了方法,你也必须重写方法。
你应该始终考虑在你的类中重写方法。
的方法返回对象的表示,对于调试非常有用。对象的表示完全取决于对象本身,这就是为什么你需要在你的类中重写。
使用和可以显示对象的文本表示,比如的实例:
对于正确重写的方法,会打印出有用的信息,就像这样:
讯享网
原文:
你可以将类的一些或所有方法声明为最终。在方法声明中使用关键字表示该方法不能被子类重写。类就是这样做的——它的一些方法是的。
如果一个方法有一个不应该被更改的实现,并且对对象的一致状态至关重要,你可能希望将其设置为最终方法。例如,你可能想要将类中的方法设置为最终方法:
从构造函数中调用的方法通常应该声明为最终方法。如果构造函数调用一个非最终方法,子类可能重新定义该方法,导致意想不到或不希望的结果。
请注意,你也可以声明整个类为最终类。声明为最终类的类不能被子类化。例如,当创建像类这样的不可变类时,这是非常有用的。
原文:
抽象类 是一个声明为 的类—它可能包含或不包含抽象方法。抽象类不能被实例化,但可以被子类化。
抽象方法 是一种声明但没有实现的方法(没有大括号,后面跟着一个分号),如下所示:
讯享网
如果一个类包含抽象方法,那么这个类本身必须声明为 ,如下所示:
当一个抽象类被子类化时,子类通常为其父类中的所有抽象方法提供实现。但是,如果没有提供实现,则子类也必须声明为 。
注意: 接口 中的方法(参见 接口 部分)如果没有声明为默认或静态,则隐式是抽象的,因此不需要使用 修饰符。 (可以使用,但是不必要。)
抽象类类似于接口。你不能实例化它们,它们可能包含一些声明有或没有实现的方法。然而,使用抽象类,你可以声明非静态和非最终的字段,并定义公共、受保护和私有的具体方法。使用接口,所有字段都自动是公共的、静态的和最终的,你声明或定义的所有方法(作为默认方法)都是公共的。此外,你只能扩展一个类,无论它是否是抽象的,而你可以实现任意数量的接口。
你应该使用抽象类还是接口?
- 如果你的情况符合以下任何一种情况,请考虑使用抽象类:
- 你想在几个密切相关的类之间共享代码。
- 你期望扩展你的抽象类的类有许多共同的方法或字段,或者需要除了 public 之外的访问修饰符(比如 protected 和 private)。
- 你想声明非静态或非最终字段。这使你能够定义可以访问和修改它们所属对象状态的方法。
- 如果你的情况符合以下任何一种情况,请考虑使用接口:
- 你期望不相关的类会实现你的接口。例如, 和 这些接口被许多不相关的类实现。
- 你想指定特定数据类型的行为,但不关心谁实现它的行为。
- 你想利用类型的多重继承。
JDK 中抽象类的一个示例是,它是集合框架的一部分。它的子类(包括 、 和 )共享许多方法(包括 、、、 和 ),这些方法是由 定义的。
JDK 中实现多个接口的一个类的示例是,它实现了接口 、 和 。通过阅读这些接口列表,你可以推断出 的实例(无论是哪个开发者或公司实现的类)可以被克隆,是可序列化的(这意味着它可以被转换为字节流;参见可序列化对象部分),并且具有映射功能。此外, 接口已经通过许多默认方法(如 和 )进行了增强,而旧类实现了该接口的类不必定义这些方法。
请注意,许多软件库同时使用抽象类和接口; 类实现了多个接口,并且还扩展了抽象类 。
在面向对象的绘图应用程序中,你可以绘制圆、矩形、线条、贝塞尔曲线和许多其他图形对象。这些对象都具有某些状态(例如:位置、方向、线条颜色、填充颜色)和行为(例如:moveTo、rotate、resize、draw)是共同的。其中一些状态和行为对所有图形对象都是相同的(例如:位置、填充颜色和 moveTo)。其他需要不同实现(例如,resize 或 draw)。所有 必须能够自行绘制或调整大小;它们只是在如何执行这些操作上有所不同。这是一个抽象超类的完美情况。你可以利用相似之处,并声明所有图形对象都继承自相同的抽象父对象(例如 ),如下图所示。

类 Rectangle、Line、Bezier 和 Circle 继承自 GraphicObject
首先,声明一个抽象类 ,以提供所有子类完全共享的成员变量和方法,例如当前位置和 方法。 还声明了抽象方法,例如 或 ,这些方法需要所有子类实现,但必须以不同的方式实现。 类可能如下所示:
讯享网
每个非抽象子类 ,如 和 ,必须提供 和 方法的实现:
在部分中指出,实现接口的类必须实现所有接口的方法。然而,可以定义一个不实现所有接口方法的类,只要该类声明为。例如,
讯享网
在这种情况下,类必须是,因为它没有完全实现,但事实上,类实现了。
一个抽象类可能有字段和方法。您可以像使用其他类一样使用这些静态成员,通过类引用(例如,)。
原文:
除了类外,一个类只有一个直接的父类。一个类从所有直接或间接的父类那里继承字段和方法。子类可以重写继承的方法,或者隐藏继承的字段或方法。(请注意,隐藏字段通常是不良的编程实践。)
在覆盖和隐藏方法部分的表格显示了声明具有与超类中方法相同签名的方法的效果。
类是类层次结构的顶部。所有类都是从这个类继承的后代,并从中继承方法。从继承的有用方法包括,,和。
通过在类的声明中使用关键字,可以防止类被子类化。同样,通过将方法声明为最终方法,可以防止子类覆盖它。
抽象类只能被子类化;它不能被实例化。抽象类可以包含抽象方法—声明但未实现的方法。然后子类为抽象方法提供实现。
原文:
1. 考虑以下两个类:
a. 哪个方法覆盖了超类中的方法?
b. 哪个方法隐藏了超类中的方法?
c. 其他方法做什么?
2. 考虑你在问题和练习:类中编写的、和类。每个类应该覆盖哪些方法?
1. 编写你在问题 2 中回答的方法的实现。
检查你的答案。
原文:
这一部分从讨论类(位于包中)及其子类开始。特别是,本节讨论了在何种情况下您会使用这些类的实例化而不是原始数据类型。此外,本节还讨论了您可能需要与数字一起工作的其他类,例如格式化或使用数学函数来补充语言内置的运算符。最后,还讨论了自动装箱和拆箱,这是一种简化代码的编译器功能。
字符串在 Java 编程中被广泛使用,它们是字符序列。在 Java 编程语言中,字符串是对象。本节描述了使用类来创建和操作字符串。它还比较了和类。
原文:
本节开始讨论包中的类,它的子类,以及在何种情况下您会使用这些类的实例化而不是原始数字类型。
本节还介绍了和类,它们提供了用于编写格式化数字输出的方法。
最后,讨论了中的类。它包含了用于补充语言内置运算符的数学函数。该类具有三角函数、指数函数等方法。
原文:
在处理数字时,大多数情况下您会在代码中使用原始类型。例如:
讯享网
然而,有理由使用对象代替原始类型,并且 Java 平台为每种原始数据类型提供了包装类。这些类将原始类型“包装”在对象中。通常,编译器会执行包装操作—如果您在期望对象的地方使用原始类型,编译器会为您将原始类型装箱到其包装类中。同样,如果您在期望原始类型的地方使用数字对象,编译器会为您拆箱对象。有关更多信息,请参阅自动装箱和拆箱
所有数字包装类都是抽象类的子类:

注意: 还有四个的子类没有在此处讨论。和用于高精度计算。和用于多线程应用程序。
有三个原因可能会使用对象而不是原始类型:
- 作为期望对象的方法的参数(在操作数字集合时经常使用)。
- 要使用类定义的常量,如和,提供数据类型的上限和下限。
- 要使用类方法将值转换为其他原始类型,将值转换为字符串,以及在不同数字系统之间进行转换(十进制、八进制、十六进制、二进制)。
以下表格列出了所有类的子类实现的实例方法。
所有子类实现的方法
| `byte byteValue() short shortValue()
int intValue()
long longValue()
float floatValue()
double doubleValue()Number`对象的值转换为返回的原始数据类型。 |
| `int compareTo(Byte anotherByte) int compareTo(Double anotherDouble)
int compareTo(Float anotherFloat)
int compareTo(Integer anotherInteger)
int compareTo(Long anotherLong)
int compareTo(Short anotherShort)Number`对象与参数进行比较。 |
| | 确定此数字对象是否等于参数。如果参数不为且为相同类型且具有相同数值的对象,则方法返回。
对于和对象,还有一些额外的要求,这些要求在 Java API 文档中有描述。 |
每个类包含其他方法,用于将数字转换为字符串,以及在不同数字系统之间进行转换。以下表格列出了类中的这些方法。其他子类的方法类似:
转换方法,类
原文:
之前你看到了使用和方法将字符串打印到标准输出()的示例。由于所有数字都可以转换为字符串(稍后将会看到),你可以使用这些方法打印任意混合的字符串和数字。然而,Java 编程语言还有其他方法,允许你在包含数字时更好地控制打印输出。
包中包含一个类,其中有两个格式化方法可用于替换和。这些方法,和,是等效的。你一直在使用的熟悉的恰好是一个对象,因此你可以在上调用方法。因此,在你以前使用或的代码中,你可以使用或。例如,
这两个方法的语法是相同的:
讯享网
其中是一个指定要使用的格式化的字符串,是要使用该格式化打印的变量列表。一个简单的示例可能是
第一个参数,,是一个格式字符串,指定了第二个参数中的对象如何被格式化。格式字符串包含普通文本以及格式说明符,这些是特殊字符,用于格式化的参数。(的表示法称为可变参数,意味着参数的数量可能变化。)
格式说明符以百分号(%)开始,并以转换器结束。转换器是指示要格式化的参数类型的字符。在百分号(%)和转换器之间,你可以有可选的标志和说明符。有许多转换器、标志和说明符,这些都在中有文档记录。
这里是一个基本示例:
讯享网
指定单个变量为十进制整数。是一个与平台无关的换行符。输出为:
和方法是重载的。每个都有以下语法版本:
讯享网
例如,要在法国系统中打印数字(在英文浮点数表示中使用逗号代替小数点),你可以使用:
下表列出了在接下来的示例程序中使用的一些转换器和标志。
在中使用的转换器和标志
以下程序展示了您可以使用进行的一些格式化。输出在嵌入式注释中用双引号显示:
讯享网
注意: 本节讨论仅涵盖了和方法的基础知识。更详细的信息可以在基础教程的部分的“格式化”页面中找到。
使用创建字符串的方法在字符串中有介绍。
您可以使用类来控制前导和尾随零、前缀和后缀、分组(千位)分隔符以及小数点分隔符的显示。在数字格式化方面提供了很大的灵活性,但可能会使您的代码变得更加复杂。
接下来的示例创建了一个对象,通过将模式字符串传递给构造函数来创建。然后通过调用从继承的方法—它接受一个值作为参数,并以字符串形式返回格式化的数字:
这是一个演示使用的示例程序:
输出为:
讯享网
以下表格解释了每行输出。
输出
原文:
Java 编程语言支持基本算术运算,使用算术运算符:+,-,*,/和%。包中的类提供了更高级数学计算的方法和常量。
类中的方法都是静态的,因此您可以直接从类中调用它们,如下所示:
注意: 使用语言特性,您不必在每个数学函数前面写:
讯享网
这使您可以通过简单名称调用类的方法。例如:
类包括两个常量:
- ,即自然对数的底数,以及
- ,即圆周与直径的比值。
类还包括 40 多个静态方法。以下表格列出了一些基本方法。
基本数学方法
| `double abs(double d) float abs(float f)
int abs(int i)
| 返回参数的绝对值。 |
| `double min(double arg1, double arg2) float min(float arg1, float arg2)
int min(int arg1, int arg2)
| 返回两个参数中较小的值。 |
| `double max(double arg1, double arg2) float max(float arg1, float arg2)
int max(int arg1, int arg2)
| 返回两个参数中较大的值。 |
以下程序,,演示了如何使用其中一些方法:
讯享网
这个程序的输出如下:
下表列出了类的指数和对数方法。
指数和对数方法
下面的程序,,显示了的值,然后对任意选择的数字调用前面表中列出的每个方法:
讯享网
当你运行时,你将看到以下输出:
类还提供了一系列三角函数,总结在下表中。传递给这些方法的值是以弧度表示的角度。你可以使用方法将角度转换为弧度。
三角函数方法
这里有一个程序,,使用每个方法来计算 45 度角的各种三角函数值:
讯享网
该程序的输出如下:
方法返回一个在 0.0 和 1.0 之间伪随机选择的数字。范围包括 0.0 但不包括 1.0。换句话说:。要获得不同范围的数字,可以对随机方法返回的值进行算术运算。例如,要生成 0 到 9 之间的整数,你可以这样写:
讯享网
通过将值乘以 10,可能值的范围变为。
使用在需要生成单个随机数时效果很好。如果需要生成一系列随机数,应该创建一个的实例,并在该对象上调用方法来生成数字。
原文:
您可以使用包装类之一 - 、、、、 或 - 将原始类型的数字包装在对象中。在必要时,Java 编译器会自动为您包装(装箱)原始类型,并在必要时对其进行拆箱。
类包括常量和有用的类方法。 和 常量包含该类型对象可以包含的最小值和最大值。、 和类似方法将一个数值类型转换为另一个数值类型。 方法将字符串转换为数字, 方法将数字转换为字符串。
要格式化包含数字的字符串以进行输出,可以使用 类中的 或 方法。或者,您可以使用 类使用模式自定义数字格式。
类包含各种执行数学函数的类方法,包括指数、对数和三角函数方法。 还包括基本算术函数,如绝对值和四舍五入,以及用于生成随机数的 方法。
原文:
- 使用 API 文档找到以下问题的答案:
- 你可以使用哪个方法将转换为以十六进制表示数字的字符串?例如,哪个方法将整数 65 转换为字符串“41”?
- 你会使用哪个方法将以基数 5 表示的字符串转换为相应的?例如,如何将字符串“230”转换为整数值 65?展示你将用于完成此任务的代码。
- 你可以使用哪个 Double 方法来检测浮点数是否具有特殊值“非数字”()?
- 以下表达式的值是多少,为什么?
- 将更改为显示最小值而不是最大值。您可以删除与变量和相关的所有代码。输出是什么?
- 创建一个程序,从命令行读取未指定数量的整数参数并将它们相加。例如,假设您输入以下内容:
讯享网
程序应显示,然后退出。如果用户只输入一个参数,程序应显示错误消息。您可以基于编写您的程序。
- 创建一个类似于上一个程序但具有以下区别的程序:
- 它不是读取整数参数,而是读取浮点参数。
- 它显示参数的总和,小数点右侧正好有两位。
例如,假设您输入以下内容:
程序将显示。根据您的区域设置,小数点可能是逗号()而不是句号()。
检查你的答案。
原文:
大多数情况下,如果您使用单个字符值,您将使用原始的类型。例如:
讯享网
然而,有时您需要将 char 用作对象—例如,作为期望对象的方法参数。Java 编程语言提供了一个包装器类,用于将包装在对象中。类型的对象包含一个单一字段,其类型为。这个Character类还提供了许多有用的类(即静态)方法来操作字符。
您可以使用构造函数创建一个对象:
Java 编译器在某些情况下也会为您创建一个对象。例如,如果您将一个原始的传递给一个期望对象的方法,编译器会自动为您将转换为。这个特性被称为自动装箱—或者拆箱,如果转换是另一种方式的话。有关自动装箱和拆箱的更多信息,请参阅自动装箱和拆箱。
注意: 类是不可变的,一旦创建,对象就无法更改。
以下表列出了类中一些最有用的方法,但并非详尽无遗。要查看此类中所有方法的完整列表(超过 50 个),请参考java.lang.Character API 规范。
类中的有用方法
一个由反斜杠()引导的字符是一个转义序列,对编译器具有特殊含义。下表显示了 Java 转义序列:
转义序列
当在打印语句中遇到转义序列时,编译器会相应地解释它。例如,如果你想在引号内放置引号,你必须使用转义序列 来处理内部引号。要打印这个句子
讯享网
你需要写
原文:
在 Java 编程中广泛使用的字符串是一系列字符。在 Java 编程语言中,字符串是对象。
Java 平台提供了类来创建和操作字符串。
创建字符串的最直接方法是写:
讯享网
在这种情况下,是一个字符串字面值——代码中用双引号括起来的一系列字符。每当编译器在您的代码中遇到字符串字面值时,它会创建一个带有其值的对象——在本例中为。
与任何其他对象一样,您可以使用关键字和构造函数创建对象。类有十三个构造函数,允许您使用不同的来源(如字符数组)提供字符串的初始值:
此代码片段的最后一行显示。
注意:类是不可变的,因此一旦创建了对象,就无法更改。类有许多方法,其中一些将在下面讨论,看起来修改了字符串。由于字符串是不可变的,这些方法实际上是创建并返回一个包含操作结果的新字符串。
用于获取有关对象信息的方法称为访问器方法。您可以与字符串一起使用的一个访问器方法是方法,它返回字符串对象中包含的字符数。执行以下两行代码后,等于 17:
讯享网
回文是一个对称的单词或句子——它正向和反向拼写相同,忽略大小写和标点符号。这是一个简短且低效的程序来反转一个回文字符串。它调用了方法,该方法返回字符串中第 i 个字符,从 0 开始计数。
运行程序会产生以下输出:
讯享网
为了实现字符串反转,程序必须将字符串转换为字符数组(第一个循环),将数组反转为第二个数组(第二个循环),然后再转换回字符串。类包括一个方法,,用于将字符串或字符串的一部分转换为字符数组,以便我们可以用以下代码替换上面程序中的第一个循环
类包括一个用于连接两个字符串的方法:
讯享网
这将返回一个新字符串,其中在字符串 1 的末尾添加了字符串 2。
您还可以使用方法与字符串字面值,如:
字符串更常用地使用运算符连接,如
讯享网
这导致
运算符广泛用于语句中。例如:
讯享网
打印
这样的连接可以是任何对象的混合。对于每个不是的对象,都会调用它的方法将其转换为。
注意: Java 编程语言不允许文字字符串跨越多行出现在源文件中,因此您必须在多行字符串的每一行末尾使用连接运算符。例如:
讯享网
使用连接运算符在行之间断开字符串,在语句中再次非常常见。
您已经看到了使用和方法打印带有格式化数字的输出。类有一个等效的类方法,它返回一个对象而不是一个对象。
使用的静态方法允许您创建一个格式化的字符串,您可以重复使用,而不是一次性的打印语句。例如,而不是
你可以写
讯享网

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/164250.html