1. IList 接口与List的区别是什么?

IList 泛型接口是 Icollection 接口的子代,并且是所有非泛型列表的基接口。 Ilist 实现有三种类别:只读、固定大小、可变大小。 无法修改只读 Ilist。 固定大小的 Ilist 不允许添加或移除元素,但允许修改现有元素。 可变大小的 Ilist 允许添加、移除和修改元素。

IList 是个接口,定义了一些操作方法这些方法要你自己去实现,当你只想使用接口的方法时,这种方式比较好.他不获取实现这个接口的类的其他方法和字段,有效的节省空间.

List 是个类型 已经实现了IList 定义的那些方法。

  1. List List11 =new List ();

是想创建一个List,而且需要使用到List的功能,进行相关操作。

IList IList11 =new List ();

只是想创建一个基于接口IList的对象的实例,只是这个接口是由List实现的。所以它只是希望使用到IList接口规定的功能而已。

2.泛型的主要约束和次要约束是什么?

当一个泛型参数没有任何约束时,它可以进行的操作和运算是非常有限的,因为不能对实参进行任何类型上的保证,这时候就需要用到泛型约束。泛型的约束分为:主要约束和次要约束,它们都使实参必须满足一定的规范,C#编译器在编译的过程中可以根据约束来检查所有泛型类型的实参并确保其满足约束条件。
(1)主要约束

一个泛型参数至多拥有一个主要约束,主要约束可以是一个引用类型、class或者struct。如果指定一个引用类型(class),那么实参必须是该类型或者该类型的派生类型。相反,struct则规定了实参必须是一个值类型。下面的代码展示了泛型参数主要约束:

public class ClassT1<T> where T : Exception
{
    private T myException;
    public ClassT1(T t)
{
        myException = t;
    }
    public override string ToString()
{
        // 主要约束保证了myException拥有source成员
        return myException.Source;
    }
}

public class ClassT2<T> where T : class
{
    private T myT;
    public void Clear()
{
        // T是引用类型,可以置null
        myT = null;
    }
}

public class ClassT3<T> where T : struct
{
    private T myT;
    public override string ToString()
{
        // T是值类型,不会发生NullReferenceException异常
        return myT.ToString();
    }

(2)次要约束
次要约束主要是指实参实现的接口的限定。对于一个泛型,可以有0到无限的次要约束,次要约束规定了实参必须实现所有的次要约束中规定的接口。次要约束与主要约束的语法基本一致,区别仅在于提供的不是一个引用类型而是一个或多个接口。例如我们为上面代码中的ClassT3增加一个次要约束:

public class ClassT3<T> where T : struct, IComparable
{
    ......      
}

3. 如何把一个array复制到arrayist里?

foreach( object arr in array)
{
  arrayist.Add(arr);
}

4.List, Set, Map是否继承自Collection接口?

List,Set是,Map不是

5. Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?

Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。

equals()和==方法决定引用值是否指向同一对像,equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。

6.有50万个int类型的数字,现在需要判断一下里面是否存在重复的数字,请你简要说一下思路。

1.使用C#的List集合自带的去重方法,例如 Distinct(),GroupBy()等

2.利用 Dictionary 的Key值唯一的特性,HashSet 元素值唯一的特性 进行判断

7.数组有没有length()这个方法? String有没有length()这个方法?

数组没有length()这个方法,有length的属性。String有有length()这个方
法。

8.一个整数List中取出最大数(找最大值)。不能用Max方法。

          private static int GetMax(List<int> list)
        {
            int max = list[0];
            for (int i = 0; i < list.Count; i++)
            {
                if (list[i]>max)
                {
                    max = list[i];
                }
            }
            return max;
        }

9. C#异常类有哪些信息?

C#中,所有异常都继承自System.Exception类,Exception类定义了C#异常应该具有的信息和方法。值得注意的属性有:

public virtual string Message { get; }// 错误的信息,文字描述
public virtual string StackTrace { get; }// 发生异常的调用堆栈信息
public System.Reflection.MethodBase TargetSite { get; }//引发这个错误的方法
public Exception InnerException { get; }// 子异常

10. 如何创建一个自定义异常?

根据类继承原则和异常处理原则,我们可以使用以下方式来自定义一个类:

public class CustomException : Exception
{
}

11. 利用IEnumerable实现斐波那契数列生成?

  IEnumerable<int> GenerateFibonacci(int n)
{
    if (n >= 1) yield return 1;

    int a = 1, b = 0;
    for (int i = 2; i <= n; ++i)
    {
        int t = b;
        b = a;
        a += t;

        yield return a;
    }
}

12.请利用 foreach 和 ref 为一个数组中的每个元素加 1

注意 foreach 不能用 var ,也不能直接用 int ,需要 ref int ,注意 arr 要转换为 Span 。

int[] arr = { 1, 2, 3, 4, 5};
Console.WriteLine(string.Join(",", arr)); // 1,2,3,4,5

foreach (ref int v in arr.AsSpan())
{
    v++;
}

Console.WriteLine(string.Join(",", arr)); // 2,3,4,5,6

13.如何针对不同的异常进行捕捉?

  public class Program
    {
        public static void Main(string[] args)
        {
            Program p = new Program();
            p.RiskWork();

            Console.ReadKey();
        }

        public void RiskWork()
        {
            try
            {
                // 一些可能会出现异常的代码
            }
            catch (NullReferenceException ex)
            {
                HandleExpectedException(ex);
            }
            catch (ArgumentException ex)
            {
                HandleExpectedException(ex);
            }
            catch (FileNotFoundException ex)
            {
                HandlerError(ex);
            }
            catch (Exception ex)
            {
                HandleCrash(ex);
            }
        }

        // 这里处理预计可能会发生的,不属于错误范畴的异常
        private void HandleExpectedException(Exception ex)
        {
            // 这里可以借助log4net写入日志
            Console.WriteLine(ex.Message);
        }

        // 这里处理在系统出错时可能会发生的,比较严重的异常
        private void HandlerError(Exception ex)
        {
            // 这里可以借助log4net写入日志
            Console.WriteLine(ex.Message);
            // 严重的异常需要抛到上层处理
            throw ex; 
        }

        // 这里处理可能会导致系统崩溃时的异常
        private void HandleCrash(Exception ex)
        {
            // 这里可以借助log4net写入日志
            Console.WriteLine(ex.Message);
            // 关闭当前程序
            System.Threading.Thread.CurrentThread.Abort();
        }
    }

14.如何避免类型转换时的异常?

其中有些是确定可以转换的(比如将一个子类类型转为父类类型),而有些则是尝试性的(比如将基类引用的对象转换成子类)。当执行常识性转换时,我们就应该做好捕捉异常的准备。

当一个不正确的类型转换发生时,会产生InvalidCastException异常,有时我们会用try-catch块做一些尝试性的类型转换,这样的代码没有任何错误,但是性能却相当糟糕,为什么呢?异常是一种耗费资源的机制,每当异常被抛出时,异常堆栈将会被建立,异常信息将被加载,而通常这些工作的成本相对较高,并且在尝试性类型转换时,这些信息都没有意义。

在.NET中提供了另外一种语法来进行尝试性的类型转换,那就是关键字 is 和 as 所做的工作。

(1)is 只负责检查类型的兼容性,并返回结果:true 和 false。→ 进行类型判断

  public static void Main(string[] args)
    {
        object o = new object();
        // 执行类型兼容性检查
        if(o is ISample)
        {
            // 执行类型转换
            ISample sample = (ISample)o;
            sample.SampleShow();
        }

        Console.ReadKey();
    }

(2)as 不仅负责检查兼容性还会进行类型转换,并返回结果,如果不兼容则返回 null 。→ 用于类型转型

  public static void Main(string[] args)
    {
        object o = new object();
        // 执行类型兼容性检查
        ISample sample = o as ISample;
        if(sample != null)
        {
            sample.SampleShow();
        }
        Console.ReadKey();
    }

两者的共同之处都在于:不会抛出异常!综上比较,as 较 is 在执行效率上会好一些,在实际开发中应该量才而用,在只进行类型判断的应用场景时,应该多使用 is 而不是 as。

15.Serializable特性有什么作用?

通过上面的流类型可以方便地操作各种字节流,但是如何把现有的实例对象转换为方便传输的字节流,就需要使用序列化技术。对象实例的序列化,是指将实例对象转换为可方便存储、传输和交互的流。在.NET中,通过Serializable特性提供了序列化对象实例的机制,当一个类型被申明为Serializable后,它就能被诸如BinaryFormatter等实现了IFormatter接口的类型进行序列化和反序列化。

16.委托是什么?

委托是寻址的.NET版本。在C++中,函数指针只不过是一个指向内存位置的指针,它不是类型安全的。我们无法判断这个指针实际指向什么,像参数和返回类型等项久更无从知晓了。

而.NET委托完全不同,委托是类型安全的类,它定义了返回类型和参数的类型。委托类不仅包含对方法的引用,也可以包含对多个方法的引用。

17.如何自定义委托?

声明一个委托类型,它的实例引用一个方法,该方法获取一个int参数,返回void。

  public delegate void Feedback(int num);

理解委托的一个要点是它们的安全性非常高。在定义委托时,必须给出它所表示的方法的签名和返回类型等全部细节。

理解委托的一种比较好的方式是把委托当作这样一件事情:它给方法的签名和返回类型指定名称。

其语法类似于方法的定义,需要在定义方法的前面加上delegate关键字。定义委托基本上就是定义一个新的类,所以可以在任何地方定义类的相同地方定义委托,也就是说,可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在名称控件中把委托定义为定义为顶层对象。访问修饰符可以是public/private/protected等。

18 .NET默认的委托类型有哪几种?

  1. Action < T >

泛型Action委托表示引用一个void返回类型的方法。这个委托类存在16种重载方法。

例如Action调用没有参数的方法

2.Func< T >

Func调用带返回类型的方法。有16种重载方法。

例如Func委托类型可以调用带返回类型且无参数的方法,Func委托类型调用带有4个参数和一个返回类型的方法。

19.什么是泛型委托?

Action就是泛型委托。

注意事项:

1.建议尽量使用这些委托类型,而不是在代码中定义更多的委托类型。这样可以减少系统中的类型数目,同时简化编码

2.如果需要使用ref或out关键字,以传引用的方式传递一个参数,就可能不得不定义自己的委托:

delegate void Test(ref int i)

3.如果委托要通过C#的params关键字获取可变数量的额参数,要为委托的任何桉树指定默认值,或者要对委托的泛型类型参数进行约束,也必须定义自己的委托类型

delegate void EventHandler(Object sender, TEventArgs e)
where TEventArgs : EventArgs;

4.使用获取泛型实参和返回值的委托时,可利用逆变与协变。逆变:父类转换为子类;协变:子类转换为父类

20. 什么事匿名方法?

匿名方法是用作委托的参数的一段代码。

  //匿名方法,例1
Func<int, int> anon = delegate(int i)
{
        i = i+1;
       return i;
};
//输出2
Console.WriteLine(anon(1));
//匿名方法,例2
Action<int> anon2 = delegate(int i)
{
        i = i + 1;
};
//输出2
Console.WriteLine(anon(1));

21.什么是闭包?

通过Lambda表达式可以访问Lambda表达式块外部的变量,这成为闭包。

当引用外部变量时,需要注意,外部变量变化时,lambda表达式的结果也可能会随着外部变量变化而变化。

如下面的例子:

int y = 5;
Func<int, int> lambda = x => x + y;
Console.WriteLine(lambda(1));
y = 10;
Console.WriteLine(lambda(1));

22.EF(Entity Framework)是什么?

实体框架EF是http://ADO.NET中的一组支持开发面向数据的软件应用程序的技术,是微软的一个ORM框架。

主要有三种方式:

Database FirstDatabase First”模式

我们称之为“数据库优先”,前提是你的应用已经有相应的数据库,你可以使用EF设计工具根据数据库生成数据数据类,你可以使用Visual Studio模型设计器修改这些模型之间对应关系。

来自 https://blog.csdn.net/u011854789/article/details/72783902 Model FirstModel First我们称之为“模型优先”,这里的模型指的是“ADO.NET Entity Framework Data Model”,此时你的应用并没有设计相关数据库,在Visual Studio中我们通过设计对于的数据模型来生成数据库和数据类。

Code FirstCode First模式我们称之为“代码优先”模式,是从EF4.1开始新建加入的功能。

使用Code First模式进行EF开发时开发人员只需要编写对应的数据类(其实就是领域模型的实现过程),然后自动生成数据库。这样设计的好处在于我们可以针对概念模型进行所有数据操作而不必关心数据的存储关系,使我们可以更加自然的采用面向对象的方式进行面向数据的应用程序开发。

23.什么是ORM?

ORM指的是面向对象的对象模型和关系型数据库的数据结构之间的互相转换。

(表实体跟表之间的相互转换)

ORM框架有很多,EF框架是ORM框架的其中一种,是实现了ORM思想的框架。

O=>表实体

M=>映射关系

R=>数据库.表

24.为什么用EF而不用原生的ADO.NET?

1.极大的提高开发效率:EF是微软自己的产品,开发中代码都是强类型的,
xiefl代码效率非常高,自动化程度非常高,命令式的编程.

2.EF提供的模型设计器非常强大,不仅仅带来了设计数据库的革命,也附带来的自动化模型代码的
功能也极大的提高开发和架构设计的效率.

3.EF跨数据支持的是ORM框架主要功能点之一,带来的是可以通过仅仅改变配置就可以做到跨数据库的能力

25.如何提高LINQ性能问题?

提升从数据库中拿数据的速度,可以参考以下几种方法:

1.在数据库中的表中定义合适的索引和键

2.只获得你需要的列(使用ViewModel或者改进你的查询)和行(使用IQueryable)

3.尽可能使用一条查询而不是多条

4.只为了展示数据,而不进行后续修改时,可以使用AsNoTracking。它不会影响生成的SQL,但它可以令系统少维护很多数据,从而提高性能

5.使用Reshaper等工具,它可能会在你写出较差的代码时给出提醒

26.什么是协变和逆变?

可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用。其对应的术语则是不变性(invariant)。

可变性:

可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用。例如对普通继承中的可变性:若某方法声明返回类型为Stream,在实现时可以返回一个MemoryStream。可变性有两种类型:协变和逆变。

协变性:

可以建立一个较为一般类型的变量,然后为其赋值,值是一个较为特殊类型的变量。例如:

string str = "test";
// An object of a more derived type is assigned to an object of a less derived type. 
object obj = str;

因为string肯定是一个object,所以这样的变化非常正常。

逆变性:在上面的例子中,我们无法将str和一个新的object对象画等号。如果强行要实现的话,只能这么干:

string s = (string) new object();

但这样还是会在运行时出错。这也告诉我们,逆变性是很不正常的。

泛型的协变与逆变:

协变性和out关键字搭配使用,用于向调用者返回某项操作的值。例如下面的接口仅有一个方法,就是生产一个T类型的实例。那么我们可以传入一个特定类型。如我们可以将IFactory视为IFactory。这也适用于Food的所有子类型。(即将其视为一个更一般类型的实现)

    interface IFactory<T>
    {
        T CreateInstance();
    }

逆变性则相反,和in关键字搭配使用,指的是API将会消费值,而不是生产值。此时一般类型出现在参数中:

    interface IPrint<T>
    {
        void Print(T value);
    }

这意味着如果我们实现了IPrint< Code >,我们就可以将其当做IPrint< CsharpCode >使用。(即将其视为一个更具体类型的实现)

如果存在双向的传递,则什么也不会发生。这种类型是不变体(invariant)。

     interface IStorage<T>
    {
        byte[] Serialize(T value);
        T Deserialize(byte[] data);
    }

这个接口是不变体。我们不能将它视为一个更具体或更一般类型的实现。

假设有如下继承关系People –> Teacher,People –> Student。

如果我们以协变的方式使用(假设你建立了一个IStorage< Teacher >的实例,并将其视为IStorage)则我们可能会在调用Serialize时产生异常,因为Serialize方法不支持协变(如果参数是People的其他子类,例如Student,则IStorage< Teacher >将无法序列化Student)。

如果我们以逆变的方式使用(假设你建立了一个IStorage的实例,并将其视为IStorage< Teacher >),则我们可能会在调用Deserialize时产生异常,因为Deserialize方法不支持逆变,它只能返回People不能返回Teacher。

27.什么是IEnumerable?

IEnumerable及IEnumerable的泛型版本IEnumerable是一个接口,它只含有一个方法GetEnumerator。Enumerable这个静态类型含有很多扩展方法,其扩展的目标是IEnumerable。

实现了这个接口的类可以使用Foreach关键字进行迭代(迭代的意思是对于一个集合,可以逐一取出元素并遍历之)。实现这个接口必须实现方法GetEnumerator。

28.IEnumerable的缺点有哪些?

IEnumerable功能有限,不能插入和删除。

访问IEnumerable只能通过迭代,不能使用索引器。迭代显然是非线程安全的,每次IEnumerable都会生成新的IEnumerator,从而形成多个互相不影响的迭代过程。

在迭代时,只能前进不能后退。新的迭代不会记得之前迭代后值的任何变化。

28.延迟执行 (Lazy Loading)是什么?

大部分LINQ语句是在最终结果的第一个元素被访问的时候(即在foreach中调用MoveNext方法)才真正开始运算的,这个特点称为延迟执行。一般来说,返回另外一个序列(通常为IEnumerable或IQueryable)的操作,使用延迟执行,而返回单一值的运算,使用立即执行。

IEnumerable是延迟执行的,当没有触发执行时,就不会进行任何运算。Select方法不会触发LINQ的执行。一些触发的方式是:foreach循环,ToList,ToArray,ToDictionary方法等

29.LINQ可视化工具简单介绍一下?

LINQPad工具是一个很好的LINQ查询可视化工具。它由Threading in C#和C# in a Nutshell的作者Albahari编写,完全免费。它的下载地址是http://www.linqpad.net/

进入界面后,LINQPad可以连接到已经存在的数据库(不过就仅限微软的SQL Server系,如果要连接到其他类型的数据库则需要安装插件)。某种程度上可以代替SQL Management Studio,是使用SQL Management Studio作为数据库管理软件的码农的强力工具,可以用于调试和性能优化(通过改善编译后的SQL规模)。

LINQPad支持使用SQL或C#语句(点标记或查询表达式)进行查询。你也可以通过点击橙色圈内的各种不同格式,看到查询表达式的各种不同表达方式:

Lambda:查询表达式的Lambda表达式版本,
SQL:由编译器转化成的SQL,通常这是我们最关心的部分,
IL:IL语言

29.LINQ to Object和LINQ to SQL有何区别?

LINQ to SQL可以将查询表达式转换为SQL语句,然后在数据库中执行。相比LINQ to Object,则是将查询表达式直接转化为Enumerable的一系列方法,最终在C#内部执行。LINQ to Object的数据源总是实现IEnumerable(所以不如叫做LINQ to IEnumerable),相对的,LINQ to SQL的数据源总是实现IQueryable并使用Queryable的扩展方法。

将查询表达式转换为SQL语句并不保证一定可以成功。

30.除了EF,列举出你知道的ORM框架?

dapper EntityFramework、 EJB、Hibernate、IBATIS、TopLink、OJB

31.如何如何获取EF生成的Sql脚本?

1.可以调试起来通过SqlServerProfiler 来获取Sql

2.EF Dbcontext 注册日志事件输出日志查看Sql

32.在哪些类型额项目中你会选择EF? 为什么?

这个要结合EF的特点来说:EF主要是以面向对象的思想来做数据库数据操作,对Sql语句能力没什么要求,开发使用效率高!便于上手,一般来说,使用EF框架,肯定会比直接使用ADO.NET,消耗的时间多一些。 所以在一般企业级开发,管理型系统,对数据性能要求不是特别高的情况下,优先选择EF,这样可以大大的推进开发效率!如果像一些互联网项目中,对性能要求精度很高!可以另外做技术选型,选择原生ADO.NET。

33.请说明EF中映射实体对象的几种状态?

Detached:该实体未由上下文跟踪。刚使用新运算符或某个 System.Data.Entity.DbSet Create 方法创建实体后,实体就处于此状态。

Unchanged:实体将由上下文跟踪并存在于数据库中,其属性值与数据库中的值相同。

Added:实体将由上下文跟踪,但是在数据库中还不存在。

Deleted:实体将由上下文跟踪并存在于数据库中,但是已被标记为在下次调用 SaveChanges 时从数据库中删除。

Modified:实体将由上下文跟踪并存在于数据库中,已修改其中的一些或所有属性值。

34.如果实体名称和数据库表名不一致,该如何处理?

实体名称和数据库表名称不一致:可以通过使用TableAttribute 特性;

35. 泛型的优点有哪些?

代码的可重用性。无需从基类型继承,无需重写成员。

扩展性好。

类型安全性提高。 泛型将类型安全的负担从你那里转移到编译器。 没有必要编写代码来测试正确的数据类型,因为它会在编译时强制执行。 降低了强制类型转换的必要性和运行时错误的可能性。

性能提高。泛型集合类型通常能更好地存储和操作值类型,因为无需对值类型进行装箱。

36.try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

会执行,在return前执行。

37.C# 中的异常类有哪些?

C# 异常是使用类来表示的,异常类主要是直接或间接地派生于 System.Exception 类。

System.ApplicationException 和 System.SystemException 类是派生于 System.Exception 类的异常类。

System.ApplicationException 类支持由应用程序生成的异常,所以我们自己定义的异常都应派生自该类。

System.SystemException 类是所有预定义的系统异常的基类。

System.IO.IOException 用于处理 I/O 错误(读写文件)。

System.IndexOutOfRangeException 用于处理当方法指向超出范围的数组索引时生成的错误。

System.ArrayTypeMismatchException 用于处理当数组类型不匹配时生成的错误。

System.NullReferenceException 用于处理当依从一个空对象时生成的错误。

System.DivideByZeroException 用于处理当除以零时生成的错误。例如:100/0就会报这个错误。

System.InvalidCastException 用于处理在类型转换期间生成的错误。

System.OutOfMemoryException 用于处理空闲内存不足生成的错误。

System.StackOverflowException 用于处理栈溢出生成的错误。

38.泛型有哪些常见的约束?

泛型约束 public void GetEntity() where T:class

where T :struct //约束T必须为值类型

where K : class //约束K必须为引用类型

where V : IComparable //约束V必须是实现了IComparable接口

where W : K //要求W必须是K类型,或者K类型的子类

where X :class ,new () // 或者写出 new class() ; X必须是引用类型,并且要有一个无参的构造函数(对于一个类型有多有约束,中间用逗号隔开)

39.Collection和Collections的区别?

Collection 是集合类的上级接口,Collections 是针对集合类的一个帮助类,它提供一系列静态方法来实现对各种集合的搜索,排序,线程安全化操作。

40.能用foreach 遍历访问的对象的要求?

需要实现IEnumerable接口或声明GetEnumerator方法的类型。

41.说出五个集合类?

List:泛型类;

Stack:堆栈,后进先出的访问各个元素

Dictionary:字典类,key是区分大小写;value用于存储对应于key的值

HashSet:此集合类中不能有重复的子元素

SortedList:排序列表,key是排好序的数组。

42.C#可否对内存进行直接的操作?

C#在Unsafe 模式下可以使用指针对内存进行操作, 但在托管模式下不可以使用指针。

1.在 Visual Studio 开发环境中设置/unsafe(启用不安全模式)编译器选项
打开项目的“属性”页。
单击“生成”属性页。
选中“允许不安全代码”复选框。

2.unsafe关键字表示不安全上下文,该上下文是任何涉及指针的操作所必需的。

可以在类型或成员的声明中使用 unsafe修饰符。

因此,类型或成员的整个正文范围均被视为不安全上下文。例如,以下是用 unsafe 修饰符声明的方法:

unsafe static void FastCopy(byte[] src, byte[] dst, int count)
{
    // Unsafe context: can use pointers here.
}

不安全上下文的范围从参数列表扩展到方法的结尾,因此指针在以下参数列表中也可以使用:

unsafe static void FastCopy ( byte* ps, byte* pd, int count ) {...}

还可以使用不安全块从而能够使用该块内的不安全代码。例如:

unsafe
{
    // Unsafe context: can use pointers here.
}

若要编译不安全代码,必须指定 /unsafe编译器选项。
无法通过公共语言运行库验证不安全代码。

43.HashMap和Hashtable区别?

Collection是集合类的上级接口,Collections是针对集合类的一个帮助类,它提供一系列静态方法来实现对各种集合的搜索,排序,线程安全化操作。