理解 C# 泛型接口中的协变与逆变(抗变)

理解 C# 泛型接口中的协变与逆变(抗变)
理解 C# 泛型接口中的协变与逆变(抗变)

最近在看《C#高级编程(第九版)》这本书,看到了泛型接口这章。其中关于协变和逆变没太理解,讲得有点坑爹,网上查了许多资料,总算(感觉)弄清楚了,来这里记录一下。

先从字面上理解协变(Covariance)、逆变(Contravariance)。

co-是英文中表示“协同”、“合作”的前缀。协变的字面意思就是“与变化的方向相同”。

contra-是英文中表示“相反”的前缀,逆变的字面意思就是是“与变化方向相反”。

那么问题来了,这里的变化方向指的是什么?

C# 中对于对象(即对象引用),仅存在一种隐式类型转换,即子类型的对象引用到父类型的对象引用的转换。这里的变化指的就是这种子->父的类型转换。

object o = "hello";

//string (子类)类型的引用转换为 object (父类)类型的引用

协变与逆变虽然从名字上看是两个完全相反的转换,但其实只是“子类型引用到父类型引用”这一过程在函数中使用的两个不同阶段而已,接下来将详细说明这点。

假设有一函数,接收object类型的参数,输出string类型的返回值:

string Method(object o)

{

return"abc";

}

那么在Main函数中我们可以这样调用它:

string s = "abc";

object o = Method(s);

注意,这里发生了两次隐式类型转换:

1.在向函数输入时,参数s由string类型转换为object类型

2.在函数输出(返回)时,返回值由string类型转换为object类型

我们这里可以看作是函数签名可发生变换(不论函数的内容,不影响结果):

1.string Method(object o)可变换为string Method(string o)

2.string Method(string o)可变换为object Method(string o)

也就是说,在函数输入时,函数的输入类型可由object变换为string,父->子在函数输出时,函数的输出类型可由string变换为object,子->父

三、理解泛型接口中的in、out参数

没有指定in、out的情况

假设有一泛型接口,并且有一个类实现了此接口:

interface IDemo

{

T Method(T value);

}

publicclass Demo : IDemo {

//实现接口IDemo publicstring Method(stringvalue) {

returnvalue;

}

}

在Main函数中这样写:

IDemodemoStr = new Demo();

IDemodemoObj = demoStr;

上面的这段代码中的第二行包含了一个假设:

IDemo类型能够隐式转换为IDemo类型

这乍看上去就像“子类型引用转换为父类型引用” 一样,然而很遗憾,他们并不相同。假如可以进行隐式类型转换,那就意味着:

string Method(string value)能转换为object Method(object value)

从上一节中我们知道,在函数这输入和输出阶段,其类型可变化方向是不同的。所以在C#中,要想应用泛型接口类型的隐式转换,需要讨论“输入”和“输出”两种情况。

接口仅用于输出的情况,协变

interface IDemo

{

//仅将类型 T 用于输出

T Method(objectvalue);

}

publicclass Demo : IDemo {

//实现接口

publicstring Method (objectvalue) {

//别忘了类型转换!

returnvalue.ToString();

}

}

在Main函数中这样写:

IDemodemoStr = new Demo();

IDemodemoObj = demoStr;

可将string Method (object value)转换为object Method (object value)

即可将IDemo类型转换为IDemo类型。

仅从泛型的类型上看,这是“子->父” 的转换,与第一节中提到的转换方向相同,称之为“协变”。接口仅用于输入的情况,逆变

同理我们可以给T加上in参数:

interface IDemo

{

//仅将类型 T 用于输入

string Method(T value);

}

publicclass Demo : IDemo {

//实现接口

publicstring Method (objectvalue) {

returnvalue.ToString();

}

}

在Main函数中这样写:

IDemodemoObj = new Demo();

IDemodemoStr = demoObj;

这里可将string Method (object value)转换为string Method (string value)

即可将IDemo类型转换为IDemo类型。

仅从泛型的类型上看,这是“父->子” 的转换,与第一节中提到的转换方向相反,称之为“逆变”,有时也译作“抗变”或“反变”。

以上只讨论了协变与逆变在方法中的情况,其实在属性中情况也相类似,不再说明。

可能大家也发现了,所谓“协”与“逆”都是只是一种表象,其内在本质为同一过程。

“协变”与“逆变”中的“协”与“逆”表示泛型接口在将类型参数仅用于输入或输出的情况下,其类型参数的隐式转换所遵循的规律。

协变

当泛型接口类型仅用于输出(使用关键词out),其类型参数隐式转换所遵循的规律与对象引用的类型转换规律相同,称之为“协变”

逆变

当泛型接口类型仅用于输入(使用关键词in),其类型参数隐式转换所遵循的规律与对象引用的类型转换规律相反,称之为“逆变”、“抗变”或“反变”。

java泛型详解

java泛型详解 泛型(Generic type 或者generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。 可以在集合框架(Collection framework)中看到泛型的动机。例如,Map类允许您向一个Map添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如String)的对象。 因为Map.get()被定义为返回Object,所以一般必须将Map.get()的结果强制类型转换为期望的类型,如下面的代码所示: Map m = new HashMap(); m.put("key", "blarg"); String s = (String) m.get("key"); 要让程序通过编译,必须将get()的结果强制类型转换为String,并且希望结果真的是一个String。但是有可能某人已经在该映射中保存了不是String的东西,这样的话,上面的代码将会抛出ClassCastException。 理想情况下,您可能会得出这样一个观点,即m是一个Map,它将String键映射到String值。这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。 泛型的好处 Java 语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。这带来了很多好处: · 类型安全。泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。 Java 程序中的一种流行技术是定义这样的集合,即它的元素或键是公共类型的,比如“Str ing列表”或者“String到String的映射”。通过在变量声明中捕获这一附加的类型信息,泛型允许编译器实施这些附加的类型约束。类型错误现在就可以在编译时被捕获了,而不是在运行时当作 ClassCastException展示出来。将类型检查从运行时挪到编译时有助于您更容易找到错误,并可提高程序的可靠性。

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/ac4475252.html, + " and Age is " + p.Age); Console.ReadKey(); } }

接口和抽象类的区别

.Net提供了接口,这个不同于Class或者Struct的类型定义。接口有些情况,看似和抽象类一样,因此有些人认为在.Net可以完全用接口来替换抽象类。其实不然,接口和抽象类各有长处和缺陷,因此往往在应用当中,两者要结合来使用,从而互补长短。 接下来先说说抽象类和接口的区别。 区别一,两者表达的概念不一样。抽象类是一类事物的高度聚合,那么对于继承抽象类的子类来说,对于抽象类来说,属于“是”的关系;而接口是定义行为规范,因此对于实现接口的子类来说,相对于接口来说,是“行为需要按照接口来完成”。这些听起来有些虚,举个例子。例如,狗是对于所有狗类动物的统称,京哈是狗,牧羊犬是狗,那么狗的一般特性,都会在京哈,牧羊犬中找到,那么狗相对于京哈和牧羊犬来说,就属于这类事物的抽象类型;而对于“叫”这个动作来说,狗可以叫,鸟也可以叫。很明显,前者相当于所说的是抽象类,而后者指的就是接口。 区别二,抽象类在定义类型方法的时候,可以给出方法的实现部分,也可以不给出;而对于接口来说,其中所定义的方法都不能给出实现部分。 例如: public abstract class AbsTest { public virtual void Test() { Debug.WriteLine( "Test" ); } public abstract void NewTest(); } public interface ITest {

void Test(); void NewTest(); } 区别三,继承类对于两者所涉及方法的实现是不同的。继承类对于抽象类所定义的抽象方法,可以不用重写,也就是说,可以延用抽象类的方法;而对于接口类所定义的方法或者属性来说,在继承类中必须要给出相应的方法和属性实现。 区别四,在抽象类中,新增一个方法的话,继承类中可以不用作任何处理;而对于接口来说,则需要修改继承类,提供新定义的方法。 知道了两者的区别,再来说说,接口相对于抽象类的优势。 好处一,接口不光可以作用于引用类型,也可以作用于值类型。而抽象类来说,只能作用于引用类型。 好处二,.Net的类型继承只能是单继承的,也就是说一个类型只能继承一个类型,而可以继承多个接口。其实,我对于这一点也比较赞同,多继承会使继承树变的混乱。 好处三,由于接口只是定义属性和方法,而与真正实现的类型没有太大的关系,因此接口可以被多个类型重用。相对于此,抽象类与继承类的关系更紧密些。 好处四,通过接口,可以减少类型暴露的属性和方法,从而便于保护类型对象。当一个实现接口的类型,可能包含其他方法或者属性,但是方法返回的时候,可以返回接口对象,这样调用端,只能通过接口提供的方法或者属性,访问对象的相关元素,这样可以有效保护对象的其他元素。

看一下Java泛型的设计

从零开始来看一下Java泛型的设计 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除。 作者:ziwenxie来源:ziwenxie|2017-03-03 10:37 收藏 分享 引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java 泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除。 泛型基础 泛型类 我们首先定义一个简单的Box类: public class Box {

private String object; public void set(String object) { this.object = object; } public String get() { return object; } } 这是最常见的做法,这样做的一个坏处是Box里面现在只能装入String类型的元素,今后如果我们需要装入Integer 等其他类型的元素,还必须要另外重写一个Box,代码得不到复用,使用泛型可以很好的解决这个问题。 public class Box { // T stands for "Type" private T t; public void set(T t) { this.t = t; } public T get() { return t; } } 这样我们的Box类便可以得到复用,我们可以将T替换成任何我们想要的类型: Box 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()); } }

实验十 泛型与集合框架

实验十泛型与集合框架 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——内容功能完善,编程风格良好,人机接口界面良好;

接口和抽象类习题-答案

(一)选择题 1.以下哪个接口的定义是正确的? A.interface B{ void print() { } ; } B.abstract interface B { void print() ; } C.abstract interface B extends A1,A2 { abstract void print(){ }; } D.interface B { void print();} 2.定义一个接口时,下列哪个关键字用不到? A.public B.extends C.interface D.class 3.定义一个接口时,要使用如下哪个关键字? A.abstract B.final C.interface D.class 4.在使用interface声明一个接口时,只可以使用哪个修饰符修饰该接口。 A.private B.protected C.private或者protected D.public 5.下列类头定义中,错误的是? A.public x extends y B.public class x extends y C.class x extends y implements y1 D.class x 6.下列类定义中,不正确的是? A.class x B.class x extends y C.class x implements y1,y2 D.public class x extends X1,X2 7.Java中能实现多重继承功能的方式是? A.接口 B.同步 C.抽象类 D.父类 8.下列叙述正确的是? A.Java中允许多重继承 B.Java一个类只能实现一个接口 C.Java中只能单重继承 D.Java中一个类可以继承多个抽象类 (二)简答题

java泛型

Java为什么要有泛型? 答: ①在没有泛型之前,一旦把一个对象添加到java集合中去,集合就会忘记对象的类型,把所有 的对象当成Object来处理.当程序从集合中取出对象后,就需要进行强制转换类型.这种类型转换不仅代码臃肿而且容易引起ClassCastException异常. ②增加了泛型支持后的集合,完全可以记住集合中的元素类型,并可以在编译时检查集合中 元素的类型,如果试图想集合中添加不满足类型要求的对象,编译器就会提示错误.增加泛型的集合,可以让代码更加简洁,程序更加健壮(java泛型可以保证如果程序在编译时候没有警告,运行时就不会产生ClassCastException). ③如果不设计泛型,那么集合中就可以装任何类型,所有可能引起异常。由于把对象丢进 集合时,集合失去了对象的状态信息,集合只知道它装的是Object类型元素,因此不仅麻烦还容易引起异常。 泛型 所谓泛型,就是允许在定义类、接口时指定类型形参,这个类型参数将在申明变量。创建对象时确定(既传入实际的类型参数,也可称为类型参数)。 代码欣赏:

上面三个接口定义的比较简单,除了尖括号中的内容—这就是泛型的实质:允许在定义接口、类时指定类型形参。类型形参在整个接口。类体内中可以当成类型使用,几乎所有可以使用其他普通类型的地方都可以使用这种类型参数。 泛型到底是什么?: 上面程序定义了一个带泛型声明的Apple类(先不要理会这个类型参数是否具有实际意义),实际使用Apple类的使用,必须给T传入实际类型。这样就生成了如Apple,Apple…等形式的逻辑子类(逻辑上不存在的子类)。 怎么使用泛型? 在开放中当我们需要一个父类,而父类中的方法或字段需要用到子类类型但是并不能确定到底要使用那一个子类类型或者遇到不知道子类具体类型,或者子类太多,不能写死一种子类时既可以给父类定义泛型,当实例化父类对象(或者使用父类对象创建子类对象时—多态)时再传入指定子类类型。

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取得任何已知名称的类的

接口和抽象类习题-答案

一)选择题 1. 以下哪个接口的定义是正确的? A. interface B{ void print() { } ; } B. abstract interface B { void print() ; } C. ab stract interface B extends A1,A2 { abstract void print(){ }; } D. interface B { void print();} 2. 定义一个接口时,下列哪个关键字用不到? A. public B. extends C. interface D. class 3. 定义一个接口时,要使用如下哪个关键字? A. abstract B. final C. interface D. class 4. 在使用interface 声明一个接口时,只可以使用哪个修饰符修饰该接口。 A. private B. protected C. private 或者protected D. public 5. 下列类头定义中,错误的是

A. public x extends y B. public class x extends y C. class x extends y implements y1 D. class x 6. 下列类定义中,不正确的是? A. class x B. class x extends y C. class x implements y1,y2 D. public class x extends X1,X2 7. Java 中能实现多重继承功能的方式是? A. 接口 B侗步 C. 抽象类 D. 父类 8. 下列叙述正确的是? A. Java 中允许多重继承 B. Java 一个类只能实现一个接口 C. Java 中只能单重继承 D. Java 中一个类可以继承多个抽象类 (二)简答题 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这个引用类型时,我们需要在

16JAVA第六单元练习题 泛型与集合

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()+""); } }

C#抽象类和接口的区别

C#抽象类和接口的区别

c#接口和抽象类的区别大家都容易把这两者搞混,我也一样,在听李建忠老师的设计模式时,他也老把抽象类说成接口,弄的我就更糊涂了,所以找了些网上的资料. 一、抽象类: 抽象类是特殊的类,只是不能被实例化;除此以外,具有类的其他特性;重要的是抽象类可以包括抽象方法,这是普通类所不能的。抽象方法只能声明于抽象类中,且不包含任何实现,派生类必须覆盖它们。另外,抽象类可以派生自一个抽象类,可以覆盖基类的抽象方法也可以不覆盖,如果不覆盖,则其派生类必须覆盖它们。 二、接口: 接口是引用类型的,类似于类,和抽象类的相似之处有三点: 1、不能实例化; 2、包含未实现的方法声明; 3、派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员(不仅是方法包括其他成员); 另外,接口有如下特性: 接口除了可以包含方法之外,还可以包含属性、索引器、事件,而且这些成员都被定义为公有的。除此之外,不能包含任何其他的成员,例如:常量、域、构造函数、析构函数、静态成员。一个类可以直接继承多个接口,但只能直接继承一个类(包括抽象类)。 三、抽象类和接口的区别: 1.类是对对象的抽象,可以把抽象类理解为把类当作对象,抽象成的类叫做抽象类.而接口只是一个行为的规范或规定,微软的自定义接口总是后带able字段,证明其是表述一类类“我能做。。。”.抽象类更多的是定义在一系列紧密相关的类间,而接口大多数是关系疏松但都实现某一功能的类中. 2.接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法; 3.一个类一次可以实现若干个接口,但是只能扩展一个父类 4.接口可以用于支持回调,而继承并不具备这个特点. 5.抽象类不能被密封。 6.抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,当然您也可以声明为虚的. 7.(接口)与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上。 8.抽象类实现了oop中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义为不可变的,而把可变的座位子类去实现。 9.好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。 10.尽量避免使用继承来实现组建功能,而是使用黑箱复用,即对象组合。因为继承的层次增多,造成最直接的后果就是当你调用这个类群中某一类,就必须把他们全部加载到栈中!

Java泛型详解

Java 泛型 1 什么是泛型 (2) 2 泛型类跟接口及泛型方法 (3) 2.1 泛型类跟接口及继承 (3) 2.1.1泛型类 (3) 2.1.2继承 (3) 2.1.3接口 (3) 2.2 泛型方法 (3) 2.2.1 方法 (3) 2.2.2 类型推断 (4) 3 泛型实现原理 (5) 4 泛型数组 (6) 5边界 (7) 6通配符 (8) 7 泛型的问题及建议 (9) 7.1问题 (9) 7.2 建议 (9)

1 什么是泛型 从jdk1.5开始,Java中开始支持泛型了。泛型是一个很有用的编程工具,给我们带来了极大的灵活性。在看了《java核心编程》之后,我小有收获,写出来与大家分享。 所谓泛型,我的感觉就是,不用考虑对象的具体类型,就可以对对象进行一定的操作,对任何对象都能进行同样的操作。这就是灵活性之所在。但是,正是因为没有考虑对象的具体类型,因此一般情况下不可以使用对象自带的接口函数,因为不同的对象所携带的接口函数不一样,你使用了对象A的接口函数,万一别人将一个对象B传给泛型,那么程序就会出现错误,这就是泛型的局限性。所以说,泛型的最佳用途,就是用于实现容器类,实现一个通用的容器。该容器可以存储对象,也可以取出对象,而不用考虑对象的具体类型。因此,在学习泛型的时候,一定要了解这一点,你不能指望泛型是万能的,要充分考虑到泛型的局限性。下面我们来探讨一下泛型的原理以及高级应用。首先给出一个泛型类: public class Pair { public Pair() { first = null; second = null; } public Pair(T first, T second) { this.first = first; this.second = second; } public T getFirst() { return first; } public T getSecond() { return second; } public void setFirst(T newValue) { first = newValue; } public void setSecond(T newValue) { second = newValue; } private T first; private T second; } 我们看到,上述Pair类是一个容器类(我会多次强调,泛型天生就是为了容器类的方便实现),容纳了2个数据,但这2个数据类型是不确定的,用泛型T来表示。关于泛型类如何使用,那是最基本的内容,在此就不讨论了。

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

泛型可提高代码的高扩展性和重用率. 1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。 2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。 3、泛型的类型参数可以有多个。 4、泛型的参数类型可以使用extends语句,例如。习惯上称为“有界类型”。 5、泛型的参数类型还可以是通配符类型。例如Class classType = Class.forName("https://www.360docs.net/doc/ac4475252.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;

抽象类与接口的区别

抽象类与接口的区别 abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。 其实,两者之间还是有很大的区别的,对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析,试图给开发者提供一个在二者之间进行选择的依据。 一、理解抽象类 abstract class和interface在Java语言中都是用来进行抽象类(本文中的抽象类并非从abstract class翻译而来,它表示的是一个抽象体,而abstract class为Java语言中用于定义抽象类的一种方法,请读者注意区分)定义的,那么什么是抽象类,使用抽象类能为我们带来什么好处呢? 在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。 比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。 在面向对象领域,抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。熟悉OCP的读者一定知道,为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类是其中的关键所在。 二、从语法定义层面看abstract class和interface 在语法层面,Java语言对于abstract class和interface给出了不同的定义方式,下面以定义一个名为Demo的抽象类为例来说明这种不同。使用abstract class的方式定义Demo抽象类的方式如下: java 代码 abstract class Demo { abstract void method1(); abstract void method2(); …

实验七: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题调试结果如下图:

java泛型详解

Java 泛型详解 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java 泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除。 泛型基础 泛型类 我们首先定义一个简单的Box类: public class Box { private String object; public void set(String object) { this.object = object; } public String get() { return object; }}这是最常见的做法,这样做的一个坏处是Box里面现在只能装入String类型的元素,今后如果我们需要装入Integer等其他类型的元素,还必须要另外重写一个Box,代码得不到复用,使用泛型可以很好的解决这个问题。 public class Box { // T stands for 'Type' private T t; public void set(T t) { this.t = t; } public T get() { return t; }} 这样我们的Box类便可以得到复用,我们可以将T替换成任何我们想要的类型: Box 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()); }}public class Pair { private K key; private V value; public Pair(K key, V value) { this.key = key; this.value = value; } public void setKey(K key) { this.key = key; } public void setValue(V value) { this.value = value; } public K getKey() { return key; } public V getValue() { return value; }} 我们可以像下面这样去调用泛型方法: Pair p1 = new Pair(1, 'apple');Pair p2 = new Pair(2, 'pear');boolean same = https://www.360docs.net/doc/ac4475252.html,pare(p1, p2); 或者在Java1.7/1.8利用type inference,让Java自动推导出相应的类型参数: Pair p1 = new Pair(1, 'apple');Pair p2 = new Pair(2, 'pear');boolean same = https://www.360docs.net/doc/ac4475252.html,pare(p1, p2);