您的位置:首页 > 编程语言 > Java开发

java基础-嵌套类

2016-11-13 16:16 155 查看


在何处使用嵌套类

顾名思义,嵌套类(或内部类) 是在一个类中定义的另一个类。

像成员变量和方法一样,Java 类也可在任何范围内定义,包括
public
private
protected
。在想要以面向对象的方式执行类中的内部处理工作时,嵌套类可能很有用,但此功能仅限于需要它的类。

通常,在需要一个与定义它的类紧密耦合的类时,应该使用嵌套类。嵌套类能够访问包含它的类中的私有数据,但此结构会带来负面影响,这些影响在开始使用嵌套(或内部)类时并不明显。


嵌套类中的范围

因为嵌套类具有范围,所以它受范围规则约束。例如,可通过该类的实例(对象)访问成员变量。嵌套类也是如此。

假设一个
Manager
和一个名为
DirectReports
的嵌套类之间的关系为:后者是
Manager
下属的
Employee
的集合:

就像每个
Manager
对象表示唯一的人一样,
DirectReports
对象表示一位经理下属的真实的人(员工)的集合。
DirectReports
在不同
Manager
中不同。在本例中,应该仅在包含
DirectReports
嵌套类的
Manager
实例中引用它,所以我将它声明为
private


公共嵌套类

因为它是
private
,所以只有
Manager
可以创建
DirectReports
实例。但是,假设您想为一个外部实体提供创建
DirectReports
实例的能力。在这种情况下,似乎可为
DirectReports
类提供
public
范围,然后任何外部代码都可以创建
DirectReports
实例,如清单
1 所示。

清单 1. 创建
DirectReports
实例:第一次尝试


清单 1 中的代码不起作用,您可能想知道为什么会这样。问题(和它的解决方案)取决于在
Manager
中定义
DirectReports
的方式,以及范围规则。


理解范围规则

如果您拥有
Manager
的一个成员变量,您会认为编译器会要求您拥有
Manager
对象的引用,然后才能引用它,对吧?
DirectReports
也是如此,至少在 清单
1 中定义它时是这样。

要创建一个公共嵌套类的实例,需要使用
new
运算符的一个特殊版本。结合对一个外部类的封闭实例的引用,可使用
new
创建嵌套类的实例:

在第 12 行上可以注意到,该语法需要使用对封闭实例的引用,还要使用一个句点和
new
关键字,后跟想要创建的类。


静态内部类

有时,您希望创建一个(在概念上)与另一个类紧密耦合的类,但范围规则比较宽松,不需要使用对封闭实例的引用。这时静态 内部类就可以派上用场。一个常见的示例是实现一个
Comparator
,用它来比较同一个类的两个实例,通常用于对类进行排序:

在本例中,不需要使用封闭实例。静态内部类的行为与它们的对应常规 Java 类类似,而且仅应在需要将一个类与它的定义紧密耦合时使用它们。显然,对于像
ManagerComparator
这样的实用程序类,没有必要创建外部类,而且它们可能让您的代码库变得杂乱。将这些类定义为静态内部类是一种解决办法。


匿名内部类

使用 Java 语言,可在任何地方实现抽象类和接口,如果必要,甚至可在一个方法内实现,而且无需为类提供名称。此功能实际上是一种编译器窍门,但有时拥有匿名内部类很方便。

清单 2 是以 第 17 单元:接口 中的清单
1 中的示例为基础构建的,添加了一个处理不属于
StockOptionEligible
Employee
类型的默认方法。该清单首先提供了
HumanResourcesApplication
中的一个处理库存选项的方法,然后提供了一个驱动该方法的
JUnit 测试:

清单 2. 处理不属于
StockOptionEligible
Employee
类型


在清单 2 的示例中,我提供了两个使用匿名内部类的接口的实现。首先是
StockOptionEligible
的两个独立实现:一个用于
Employee
,另一个用于
Person
(以符合接口要求)。然后是一个
StockOptionProcessingCallback
实现,用于处理
Manager
实例的库存选项。

可能需要一定的时间才能掌握匿名内部类的概念,但它们非常方便。我一直在 Java 代码中使用它们。而且作为 Java 开发人员,随着您的不断进步,我相信您也会这么做。


测试您的理解情况

什么是嵌套类?

一个向应用程序中的其他类提供某种工具的类

一个在另一个类中定义的类

将一个或多个接口引用传入其构造方法的类

上述选项都不是

何时可以使用嵌套类?

当需要定义一个与另一个类(在功能上)紧密耦合的类时

当希望编写一个使用来自 JDK 的大量接口的类时

当一个类需要访问另一个类的私有数据,而您已超出了应用程序允许的最大类数量时

对于一个定义了超过 20 个方法且应重构的类

您能否找到以下代码中的错误?选择最佳答案,解释您的选择,并提供正确的代码。

类名
Outer
不是合法的 Java 类名。

类名
Inner
难以理解。

Outer
中定义的 main 方法的方法签名是错误的。

main() 中的
log.info()
调用了太多参数。

Inner
的主体是空的。

上述选项都不是。

参阅问题 3 中的代码清单。假设您在包含
Outer
的包中想要一个名为
AnotherOuter
且可以实例化
Outer.Inner
的新类。您需要对
Outer.Inner
的声明执行哪些更改?

没必要执行更改;
Inner
可按原样实例化。

没有内部类可包含它的类外部实例化。

Inner
的可视性更改为
protected
或包私有。

static
修饰符添加到
Inner
类声明中。

上述选项都不是。

给定以下框架,充实
main()
方法来执行以下操作:

实例化
Hello


调用
Hello
talk()
方法,向它传递一个实现为匿名内部类的
HelloCallback
实例

修改
sayHello()
的匿名内部类实现,以便使用
Hello
上定义的
Logger
来实现输出:

“This implementation says:”

whatToSay
字符串

能否编写一个可由您应用程序中的任何类(无论它位于哪个包中)实例化的内部类,而无需外部类的封闭实例?解释您的答案。

嵌套类与内部类有何区别?

内部类是仅使用私有访问级别定义的类,而嵌套类被声明为 static。

两个术语同义,可以交替使用。

嵌套类必须位于封闭类中,并在封闭类的任何变量之前声明。

嵌套类在 main() 中定义,而内部类可在任何地方定义。

不存在所谓的嵌套类。

上述选项都不是。

以下哪句有关内部类的描述是正确的?

内部类可访问包含它的类的任何私有数据变量,除非将它声明为
static


内部类必须声明为
public
,才能被封闭类以外的其他任何类实例化。

除非在特殊情况下,否则不允许使用静态内部类。

内部类对其封闭类完全不可见。

上述选项都不是。

答案:

什么是嵌套类?( b )

一个向应用程序中的其他类提供某种工具的类

一个在另一个类中定义的类

将一个或多个接口引用传入其构造方法的类

上述选项都不是

何时可以使用嵌套类?( a )

当需要定义一个与另一个类(在功能上)紧密耦合的类时

当希望编写一个使用来自 JDK 的大量接口的类时

当一个类需要访问另一个类的私有数据,而您已超出了应用程序允许的最大类数量时

对于一个定义了超过 20 个方法且应重构的类

您能否找到以下代码中的错误?选择最佳答案,解释您的选择,并提供正确的代码。( f )

package com.makotojava.intro.quiz;

import java.util.logging.Logger;

public class Outer {

private static final Logger log = Logger.getLogger(Outer.class.getName());

public void setInner(Inner inner) {
this.inner = inner;
}

private Inner inner;

public Inner getInner() {

return inner;
}

private class Inner {
}

public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = new Outer.Inner();
outer.setInner(inner);
log.info("Outer/Inner: " + outer.hashCode() + "/" + outer.getInner().hashCode());
}

}


类名
Outer
不是合法的
Java 类名。

类名
Inner
难以理解。

Outer
中定义的
main 方法的方法签名是错误的。

main() 中的
log.info()
调用了太多参数。

Inner
的主体是空的。

上述选项都不是。

解释:代码行
Inner inner
= new Outer.Inner();
是有错误的。对于引用 一个封闭类去实例化一个嵌套类的语法是不正确的。它应该是:
Inner
inner = outer.new Inner();


参阅问题 3 中的代码清单。假设您在包含
Outer
的包中想要一个名为
AnotherOuter
且可以实例化
Outer.Inner
的新类。您需要对
Outer.Inner
的声明执行哪些更改?(
c )

没必要执行更改;
Inner
可按原样实例化。

没有内部类可包含它的类外部实例化。

Inner
的可视性更改为
protected
或包私有。

static
修饰符添加到
Inner
类声明中。

上述选项都不是。

给定以下框架,充实
main()
方法来执行以下操作:

实例化
Hello


调用
Hello
talk()
方法,向它传递一个实现为匿名内部类的
HelloCallback
实例

修改
sayHello()
的匿名内部类实现,以便使用
Hello
上定义的
Logger
来实现输出:

“This implementation says:”

whatToSay
字符串

import java.util.logging.Logger;

public class Hello {

private static final Logger log = Logger.getLogger(Hello.class.getName());

interface HelloCallback {
void sayHello(String whatToSay);
}

public void talk(HelloCallback helloCallback) {
helloCallback.sayHello("Hello, world (how original :/)...");
}

public static void main(String[] args) {
Hello hello = new Hello();

hello.talk(new HelloCallback() {

@Override
public void sayHello(String whatToSay) {
log.info("This implementation says: " + whatToSay);
}

});
}

}


能否编写一个可由您应用程序中的任何类(无论它位于哪个包中)实例化的内部类,而无需外部类的封闭实例?解释您的答案。

答案:可以。内部类应该为修饰符
static
声明,并且
public
可见。然后在您应用程序的任何类都可以实例化内部类,无需外部类的
封闭实例。

嵌套类与内部类有何区别? ( b )

内部类是仅使用私有访问级别定义的类,而嵌套类被声明为 static。

两个术语同义,可以交替使用。

嵌套类必须位于封闭类中,并在封闭类的任何变量之前声明。

嵌套类在 main() 中定义,而内部类可在任何地方定义。

不存在所谓的嵌套类。

上述选项都不是。

以下哪句有关内部类的描述是正确的? ( a )

内部类可访问包含它的类的任何私有数据变量,除非将它声明为
static


内部类必须声明为
public
,才能被封闭类以外的其他任何类实例化。

除非在特殊情况下,否则不允许使用静态内部类。

内部类对其封闭类完全不可见。

上述选项都不是。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java