泛型ch15

泛型ch15
泛型ch15

写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。

在面向对象编程语言中,多态算是一种泛化机制。例如,你可以将方法的参数类型设为基类,那么该方法就可以接受从这个基类中导出的任何类作为参数。这样的方法更加通用一些,

类不能扩展,其他任何类都可以被扩展,

有时候,拘泥于单继承体系,也会使程序受限太多。如果方法的参数是一个接口,而不是617

可以不用参考C++。我也是尽力这样做的,除非,与C++的比较能够加深你的理解。

Java 中的泛型就需要与C++进行一番比较,理由有二:首先,了解C++模板的某些方面,有助于你理解泛型的基础。同时,非常重要的一点是,你可以了解Java 泛型的局限是什么,以及为什么会有这些限制。最终的目的是帮助你理解,Java 泛型的边界在哪里。根据我的经验,理解了边界所在,你才能成为程序高手。因为只有知道了某个技术不能做到什么,你才能更好地做到所能做的(部分原因是,不必浪费时间在死胡同里乱转)。

第二个原因是,在Java 社区中,人们普遍对C++模板有一种误解,而这种误解可能会误导你,令你在理解泛型的意图时产生偏差。

因此,在本章中会介绍一些C++模板的例子,不过我也会尽量控制它们的篇幅。

15.2 简单泛型

有许多原因促成了泛型的出现,而最引人注目的一个原因,就是为了创造容器类。(关于容器类,你可以参考第11章和第17章这两章。)容器,就是存放要使用的对象的地方。数组也是如此,不过与简单的数组相比,容器类更加灵活,具备更多不同的功能。事实上,所有的程序,在运行时都要求你持有一大堆对象,所以,容器类算得上最具重用性的类库之一。

我们先来看看一个只能持有单个对象的类。当然了,这个类可以明确指定其持有的对象的类型:不过,这个类的可重用性就不怎么样了,它无法持有其他类型的任何对象。我们可不希望为碰到的每个类型都编写一个新的类。在Java SE5之前,我们可以让这个类直接持有

Object 类型的对象:

现在,Holder2可以存储任何类型的对象,在这个例子中,只用了一个Holder2对象,却先后三次存储了三种不同类型的对象。有些情况下,我们确实希望容器能够同时持有多种类型的对象。但是,通常而言,我们只会使用容器来存储一种类型的对象。泛型的主要目的之一就是用来指定容器要持有什么类型的泛型353618619

对象,而且由编译器来保证类型的正确性。

因此,与其使用Object ,我们更喜欢暂时不指定类型,而是稍后再决定具体使用什么类型。要达到这个目的,需要使用类型参数,用尖括号括住,放在类名后面。然后在使用这个类的时候,再用实际的类型替换此类型参数。在下面的例子中,T 就是类型参数:现在,当你创建

Holder3对象时,必须指明想持有什么类型的对象,将其置于尖括号内。就像main()

中那样。然后,你就只能在Holder3中存入该类型(或其子类,因为多态与泛型不冲突)的对象了。并且,在你从

Holder3中取出它持有的对象时,自动地就是正确的类型。

这就是Java 泛型的核心概念:告诉编译器想使用什么类型,然后编译器帮你处理一切细节。一般而言,你可以认为泛型与其他的类型差不多,只不过它们碰巧有类型参数罢了。稍后

我们会看到,在使用泛型时,我们只需指定它们的名称以及类型参数列表即可。练习1:(1) 配合typeinfo.pets 类库,用Holder3来证明,如果指定Holder3可以持有某个基类类型,那么它也能持有导出类型。

练习2:(1) 创建一个Holder 类,使其能够持有具有相同类型的3个对象,并提供相应的读写方法访问这些对象,以及一个可以初始化其持有的3个对象的构造器。

15.2.1 一个元组类库

仅一次方法调用就能返回多个对象,你应该经常需要这样的功能吧。可是return 语句只允许返回单个对象,因此,解决办法就是创建一个对象,用它来持有想要返回的多个对象。当然,可以在每次需要的时候,专门创建一个类来完成这样的工作。可是有了泛型,我们就能够一次性地解决该问题,以后再也不用在这个问题上浪费时间了。同时,我们在编译期就能确保类型安全。

这个概念称为元组(tuple ),它是将一组对象直接打包存储于其中的一个单一对象。这个容器对象允许读取其中元素,但是不允许向其中存放新的对象。(这个概念也称为数据传送对象,或信使。)

通常,元组可以具有任意长度,同时,元组中的对象可以是任意不同的类型。不过,我们希望能够为每一个对象指明其类型,并且从容器中读取出来时,能够得到正确的类型。要处理不同长度的问题,我们需要创建多个不同的元组。下面的程序是一个2维元组,它能够持有两个对象:

354第15 章620

621

构造器捕获了要存储的对象,而toString()

是一个便利函数,用来显示列表中的值。注意,元组隐含地保持了其中元素的次序。

第一次阅读上面的代码时,你也许会想,这不是违反了Java 编程的安全性原则吗?

first 和second 应该声明为private ,然后提供getFirst()和getSecond()之类的访问方法才对呀?让我们仔细看看这个例子中的安全性:客户端程序可以读取first 和second 对象,然后可以随心所欲地使用这两个对象。但是,它们却无法将其他值赋予first 或second 。因为final 声明为你买了相同的安全保险,而且这种格式更简洁明了。

还有另一种设计考虑,即你确实希望允许客户端程序员改变first 或second 所引用的对象。然而,采用以上的形式无疑是更安全的做法,这样的话,如果程序员想要使用具有不同元素的元组,就强制要求他们另外创建一个新的TwoTuple 对象。

我们可以利用继承机制实现长度更长的元组。从下面的例子中可以看到,增加类型参数是件很简单的事情:

泛型355622

为了使用元组,你只需定义一个长度适合的元组,将其作为方法的返回值,然后在return 语句中创建该元组,并返回即可。

由于有了泛型,你可以很容易地创建元组,令其返回一组任意类型的对象。而你所要做的,

只是编写表达式而已。通过ttsi.first = "there"语句的错误,我们可以看出,final 声明确实能够保护

public 元素,在对象被构造出来之后,声明为final 的元素便不能被再赋予其他值了。在上面的程序中,new 表达式确实有点罗嗦。本章稍后会介绍,如何利用泛型方法简化这样的表达式。练习3:(1) 使用泛型编写一个SixTuple 类,并测试它。练习4:(3) “泛型化”innerclasses/Sequence.java 类。

15.2.2 一个堆栈类

接下来我们看一个稍微复杂一点的例子:传统的下推堆栈。在第11章中,我们看到,这个堆栈是作为net.mindview.util.Stack 类,用一个LinkedList 实现的。在那个例子中,LinkedList 本身已经具备了创建堆栈所必需的方法,而Stack 可以通过两个泛型的类Stack和LinkedList的组合来创建。在那个示例中,我们可以看出,泛型类型也就是另一种类型罢了(稍候我们会356第15 章623

624

看到一些例外的情况)。

现在我们不用LinkedList ,来实现自己的内部链式存储机制。

内部类Node

也是一个泛型,它拥有自己的类型参数。这个例子使用了一个末端哨兵(end sentinel )来判断堆栈何时为空。这个末端哨兵是在构造LinkedStack 时创建的。然后,每调用一次push()方法,就会创建一个Node对象,并将其链接到前一个Node对象。当你调用pop()方法时,总是返回top.item ,然后丢弃当前top 所指的Node,并将top 转移到下一个Node,除非你已经碰到了末端哨兵,这时候就不再移动top 了。如果已经到了末端,客户端程序还继续调用pop()方法,它只能得到null ,说明堆栈已经空了。

练习5:(2) 移除Node 类上的类型参数,并修改LinkedStack.java 的代码,证明内部类可以访问其外部类的类型参数。

15.2.3 RandomList

作为容器的另一个例子,假设我们需要一个持有特定类型对象的列表,每次调用其上的select()方法时,它可以随机地选取一个元素。如果我们希望以此构建一个可以应用于各种类型的对象的工具,就需要使用泛型:泛型357625

练习6:

(1) 使用RandomList

来处理两种额外的不同类型的元素,要区别于main()中已经用过的类型。

15.3 泛型接口泛型也可以应用于接口。例如生成器(generator ),这是一种专门负责创建对象的类。实际

上,这是工厂方法设计模式的一种应用。不过,当使用生成器创建新的对象时,它不需要任何参数,而工厂方法一般需要参数。也就是说,生成器无需额外的信息就知道如何创建新对象。

一般而言,一个生成器只定义一个方法,该方法用以产生新的对象。在这里,就是next()方法。我将它收录在我的标准工具类库中:

方法next()的返回类型是参数化的T 。正如你所见到的,接口使用泛型与类使用泛型没什么区别。

为了演示如何实现Generator 接口,我们还需要一些别的类。例如,Coffee 类层次结构如下:358第15 章626

627

现在,我们可以编写一个类,实现Generator

接口,它能够随机生成不同类型的Coffee 对象:

泛型359628

参数化的Generator 接口确保next()的返回值是参数的类型。CoffeeGenerator 同时还实现了Iterable 接口,所以它可以在循环语句中使用。不过,它还需要一个“末端哨兵”来判断何时停止,这正是第二个构造器的功能。

下面的类是Generator接口的另一个实现,它负责生成Fibonacci 数列:

虽然我们在

Fibonacci 类的里里外外使用的都是int 类型,但是其类型参数却是

Integer 。这个例子引出了

Java 泛型的一个局限性:基本类型无法作为类型参数。不过,Java SE5具备了自动打包和自动拆包的功能,可以很方便地在基本类型和其相应的包装器类型之间进行转换。通过这个例子中Fibonacci

类对int 的使用,我们已经看到了这种效果。

如果还想更进一步,编写一个实现了Iterable 的Fibonacci 生成器。我们的一个选择是重写这个类,令其实现Iterable 接口。不过,你并不是总能拥有源代码的控制权,并且,除非必须这么做,否则,我们也不愿意重写一个类。而且我们还有另一种选择,就是创建一个适配器(adapter )来实现所需的接口,我们在前面介绍过这个设计模式。

有多种方法可以实现适配器。例如,可以通过继承来创建适配器类:

360第15 章629

630

如果要在循环语句中使用IterableFibonacci ,必须向

IterableFibonacci 的构造器提供一个边界值,然后hasNext()方法才能知道何时应该返回false 。练习7:(2) 使用组合代替继承,适配Fibonacci 使其成为Iterable 。

练习8:(2) 模仿Coffee 示例的样子,根据你喜爱的电影人物,创建一个StoryCharacters 的类层次结构,将它们划分为GoodGuys 和BadGuys 。再按照CoffeeGenerator 的形式,编写一个StoryCharacters 的生成器。

15.4 泛型方法

到目前为止,我们看到的泛型,都是应用于整个类上。但同样可以在类中包含参数化方法,而这个方法所在的类可以是泛型类,也可以不是泛型类。也就是说,是否拥有泛型方法,与其所在的类是否是泛型没有关系。

泛型方法使得该方法能够独立于类而产生变化。以下是一个基本的指导原则:无论何时,只要你能做到,你就应该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类泛型化,那么就应该只使用泛型方法,因为它可以使事情更清楚明白。另外,对于一个static 的方法而言,无法访问泛型类的类型参数,所以,如果static 方法需要使用泛型能力,就必须使其成为泛型方法。

要定义泛型方法,只需将泛型参数列表置于返回值之前,就像下面这样:

GenericMethods 并不是参数化的,尽管这个类和其内部的方法可以被同时参数化,但是在这个例子中,只有方法f()拥有类型参数。这是由该方法的返回类型前面的类型参数列表指明的。

注意,当使用泛型类时,必须在创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不必指明参数类型,因为编译器会为我们找出具体的类型。这称为类型参数推断(type argument inference )。因此,我们可以像调用普通方法一样调用f(),而且就好像是f()被无限次地重载过。它甚至可以接受GenericMethods 作为其类型参数。

如果调用f()时传入基本类型,自动打包机制就会介入其中,将基本类型的值包装为对应的对象。事实上,泛型方法与自动打包避免了许多以前我们不得不自己编写出来的代码。泛型361631632

练习9:(1) 修改GenericMethods.java 类,使f()可以接受三个类型各不相同的参数。

练习10:(1) 修改前一个练习,将方法f()的其中一个参数修改为非参数化的类型。

15.4.1 杠杆利用类型参数推断

人们对泛型有一个抱怨,使用泛型有时候需要向程序中加入更多的代码。考虑第11章中的holding/MapOfList.java 类,如果要创建一个持有List 的Map ,就要像下面这样:(本章稍后会介绍表达式中问号与

extends 的用法。)看到了吧,你在重复自己做过的事情,

编译器本来应该能够从泛型参数列表中的一个参数推断出另一个参数。唉,可惜的是,编译器暂时还做不到。然而,在泛型方法中,类型参数推断可以为我们简化一部分工作。例如,我们可以编写一个工具类,它包含各种各样的static 方法,专门用来创建各种常用的容器对象:

main()方法演示了如何使用这个工具类,类型参数推断避免了重复的泛型参数列表。它同

样可以应用于holding/MapOfList.java :

对于类型参数推断而言,这是一个有趣的例子。不过,很难说它为我们带来了多少好处。362

第15 章633

如果某人阅读以上代码,他必须分析理解工具类New ,以及New 所隐含的功能。而这似乎与不使用New 时(具有重复的类型参数列表的定义)的工作效率差不多。这真够讽刺的,要知道,我们引入New 工具类的目的,正是为了使代码简单易读。不过,如果标准Java 类库要是能添加类似New.java 这样的工具类的话,我们还是应该使用这样的工具类。

类型推断只对赋值操作有效,其他时候并不起作用。如果你将一个泛型方法调用的结果(例如New.map())作为参数,传递给另一个方法,这时编译器并不会执行类型推断。在这种情况下,编译器认为:调用泛型方法后,其返回值被赋给一个Object 类型的变量。下面的例子证明了这一点:

练习11:(1)

创建自己的若干个类来测试New.java ,并确保New

可以正确地与它们一起工作。显式的类型说明在泛型方法中,可以显式地指明类型,不过这种语法很少使用。要显式地指明类型,必须在点操作符与方法名之间插入尖括号,然后把类型置于尖括号内。如果是在定义该方法的类的内部,必须在点操作符之前使用this 关键字,如果是使用static 的方法,必须在点操作符之前加上类名。使用这种语法,可以解决LimitsOfInference.java 中的问题:

当然,这种语法抵消了New 类为我们带来的好处(即省去了大量的类型说明),不过,只有在编写非赋值语句时,我们才需要这样的额外说明。

练习12:(1) 使用显式的类型说明来重复前一个练习。

15.4.2 可变参数与泛型方法

泛型方法与可变参数列表能够很好地共存:泛型363634635

makeList()方法展示了与标准类库中

java.util.Arrays.asList()方法相同的功能。

15.4.3 用于Generator 的泛型方法利用生成器,我们可以很方便地填充一个Collection ,而泛型化这种操作是具有实际意义的:

请注意,fill()方法是如何透明地应用于Coffee 和

Integer 的容器和生成器。

练习13:(4) 重载fill()方法,使其参数与返回值的类型为Collection 的导出类:List 、Queue 和Set 。通过这种方式,我们就不会丢失容器的类型。能够在重载时区分List 和LinkedList 吗?15.4.4 一个通用的Generator

下面的程序可以为任何类构造一个Generator ,只要该类具有默认的构造器。为了减少类型声明,它提供了一个泛型方法,用以生成BasicGenerator :

364第15 章636

这个类提供了一个基本实现,用以生成某个类的对象。这个类必需具备两个特点:(1

)它必须声明为public 。

(因为BasicGenerator 与要处理的类在不同的包中,所以该类必须声明为

public ,并且不只具有包内访问权限。)(2)它必须具备默认的构造器(无参数的构造器)。要创建这样的BasicGenerator 对象,只需调用create()方法,并传入想要生成的类型。泛型化的create()方法允许执行BasicGenerator.create(MyType.class),而不必执行麻烦的new Basic-Generator(MyType.class)。

例如,下面是一个具有默认构造器的简单的类:

CountedObject 类能够记录下它创建了多少个CountedObject 实例,并通过toString()方法告诉我们其编号。

使用BasicGenerator ,你可以很容易地为CountedObject 创建一个Generator :

可以看到,使用泛型方法创建Generator 对象,大大减少了我们要编写的代码。Java 泛型要求传入Class 对象,以便也可以在create()方法中用它进行类型推断。

练习14:(1) 修改BasicGeneratorDemo.java 类,使其显式地构造Generator (也就是不使用create()方法,而是使用显式的构造器)。泛型365637638

15.4.5 简化元组的使用

有了类型参数推断,再加上static 方法,我们可以重新编写之前看到的元组工具,使其成为更通用的工具类库。在这个类中,我们通过重载static 方法创建元组:

下面是修改后的TupleTest.java ,用来测试Tuple.java

:注意,方法f()返回一个参数化的

TwoTuple 对象,而f2()返回的是非参数化的TwoTuple 对象。366第15 章639

在这个例子中,编译器并没有关于f2()的警告信息,因为我们并没有将其返回值作为参数化对象使用。在某种意义上,它被“向上转型”为一个非参数化的TwoTuple 。然而,如果试图将f2()的返回值转型为参数化的TwoTuple ,编译器就会发出警告。

练习15:(1) 验证前面的陈述是否属实。

练习16:(2) 为Tuple.java 添加一个SixTuple ,并在TupleTest2.java 中进行测试。

15.4.6 一个Set 实用工具

作为泛型方法的另一个示例,我们看看如何用Set 来表达数学中的关系式。通过使用泛型方法,可以很方便地做到这一点,而且可以应用于多种类型:在前三个方法中,都将第一个参数Set

复制了一份,将Set 中的所有引用都存入一个新的HashSet 对象中,因此,我们并未直接修改参数中的Set 。返回的值是一个全新的Set 对象。

这四个方法表达了如下的数学集合操作:union()返回一个Set ,它将两个参数合并在一起;intersection()返回的Set 只包含两个参数共有的部分;difference()方法从superset 中移除subset 包含的元素;complement()返回的Set 包含除了交集之外的所有元素。下面提供了一个enum ,它包含各种水彩画的颜色。我们将用它来演示以上这些方法的功能和效果。

为了方便起见(可以直接使用enum 中的元素名),下面的示例以static 的方式引入Watercolors 。这个示例使用了EnumSet ,这是Java SE5中的新工具,用来从enum 直接创建Set 。(在第19章中,泛型367640641

我们会详细介绍EnumSet 。)在这里,我们向static 方法EnumSet.range()传入某个范围的第一个元素与最后一个元素,然后它将返回一个Set ,其中包含该范围内的所有元素:

我们可以从输出中看到各种关系运算的结果。

下面的示例使用

Sets.difference()打印出java.util 包中各种Collection

类与Map 类之间的方法差异:368

第15 章642

643

在第11章的“总结”中,我们使用了这个程序的输出结果。

练习17:(4) 研究JDK 文档中有关EnumSet 的部分,你会看到它定义了clone()方法。然而,在Sets.java 中,你却不能复制Set 接口中的引用。请试着修改Sets.java ,使其不但能接受一般的Set 接口,而且能直接接受EnumSet ,并使用clone()而不是创建新的HashSet 对象。

15.5 匿名内部类

泛型还可以应用于内部类以及匿名内部类。下面的示例使用匿名内部类实现了Generator 接口:泛型369644

Customer 和Teller 类都只有private 的构造器,这可以强制你必须使用

Generator 对象。Customer 有一个generator()方法,每次执行它都会生成一个新的Generator对象。我们其实不需要多个Generator 对象,Teller 就只创建了一个public 的generator 对象。在main()方法中可以看到,这两种创建Generator 的方式都在fill()中用到了。

由于Customer 中的generator()方法,以及Teller 中的Generator 对象都声明成了static 的,所以它们无法作为接口的一部分,因此无法用接口这种特定的惯用法来泛化这二者。尽管如此,它们在fill()方法中都工作得很好。

在第21章中,我们还会看到关于这个排队问题的另一个版本。

练习18:(3) 遵循BackTeller.java 的形式,创建一个Ocean 中BigFish 吃LittleFish 的例子。370第15 章645

646

15.6 构建复杂模型

泛型的一个重要好处是能够简单而安全地创建复杂的模型。例如,我们可以很容易地创建List 元组:尽管这看上去有些冗长(特别是迭代器的创建),但最终还是没有用过多的代码就得到了一

个相当强大的数据结构。下面是另一个示例,它展示了使用泛型类型来构建复杂模型是多么的简单。即使每个类都是作为一个构建块创建的,但是其整个还是包含许多部分。在本例中,构建的模型是一个零售店,它包含走廊、货架和商品:泛型371647

实验十 泛型与集合框架

实验十泛型与集合框架 1.实验目的 1、掌握LinkedList类和Collections类提供的用于排序和查找链表中 的数据的方法 2、掌握用散列映射来存储数据 3、掌握TreeSet类的使用 2.实验内容 1、根据附录里的源代码,按照注释要求,完成代码填空,使程序能够运行 得出结果。 1)实验1 按身高排序 2)实验2 英汉小字典 3)实验3 演出节目单 4)实验4输出args[]中的单词 2、设计编写程序完成以下任务。 1)仿照实验1编写TV类,要求通过实现Comparable接口规定该类的对象的大小关系,按price值得大小确定大小关系,即电视机按其价格确定之间的大小关系。 2)从控制台输入若干个单词(输入回车结束)放入集合中,将这些单词排序后(忽略大小写)打印出来。 知识点:List接口的实现类、String常用方法 3)请使用LinkedList来模拟一个队列(先进先出的特性): (1)拥有放入对象的方法void put(Object o) (2)取出对象的方法Object get() (3)判断队列当中是否为空的方法boolean isEmpty();并且,编写测试代码,验证你的队列是否正确。 知识点:List接口的实现类LinkedList常用方法 4)在一个列表中存储以下元素:apple,grape,banana,pear (1)返回集合中的最大的和最小的元素 (2)将集合进行排序,并将排序后的结果打印在控制台上 知识点:Collections类中的方法 3.实验步骤 略 4.评分标准 1.A——内容功能完善,编程风格好,人机接口界面好; 2.B——内容功能完善,编程风格良好,人机接口界面良好;

浅谈c# 泛型类的应用分析

浅谈c# 泛型类的应用 本篇文章是对c#中泛型类的应用进行了详细的分析介绍,需要的朋友参考下 泛型类 泛型类封装不是特定于具体数据类型的操作。泛型类最常用于集合,如链接列表、哈希表、堆栈、队列、树等。像从集合中添加和移除项这样的操作都以大体上相同的方式执行,与所存储数据的类型无关。对大多集合类的操作,推荐使用.NET Framework 类库中所提供的类。 (1)泛型类可以继承具体类、封闭式构造、开放式构造基类。 复制代码代码如下: class BaseNode { } class BaseNodeGeneric { } // 继承具体类 class NodeConcrete : BaseNode { } //继承封闭式构造基类 //封闭式构造基类指基类类型参数指定具体类型 class NodeClosed : BaseNodeGeneric { } //继承开放式构造基类 //开放式构造基类指基类类型参数未指定 class NodeOpen : BaseNodeGeneric { } (2)基类类型参数必须在子类中指定实现。 复制代码代码如下: //正确 class Node1 : BaseNodeGeneric { } //错误 //在子类中未指定父类类型参数实现 class Node2 : BaseNodeGeneric {} //错误 //在子类中未指定父类类型参数实现 class Node3 : T {} class BaseNodeMultiple { } //正确 class Node4 : BaseNodeMultiple { } //正确

JAVA实验报告-集合框架与泛型机制

Java 语言程序设计 C 实验报告 集合框架及泛型机制 学生姓名 专业、班级 指导教师 成绩 计算机与信息工程学院 年月日

一、实验目的 学习课程相关章节知识,通过上机练习,掌握以下知识: 1.掌握 List 接口下 ArrayList 及 LinkedList 的使用方法。 2.掌握 Map 接口下 HashMap 及 HashTable的使用方法 3.掌握集合中泛型的使用 二、实验内容 利用集合完成象数据库那样存储数据,并且可以简单查询,利用 map 存储学生信息,字段如下: id ,name,age,实现步骤: (1)创建类,类图如下: (2)在 main 方法编写逻辑代码 (3)运行程序并测试结果 package https://www.360docs.net/doc/c511424949.html,; public class Student { private String name ; private int age ; private String id ;

public String getName() { return name ; } public void setName(String name ) { this . name =name ; } public int getAge() { return age ; } public void setAge(int age ) { this. age=age ; } public String getId() { return id; } public void setId(String id) { this. id=id; } public Student(String name ,int age , String id ) { super(); this. name =name ; this. age=age ; this. id=id; } public void sayHi() { System.out.println("name=" +this.getName()+"age=" + this .getAge()+" " + "id=" + this.getId()); } }

java简答(无答案版)

1、JDBC编程的主要步骤有那些? 答:选择并加载一个合适的JDBC驱动程序; 创建一个Connection对象,建立与数据库的链接; 创建一个Statement对象,用该Statement对象进行数据库的操作; 从返回的ResultSet中获取相应数据。 2、什么是标准的输入输出流? 答:system.in 标准输入流system.out.标准输出流system.err标准错误输出 3、抽象类的特点和用途? 答:抽象类不能创建对象,只能作为其他类的父类; 抽象类的作用: 1、表示抽象的概念,如动物, 2、建立类之间的关系 3、为实现某一接口的单一功能,抽象类中的抽象方法可以不要全部实现 4、Java的GUI事件处理模型的编程步骤有那些? 5、什么是对象流和序列化? 答:对象流是一种以字节流为基础的可用于持久化保存对象的机制; 序列化是指将java对象转化为字节序列的过程 6、Java语言如何进行异常处理? 7、编写JDBC应用程序通用的步骤有哪几个? 8、什么是Java的GUI事件处理机制? 答:事件响应是GUI程序设计的关键部分,所谓的事件响应就是通过调用与事件关联的方法来处理执行事件。Java事件处理机制把事件源、事件监听器、事件对象三个基本要素联系起来了,包含了对事件进行监听、发生事件、通知监听器以及处理整个事件的流程。 9、类的重用方式有几种?分别如何实现?, 答:继承和组合;java只支持单继承,每个子类都只能有一个直接父类,子类可以继承父类的数据成员和方法,也可以增加新的变量和方法,还可以覆盖继承的方法,通过关键字extends来实现。组合也称为聚合,指java的类中可以包含其他类的对象作为数据成员,是一种包含关系。 10、如何理解Java中包的概念? 11、类的访问控制有哪几种,各有和作用? 答:public: Protected: Private: 包 12、多态机制实线的条件? 答:1、必须是继承关系的类; 2、首先要把子类对象向上转型为父类对象,然后用父类对象调用同名的方法, 系统才能通过动态绑定自动识别调用的方法所属的类; 3、对象的使用者只保持与父类接口通信。 13、终结类和终结方法的特点和用途? 14、反射机制可以用来在程序运行时得到对象的类的那些信息? 答:它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法。Reflection机制允许程序在正在执行的过程中,利用Reflection APIs取得任何已知名称的类的

实验11泛型与集合

实验内容: (1)定义一个泛型类Instrument,其中包括一个泛型方法void play(E x)。定义两种乐器类:Cello、Violin 可以进行演奏。定义一个测试类进行测试。 package ex111; public class Violin { public String toString() { System.out.println("violin........."); return ""; } } package ex111; public class Test_Main { public static void main(String[] args) { instrumentmodel = new instrument(); instrumentmodel1 = new instrument(); Cello cello = new Cello(); Violin violin = new Violin(); model.play(cello); model1.play(violin); } } package ex111; class instrument {//泛型类 void play(E x) { x.toString(); } } package ex111; public class Cello { public String toString(){ System.out.println("cello........."); return ""; } } (2)输入10 个数字保存到List 中,并按倒序显示出来。 package ex112; import java.util.ArrayList; import java.util.Collections;

通过实例学习C#开发中的泛型

C#中所谓泛型:即通过参数化类型来实现在同一份代码上操作多种数据类型。泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。 C#泛型赋予了代码更强的类型安全,更好的复用,更高的效率,更清晰的约束。 C#泛型机制简介 C#泛型能力由CLR在运行时支持,区别于C++的编译时模板机制,和java 的编译时的“搽拭法”。这使得泛型能力可以在各个支持CLR的语言之间进行无缝的互操作。 C#泛型代码在被编译为IL和元数据时,采用特殊的占位符来表示泛型类型,并用专有的IL指令支持泛型操作。而真正的泛型实例化工作以“on-demand”的方式,发生在JIT编译时。 C#泛型编译机制 第一轮编译时,编译器只为Stack类型产生“泛型版”的IL代码和元数据,并不进行泛型类型的实例化,T在中间只充当占位符。 JIT编译时,当JIT编译器第一次遇到Stack时,将用int类型替换“泛型版”IL代码与元数据中的T -- 进行泛型类型的实例化。 CLR为所有类型参数为“引用类型”的泛型类型产生同一份代码,但如果类型参数为“值类型”,对每一个不同的“值类型”,CLR将为其产生一份独立的代码。 C#泛型的几个特点 如果实例化泛型类型的参数相同,那么JIT编译器会重复使用该类型,因此C#的动态泛型能力避免了C++静态模板可能导致的代码膨胀的问题。 C#泛型类型携带有丰富的元数据,因此C#的泛型类型可以应用于强大的反射技术。 C#的泛型采用“基类、接口、构造器、值类型/引用类型”的约束方式来实现对类型参数的“显示约束”,提高了类型安全的同时,也丧失了C++模板基于“签名”的隐式约束所具有的高灵活性。 C#泛型类与结构 class C{} //合法 class D:C{} //合法

IEnumerable和IEnumerableT接口

IEnumerable和IEnumerable接口在.NET中是非常重要的接口,它允许开发人员定义foreach语句功能的实现并支持非泛型方法的简单的迭代,IEnumerable和IEnumerable接口是.NET Fra mework中最基本的集合访问器,这两个接口对于LINQ的理解是非常重要的。 在面向对象的开发过程中,常常需要创建若干对象,并进行对象的操作和查询,在创建对象前,首先需要声明一个类为对象提供描述,示例代码如下所示。 using System; using System.Collections.Generic; using System.Linq; //使用LINQ命名控件using System.Text; namespace IEnumeratorSample { class Person //定义一个Person类 { public string Name; //定义Person的名字 public string Age; //定义Person的年龄 public Person(string name, string age) //为Person初始化(构造函数) { Name = name; //配置Name值 Age = age; //配置Age值 } } 上述代码定义了一个Person类并抽象一个Person类的属性,这些属性包括Name和Age。Name 和Age属性分别用于描述Person的名字和年龄,用于数据初始化。初始化之后的数据就需要创建一系列Person对象,通过这些对象的相应属性能够进行对象的访问和遍历,示例代码如下所示。 class Program { static void Main(string[] args) { Person[] per = new Person[2] //创建并初始化2个Person对象{ new Person("guojing","21"), //通过构造函数构造对象 new Person("muqing","21"), //通过构造函数构造对象 }; foreach (Person p in per) //遍历对象 Console.WriteLine("Name is " + https://www.360docs.net/doc/c511424949.html, + " and Age is " + p.Age); Console.ReadKey(); } }

实验11泛型与集合

实验内容: (1)定义一个泛型类In strume nt,其中包括一个泛型方法void play(E x) 定义两种乐器类:Cello、Violin可以进行演奏。定义一个测试类进行测试。 package ex111; public class Violin { public String toStri ng() { System.out.println("violin ....... "); return ""; } } package ex111; public class Test_Ma in { public static void main( Stri ng[] args) { instrumentmodel = new instrument(); in strume ntvVioli n> model1 = new in strume ntvVioli n>(); Cello cello = new Cello(); Violin violin = new Violi n(); model.play(cello); model1.play(violi n); } } package ex111; class in strume nt {//泛型类void play(E x) { x.toStri ng(); } } package ex111; public class Cello { public Stri ng toStri ng(){ System.out.println("cello ....... "); return ""; } } (2)输入10个数字保存到List中,并按倒序显示出来 package ex112; import java.util.ArrayList; import java.util.Collectio ns; import java.util.List; import java.util.Sca nner; public class Test{ public static void main(final String[] args) { final List< In teger> in tegers = new ArrayListvl nteger>(); final Scanner sca nner = new Scann er(System.i n); for (int i = 1; i <= 3; i++) {

第8章_泛型编程习题_参考答案

《面向对象程序设计》习题 第8章泛型编程 一、选择题(共40分,每题2分) 二、填空题(共20分,每空2分) 1. 逻辑数据类型 2. 函数类 3. 函数模板类模板 4.函数类型形参类型 5.2 6. 尖括号 三、下列程序有2个错,找出并修改(共6分) 错1:public: A(T a, b) // A(T a,T b) {x=a,y=b;s=x+y;} 错2: int main() { A add(10,100); // A add(10,100); add.show(); return 0; } 四、看程序写结果(共12分,每题4分) 1. 2. 3.

五、编程题(22分) 1.设计一个函数模板,实现两数的交换,并用int、float、double、char类型的数据进行测试。 #include #include using namespace std; template void change(T &x, T &y) { T temp; temp=x; x=y; y=temp; } int main() { int a=12, b=34; float c=1.1, d=2.2; double e=1.23456789, f=2.23456789; char u='A', v='B'; cout<<"交换前:a="< integerBox = new Box(); Box doubleBox = new Box(); Box stringBox = new Box(); 泛型方法 看完了泛型类,接下来我们来了解一下泛型方法。声明一个泛型方法很简单,只要在返回类型前面加上一个类似的形式就行了: public class Util { public static boolean compare(Pair p1, Pair p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); } }

c#中的泛型总结

泛型 一、泛型体验 泛型是framework 2.0加入的一种特殊的算法重用机制,允许程序员在代码中将变量的类型先用类型占位符来替代,等到运行的时候在根据传入的类来替换。 Demo1 MyList类: 1public class MyList 2 { 3 T[] arr; 4public int count=0; 5public MyList(int length) 6 { 7 arr = new T[length]; 8 } 9public void Add(T t) 10 { 11 arr[count] = t; 12 count++; 13 } 14 15///

16///索引器 17/// 18/// 19/// 20public T this[int index] 21 { 22get 23 { 24if (index >= arr.Length) 25 { 26throw new System.Exception("数组下标越界 "); 27 } 28else

29 { 30return arr[index]; 31 } 32 } 33set 34 { 35if (index >= arr.Length) 36 { 37throw new System.Exception("数组下标越界 "); 38 } 39else 40 { 41 arr[index]=value; 42 } 43 } 44 } 45 } 调用: 1protected void Page_Load(object sender, EventArgs e) 2 { 3 MyList list = new MyList(4); 4 5 list.Add(1); 6 list.Add(4); 7 list.Add(5); 8 list.Add(6); 9for (int i = 0; i < list.count; i++) 10 { 11 Response.Write(list[i].ToString()); 12 } 13 } 注意: 1、是在运行时,将堆空间里的对象内部所有的占位符都替换成传入的类型. 2、泛型是指带类型参数的类,而不是类型参数本身。

1C#中接口委托装箱拆箱深拷贝浅拷贝

关于接口: 接口是对一组能提供相同服务的类或结构的抽象。 接口是表示一组函数成员而不实现成员的引用类型。 接口是一种抽象的数据类型,不能被实例化。 接口可以被实现,只有类和结构才能实现接口。 类或接口都可以对接口进行继承。 如果基类和接口被继承,基类要写在接口之前。 接口本身可以有任意的访问修饰符号。 接口成员是隐式public,不允许有任何访问修饰符,包括public。 关于委托: 委托类似于C/C++的函数指针。 使用委托的过程分3步:定义、实例化和调用。 委托的定义使用delegate关键字。 委托的实例化使用new关键字,所引用的方法的参数列表和返回类型都要与委托的定义一致。 调用委托与调用方法相似。 Delegate void MDelegate(unit i); MDelegate md=new MDelegate(card1.Deposit); Md(100); md=new MDelegate(card1.withdraw); md(50); 深拷贝和浅拷贝: 浅拷贝:是指将对象中的所有字段逐字复制到一个新对象

对值类型字段只是简单的拷贝一个副本到目标对象,改变目标对象中值类型字段的值不会反应到原始对象中,因为拷贝的是副本。 对引用类型字段则是指拷贝它的一个引用到目标对象。改变目标对象中引用类型字段的值将反应到原始对象中,因为拷贝的是指向堆上的一个地址。 深拷贝:深拷贝与浅拷贝不同的是对于引用字段的处理,深拷贝将会在新对象中创建一个新的对象和原始对象中对应字段相同(内容相同)的字段,也就是书这个引用和原始对象是不同,我们改变新对象中这个字段的时候是不会影响到原始对象中对应字段的内容。 浅复制:须实现ICloneable接口中的Clone方法,且需要需要克隆的对象加上[Serializable]特性。 《装箱拆箱》 今天看JDK5的时候也发现了装箱/拆箱概念,遂作一总结,以备后用。 .net中有一个很重要的概念,装箱与拆箱,之后在jdk5也出现了自动装箱/拆箱的概念。 一、什么是装箱/拆箱。 这要涉及到数据类型,在.net中所有的类型都继承自System.Object,所有的类型都是对象.类型主要分为两种,一是值类型,包括原类型(Sbyte、Byte、Short、Ushort、Int、Uint、Long、Ulong、Char、Float、Double、Bool、Decimal)、枚举(enum)、结构(struct).另一类是引用类型,包括类、数组、接口、委托、字符串等. 其中值类型是在栈中分配内存,本身的声明就是一个初始化的过程,其不需要进行垃圾回收,只要超出所定义的作用范围会自动释放内存. 而引用类型则是在堆中分配的,和java一样,在堆种分配内存,而其托管堆进行垃圾回收. 当两种数据类型进行转换时就引出了装箱/拆箱. 装箱:值类型到引用类型或到此值类型所实现的任何接口类型的隐式转换 例如:int temp=3; System.Object obj=temp; 其中,temp为值类型,在栈中分配;当分配obj这个引用类型时,我们需要在

实验11泛型与集合

实验内容: (1) 定义一个泛型类Instrument<E 〉,其中包括一个泛型方法void pla y(E x)。 定义两种乐器类:Cello、Violin 可以进行演奏。定义一个测试类进行测试. package ex111; public class Violin{ publicString toString() { System、out、println("violin、、、、、、、、、"); return ””; } } package ex111; public class Test_Main{ public staticvoid main(String[]args){ instrument〈Cello>model = new instrument〈Cello〉(); instrument

6Java第六单元练习题-泛型与集合

6泛型与集合 6.1单项选择题 1.可实现有序对象的操作是?() A.HashMap B.HashSet C.TreeMap D.Stack 2.不是迭代器接口(Iterator)所定义的方法是()。 A.hasNext() B.next() C.remove() D.nextElement() 3.下面说法不正确的是() A.列表(List)、集合(Set)和映射(Map)都是java.util包中的接口。 B.List接口是可以包含重复元素的有序集合。 C.Set接口是不包含重复元素的集合。 D.Map接口将键映射到值,键可以重复,但每个键最多只能映射一个值。 4.下面那些方法不是接口Collection中已声明的方法() A.添加元素的add(Object obj) 方法 B.删除元素的remove(Object obj)方法 C.得到元素个数的length()方法 D.返回迭代器的iterator()方法,迭代器用于元素遍历 5. 下列关于容器的描述中,错误的是() A.容器是由若干个组建和容器组成的 B.容器是对图形界面中界面元素的一种管理 C.容器是一种对指定宽和高的矩形范围 D.容器都是可以独立的窗口 6. 下列界面元素中,不是容器的是() A.List B.JFrame C.JDialog D.Panel 7.应用程序的main方法中有以下语句,则输出的结果是( )。

Hashtable hashtable=new Hashtable(); hashtable.put("100","aaa"); hashtable.put("200","bbb"); hashtable.put("300","ccc"); System.out.println(hashtable.get("300").toString() + hashtable.get("200").toString() + hashtable.get("100").toString()); A) aaa B) bbb C) ccc D) cccbbbaaa 6.2判断题 1.Map接口是自Collection接口继承而来。(×) 2.集合Set是通过键-值对的方式来存储对象的。(×) 3.Integer i = (Integer.valueOf("926")).intValue();(√) 4.String s = (Double.valueOf("3.1415926")).toString(); (√) 5.Integer I = Integer.parseInt("926");(√) 6.Arrays类主要对数组进行操作。(√) 7.在集合中元素类型必须是相同的。(√) 8.集合中可以包含相同的对象。(×) 9.枚举接口定义了具有删除功能的方法。(×) 6.3程序阅读题 1.阅读下面的程序,回答问题。 import java.util.*; public class T { public static void main(String args[]) { Set set = new TreeSet(); set.add(new Integer(10)); set.add(new Integer(5)); set.add(new Integer(15)); set.add(new Integer(5)); set.add(new Integer(10)); System.out.println("size = " + set.size()); Iterator it=set.iterator(); while(it.hasNext()){ System.out.print(it.next()+" "); } }

实验七:Java集合与泛型

实验七Java集合与泛型 一、实验目的 1)掌握集合的概念、体系结构、分类及使用场景 2)了解Set接口及主要实现类(HashSet、TreeSet) 3)了解List接口及主要实现类(ArrayList、LinkedList、Vector) 4)掌握ArrayList的使用 5)掌握ArrayList与Vector的区别 6)了解Map接口及主要实现类(HashMap、TreeMap、HashTable) 7)掌握HashMap的使用 8)掌握HashMap与HashTable的区别 二、实验环境 JDK1.6+Eclpise3.2 三、实验准备 1)复习课件中理论知识 2)练习课堂所讲的例子 四、实验内容 1、编写程序练习List集合的基本使用: 1) 创建一个只能容纳String对象名为names的ArrayList集合; 2)按顺序往集合中添加5个字符串对象:“张三”、“李四”、“王五”、“马六”、“赵七”; 3)对集合进行遍历,分别打印集合中的每个元素的位置与内容; 4)首先打印集合的大小,然后删除集合中的第3个元素,并显示删除元素的内容,然后再打印目前集合中第3个元素的内容,并再次打印集合的大小。 2、编写程序练习Map集合的基本使用: 1)创建一个只能值只能容纳String对象的person的HashMap集合; 2)往集合中添加5个“键-值”对象:id—>”1”、name—>”张三”、sex—>”男”、age—>”25”、love—>”爱学Java” 3)对集合进行遍历,分别打印集合中的每个元素的键与值; 4)首先打印集合的大小,然后删除集合中的键为age的元素,并显示删除元素的内容,并再次打印集合的大小。 五、验过程及结果 第1题调试结果如下图:

C#泛型探究(自学篇)

前言 前几日同学告诉我他老师告诉他,泛型是定义一种通用的方法,至于为什么用泛型他的答 案还是定义一种通用的方法,当时我也没有学,还不懂啦,毕竟人家是计算机专业的科班生,我当 然没有发言权,只是怀疑的记下了这个错误的结论打算以后看看是不是对的,这两天算是把泛型学 了一下,其实它定义的不只是方法,自己感觉他就是一种规范代码执行效率的模版,这样极不容易 出错,并把我们常用的箱拆箱操作过程给省了,提高了编译器的执行效率,。至于为什么用泛型这 个我貌似已经说明白了,泛型多用于集合类操作,我在这里随意的拿出C#定义的ArrayList的 Add方法的定义我们一起看看: public virtual int Add( Object value ) 可以看出我们可以往ArrayList里添加任何类型的元素,假如有一个string类型的str字符 串它在添加到ArrayList lib的过程中实际进行了装箱操作,即object value=str;那么我 们在获取这个值得时候必须这样使用string s=(string)lib[0];不能遗漏(string)否则会提示你, 错误1无法将类型“object”隐式转换为“string”。存在一个显式转换(是否缺少强制转换?) 但是你假如这样写:int a=(int)lib[0];程序在运行前是无法报错的,只要一旦运行就会出 现异常,而这些错误都可以利用泛型轻松搞定,让你在编译时就可以发现错误,具体的就看你怎么 领悟了,我在文章里没有写任何定义的语法格式,因为这个既没必要说,这是常识,出来混这些迟 早是要明白的,呵呵。玩笑啦......欢迎新手同学来我的博客交流学习,我也希望你们可以为我敞 开心怀,因为我既不是计算机专业的学生,甚至上了大学我已经不再是理工类的学生。我无意扎进了 文科专业去叱咤风云啦,哎,这个文科专业名字太有点科学技术的味道了。我喜欢 ........ 我的博客地址是:https://www.360docs.net/doc/c511424949.html,

java泛型接口,泛型类泛型方法

泛型可提高代码的高扩展性和重用率. 1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。 2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。 3、泛型的类型参数可以有多个。 4、泛型的参数类型可以使用extends语句,例如。习惯上称为“有界类型”。 5、泛型的参数类型还可以是通配符类型。例如Class classType = Class.forName("https://www.360docs.net/doc/c511424949.html,ng.String"); 泛型可以用在接口,类方法,集合上面. 泛型接口: interface testGenerics{ T getT(T t); String assume(T t); } 泛型类:

public class GenericsFoo { private T x; public GenericsFoo(T x) { this.x = x; } public T getX() { return x; } public void setX(T x) { this.x = x; } } 使用来声明一个类型持有者名称,然后就可以把T当作一个类型代表来声明成员、参数和返回值类型。 当然T仅仅是个名字,这个名字可以自行定义。 泛型方法: 是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。如: public class ExampleA { public void f(T x) {

System.out.println(x.getClass().getName()); } 使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。 限制泛型的可用类型: 在上面的例子中,由于没有限制class GenericsFoo类型持有者T的范围,实际上这里的限定类型相当于Object,这和“Object泛型”实质是一样的。限制比如我们要限制T为集合接口类型。只需要这么做: class GenericsFoo,这样类中的泛型T 只能是Collection接口的实现类,传入非Collection接口编译会出错。 注意:这里的限定使用关键字extends,后面可以是类也可以是接口。但这里的extends已经不是继承的含义了,应该理解为T类型是实现Collection接口的类型,或者T是继承了XX类的类型。 下面继续对上面的例子改进,我只要实现了集合接口的类型: public class CollectionGenFoo { private T x; public CollectionGenFoo(T x) { this.x = x;

c代码规范

c代码规范(总7页) -CAL-FENGHAI.-(YICAI)-Company One1 -CAL-本页仅作为文档封面,使用请直接删除

C# 代码规范 1、前言 本文档定义了一些通用的代码规范和准则,一般情况下本文档适用于项目组所有项目,特殊情况下,如果客户有自己的代码规范,以客户的代码优先。 2、大小写约定 2.1、大小写样式,本文中将出现两种大小写样式,这里先分别定义: Pascal大小写 将标识符的首字母和后面连接的每个单词的首字母都大写。可以对三字符或更多字符的标识符使用 Pascal 大小写。例如:BackColor Camel大小写 标识符的首字母小写,而每个后面连接的单词的首字母都大写。例如:backColor 匈牙利命名法 基本原则是:变量名=属性+类型+对象描述。例如:lblName 2.2、标识符大小写规则 2.2.1、下表中列出常见的代码元素的样式规范和示例 标识符规则示例 类Pascal AppDomain 枚举类型Pascal ErrorLevel 枚举值Pascal Warning 事件Pascal ValueChanging, ValueChanged 异常类Pascal WebException 只读的静态字段Pascal CurrentUser 接口Pascal IDisposable 方法Pascal ToString 命名空间Pascal 参数Camel typeName 属性Pascal Name 常量全大写MAXLENGTH, LENGTH_MAX Web或Win控件匈牙利txtName 2.2.2、除了遵循以上大小写约定外还需注意以下约定(除常量为特例): 如果标识符由多个单词组成,请不要在各单词之间使用分隔符,如下划线(“_”)或连字符(“-”)等。而应使用大小写来指示每个单词的开头。 所有公共的成员如:方法、属性,都应使用Pascal大小写样式 2.3、首缩写词的大小写规则 2.3.1、首字母缩写词 首字母缩写词是由术语或短语中各单词的首字母构成的单词。 例如,HTML 是 Hypertext Markup Language 的首字母缩写。为了方便编码规范的实施,本文规定受字母缩写词必须至少为两个单词,正好为两个单词的首字母缩写词称其为“短型首字母缩写词”,两个单词以上的称其为“长型首字母缩写词” 2.3.2、单缩写词

继承和接口设计习题

第7章继承和接口设计 一.选择题 1.在C#中,一个类【】。 A) 可以继承多个类B) 可以实现多个接口 C) 在一个程序中只能有一个子类D) 只能实现一个接口 2.【】关键字用于在C#中从派生类中访问基类的成员。 A) new B) super C) this D) base 3.在定义类时,若希望类的某个方法能够在派生类中进一步改进,以满足派生类的不同需要,则应将该方法声明为【】。 A) new B) public C) virtual D) override 4.在C#中,在派生类中对基类的虚方法进行重写,要求在派生类的声明中使用【】。 A) new B) public C) virtual D) override 5.已知类B是由类A继承而来,类A中有一个名为M的非虚方法,现在希望在类B中也定义一个名为M的方法,且两方法的参数个数和类型完全相同,若希望编译时不出现警告信息,则在类B中声明该方法时,应使用【】关键字。 A) static B) new C) override D) virtual 6.假设类B继承了类A,下列说法错误的是【】。 A) 类B中的成员可以访问类A中的公有成员 B) 类B中的成员可以访问类A中的保护成员 C) 类B中的成员可以访问类A中的私有成员 D) 类B中的成员可以访问类A中的静态成员 7.关于多态,下列说法正确的是【】。 A) 多态实际上就是重载,它们本质上是以一样的 B) 多态可以分为编译时多态和运行时多态。前者的特点是在编译时就能确定要调用成 员方法的哪个版本,后者则是在程序运行时才能确定要调用成员方法的哪个版本。 C) 编译时多态是在程序运行时才能确定要调用成员方法的哪个版本,而运行时多态在 编译时就能确定要调用成员方法的哪个版本。 D) 多态和重载是两个完全不同的概念,前者是通过定义虚方法和重写虚方法来实现, 后者是通过对同一函数名编写多个不同的实现代码来实现。 8.下列关于接口的说法,正确的是【】。 A) 接口中定义的方法都必须是虚方法 B) 接口中定义的方法可以编写其实现代码 C) 继承接口的类可提供被继承接口中部分成员的实现代码 D) 接口中的所有方法都必须在其派生类中得到实现。 9.下列关于虚方法的描述中,正确的是【】。 A) 虚方法能在程序执行时动态确定要调用的方法,因此比非虚方法更灵活 B) 在定义虚方法时,基类和派生类的方法定义语句中都要带上virtual修饰符 C) 在重写基类的虚方法时,为消除隐藏基类成员的警告,需要带上new修饰符 D) 在重写基类的虚方法时,需要同时带上virtual和override修饰符 10.在C#中,以下关于抽象类的叙述中错误的是【】。 A) 抽象类可以包含抽象方法B) 含有抽象方法的类一定是抽象类

相关文档
最新文档