Java 集合和泛型,java开发面试笔试题


我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。
扫描二维码或搜索下图红色VX号,加VX好友,拉你进【程序员面试学习交流群】免费领取。也欢迎各位一起在群里探讨技术。
推荐文章:Java 面试知识点解析Mysql优化技巧(数据库设计、命名规范、索引优化

一、集合(Collections)

Java使用集合来组织和管理对象。

1、Java的集合类

集合类主要负责保存、盛装和管理对象,因此集合类也被称为容器类。

集合类分为Set、List、Map和Queue四大体系。




  •  
  • Set 代表无序、不可重复集合;


     
  • List 代表有序、可重复集合;


     
  • Map 代表具有映射关系元素的集合;


     
  • Queue 代表队列,实现元素的先进先出管理。


     

数组也是一种集合类,它是能随机存储和访问引用序列的诸多方法中最高效的一种,当追求高效的数据访问时,数组是很不错的选择。

2、集合与泛型

所有集合类都位于java.util包中,集合中只能保存对象的引用。集合类把它所含有的元素看成是Object的实例,这样方便但是也有隐患,即多个类型不同的元素被放入一个集合中,会增加集合访问时类型转换的困难,甚至会产生错误。

泛型的引入改善了这种情况,使用泛型来限制集合里元素的类型,并让集合记住元素的类型。这样可以允许编译器检查加入集合的元素类型,避免值类型不一致的错误。

3、Java集合框架介绍

集合框架是一个用来表示和操作集合的统一架构,包含实现集合的接口和类。

Java的整个集合框架围绕一组标准接口设计,开发者可以直接使用这些接口的标准实现,也可以使用集合框架接口实现自定义的集合实现类。

集合框架的设计应满足一下三个目标:




  •  
  • 高性能。保证算法的实现效率。


     
  • 互操作性。


     
  • 高扩展性。对集合进行扩展是简单的,只需要实现特定接口即可。


     

4、Java集合框架基于统一的方式组织和管理对象,包含3个方面:




  •  
  • 接口。接口定义了集合操作的行为规约,它形成集合的高层视图。


     
  • 实现类。是集合接口的具体表现。本质上说,是可重复使用的数据结构。


     
  • 算法。实现集合操作中常用的算法,比如搜索和排序。这些算法通过多态实现,即相同的方法在相似的接口上有着不同的实现


     

5、集合接口

集合框架定义了一组接口,接口申明了对特定类型的集合可以执行的操作。

Java的集合类主要由两个接口派生而出——CollectionMap,它们是Java集合框架的根接口。

Collection接口的子接口:




  •  
  • java.util.List


     
  • java.util.Set


     
  • java.util.SortedSet


     
  • java.util.NavigableSet


     
  • java.util.Queue


     
  • java.util.concurrent.BlockingQueue


     
  • java.util.concurrent.TransferQueue


     
  • java.util.Deque


     
  • java.util.concurrent.BlockingDeque


     

Map接口的子接口:




  •  
  • java.util.SortedMap


     
  • java.util.NavigableMap


     
  • java.util.concurrent.ConcurrentMap


     
  • java.util.concurrent.ConcurrentNavigableMap


     

6、集合类

标准集合类实现了Collection接口,其中一些是抽象类,实现部分接口,其它是具体类,可以直接在代码中使用。

常见的集合类
Interface Hash Table Resizable Array Balanced Tree Linked List  

Hash Table+

 

Linked List


 
Set HashSet   TreeSet   LinkedHashSet
List   ArrayList   LinkedList  
Deque   ArrayDeque   LinkedList  
Map HashMap   TreeMap   LinkedHashMap

所有实现Collection接口的类都必须提供两个标准的构造函数:




  •  
  • 无参构造函数——用于创建一个空的Collection;


     
  • 使用Collection类型作为参数的构造函数——用于创建一个新的Collection,目的是复制。


     

二、泛型(Generics)

泛型允许在定义类、接口和方法时使类型(类、接口)成为参数,声明的类型参数在使用时用具体的类型替换。

泛型主要应用在集合框架中。

1、为什么使用泛型




  •  
  • 提高程序的类型安全;泛型的使用让编译器可以验证类型假设。


     
  • 有助于避免(强制)转型,使得编译器能够在编译时发现转型错误而不用等到运行时


     
  • 可以实现通用算法


     

2、泛型类

泛型类的定义和声明:

类名之后通过<>指定一个或者多个类型参数的名字,同时还可以对类型参数的取值范围进行限定,多个类型参数之间使用逗号分隔。

public class Matrix<T>{

    ….

}

泛型的使用:

定义完类型参数后,可以在该类几乎任意地方(静态块、静态属性、静态方法除外)使用类型参数。注意,父类定义的类型参数不能被子类继承。

/*实例化泛型类*/

Matrix<Float> ft=new Matrix<Float>();

3、泛型方法

方法也可以泛型化,不管定义他们的类是不是泛型化。

为什么要使用泛型方法而不是将类型T添加到类定义中呢?




  •  
  • 当泛型方法是静态时,不能使用类的类型参数。


     
  • 当T上的类型约束对于方法是局部时,这意味着没有在类的另一个方法签名中使用相同类型的T的约束。泛型方法的类型参数是局部的,可以简化封闭类型的签名。


     

声明泛型方法:

public <T> T ifThenElse(boolean b, T first, T second) {

    return b? first : second;

}

泛型类是在实例化类时指明泛型的具体类型,泛型方法是在调用方法时指明泛型的具体类型。

编译器会允许调用下面的代码时使用类型推理来推断出T的类型,并用实际参数替代T:

String s=ifThenElse(b, ”a”, ”b”);

Integer i=ifThenElse(b, new Integer(1), new Integer(2));

4、类型限制

有时我们需要限制类型参数的范围。

类型通配符(?),Matrix<?>表示任意的泛型类型。

/*表示add()可以接受任意泛型类型的参数。*/

 public void add(Matrix<?> m);

这种情况下,add()可以接受的参数类型太宽泛了。开发人员可能希望限制参数的具体类型,例如只希望接受Number及其子类的类型的变量,而不接受Random、Locale等类型的变量。这样就要对通配符有所限制。

如Matrix类,使用了类型参数T,我们让Number类作为类型上界来限制这个类型参数:

/*表示Matrix中包含的参数类型是Number及其子类*/

public class Matrix<T extends Numbers>{…}

当引入了类型上界后,在使用类型时就可以使用类型上界类(Number)中定义的方法。

同理我们可以使用Number类作为类型下界:

/*表示Matrix中包含的参数类型是Number及其父类*/

public class Matrix<? super Number>{…}

5、类型擦除(Type Erasure)

泛型是在编译器这个层次实现的,在生成的字节代码中是不包含泛型的类型信息的。

使用泛型时加上的类型参数,会被编译器在编译时去掉,这个过程称为类型擦除。也就是说,由泛型附加的类型信息对JVM来说都是不可见的。

编译器在编译时尽可能地发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。

类型擦除的过程:

首先,找到用来替换类型参数的具体类。如果指定了类型参数的上界的话,则使用上界。

然后,把代码中的类型参数都替换成具体类型,同时去掉出现的类型声明,即<>的内容;

理解了类型擦除,就会明白编译器承担了全部的类型检查工作。编译器禁止某些泛型的使用方式,是为了确保类型的安全性。

很多泛型的特性都与类型擦除有关,如




  •  
  • 静态变量是被泛型类的所有实例共享的,即泛型不能用于静态变量


     
  • 泛型的类型参数不能用在异常处理的catch语句中,因为异常处理是由JVM在运行时刻进行的。由于类型擦除,JVM已经无法区分源于同一泛型类型的两个不同类型的异常。


     

6、开发泛型类

因为类型擦除机制,类型参数并不能用来(在类中)创建对象(比如T t=new T();)或是静态变量的类型。

/*泛型类*/

public class Lhist<V>{}

/*创建泛型类实例*/

Lhist<Integer>li=new Lhist<Integer>(30);

7、泛型的最佳实践

使用泛型常见的实践原则:




  •  
  • 在代码中避免泛型类和原始类型混用,如List<String>和List不应共同使用。


     
  • 使用带通配符(?)的泛型类时,需要明确通配符所代表的一组类型的概念。


     
  • 不能实例化泛型类型变量,然后利用反射的newInstance来创建实例;同样,不能创建一个泛型的数组。


     
  • 尽量不要忽视编译器给出的警告。


     


转载:https://www.cnblogs.com/bigbigbigo/p/8423588.html

推荐内容:
一文助您成为Java.Net双平台高手
【JVM系列】一步步解析java执行内幕
【Java】几道常见的秋招面试题
Java开发岗位面试题归类
在Java的反射中,Class.forName和ClassLoader的区别
京东面试题 Java相关
Java 图形化界面设计(GUI)实战练习(代码)
8/人天,小记一次 JAVA(APP后台) 项目改造 .NET 过程(后台代码已完整开源于 Github)
java中的基本算法
关于Java的Object.clone()方法与对象的深浅拷贝

猜你喜欢

转载自blog.csdn.net/bi_zhiyi/article/details/89667402
今日推荐