首页 > 编程知识 正文

java方法嵌套,java中间容器

时间:2023-05-06 08:55:23 阅读:40670 作者:505

程序=算法的数据结构。 在以前的文章中,我和大家分享了Java面向对象编程的基本方法。 我相信大家已经能在Java上实现简单的算法了。 数据结构是什么呢? 学习计算机基础课程的学生可能知道数据结构是计算机存储和组织数据的方法。 很多理工科学生在本科阶段也学习这个数据结构课程。

事实上,所有数据结构都完全可以通过Java实现。 但是,在工程设计中,每次需要使用一个数据结构时,都不能自己一次完成。 这不仅不经济,而且在后续的维护方面也存在很多问题。 为了解决这个问题,Java提供了一个用于存储对象的容器框架。 在这篇文章中,我将与大家分享有关容器的知识。 希望你喜欢。

Java容器

在Java中,可以使用各种手段来保存对象。 我们知道的排列是其中之一。 但是,数组是固定大小的,程序通常在运行时根据条件创建对象。 由于无法预测要创建的对象的数量和类型,Java推出了容器类来解决此问题。

Java的容器类分为List、Set、Queue和Map。 我们也将它们称为集合类(Collection )。

Java使用泛型实现容器类。 例如,使用名为顺序表的数据结构。 Java有两种实现类: ArrayList和LinkedList,ArrayList的实现基于数组。 例如,如果要保存Java8之前版本的用户组,请使用List users=new ArrayList (; 然后用add方法添加变量。

Java7和Java8容器

喜欢新事物的人,可以尝试一下能够推测通用目标类型的Java7。 此对象List users=new ArrayList ();

在Java7中,编译器根据变量声明时的泛型类型自动估计用于实例化的泛型类型。 但是,创建通用实例时的类型估计是有限的。 只有在上下文中显式声明构造函数的参数化类型时,类型估计才可用。 否则不能使用。 例如:

列表列表=new ArrayList (;

list.add(a ); 以下语句无法通过,因为addAll需要Collection extends String类型的参数

list.addall (新阵列) );

Java8支持两种通用目标类型的估计。

1 .支持方法上下文估计通用目标类型

2 .在方法调用链路中,支持泛型类型估计传递到最后一个方法

上述步骤可以修改为:

//方法根据赋值的目标参数自动估计泛型类型

List list=List.nil (;

//根据前一种方法的参数类型估计通用类型

list.cons(42,List.nil ) );

Java容器的基本概念

Java容器类库用于存储对象,有两个不同的概念: Collection。 独立元素的数组。 所有这些元素都遵循一个或多个规则。 List、Set和Queue都是Collection的一种,List必须按顺序保存元素,但Set不能有重复元素。 Queue需要根据队列规则确定对象的顺序。

地图。 Map是键-值对类型,用户可以使用键搜索对象。 ArrayList允许您使用数字搜索值,而混列表允许您使用其他对象搜索对象。

尽管有这两个概念,但在工程设计中,大多数代码都与接口进行交互。 Collection界面总结了序列的概念,序列是存储一系列对象的方法。 具体类(如ArrayList和HashSet )实现了Collection接口或Collection接口的子接口(如列表接口和Set接口)。

Collection接口的定义如下:

publicinterfacecollectionextendsiterable {

int size (;

布尔isempty (;

布尔内容(对象);

迭代器迭代器(;

对象[ ] to array (;

t [ ]到阵列(t [ ] a );

布尔添加(e );

布尔移除(对象);

布尔连续性(collection c;

布尔Addall (collectionextendsec;

布尔移动全部(collection c;

布尔延迟(collection c;

语音清除(;

布尔表达式(对象);

int hashCode (;

}

我知道Collection

接口实际上继承了Iterable接口,实现这个接口的类可以使用迭代器以及foreach语法进行遍历。

size, isEmpty, contains, iterator, toArray, add, remove, containAll, addAll, removeAll, clear方法分别表示获取这个Collection类型的对象的元素个数,是否为空,是否包含某个元素,获取迭代器,转换为数组,增加元素,删除元素,某个Collection对象是否为它的子集以及进行取差集和清空操作。

除了上述成员方法,java.utils包中的Arrays和Collections类中还提供了很多实用的方法,如:Arrays.asList()方法可以接受数组或逗号分隔的元素列表,并将其转化为一个List对象。

Collections.addAll()方法接受一个Collection对象和一个数组或以逗号分隔的列表将其加入到集合当中。

等等

我们可以这样使用:

//使用asList方法生成list

List keywords = Arrays.asList("hello", "thank", "you");

//我们要将其他元素加入到keywords容器中

Collections.addAll(keywords, "very", "much");

使用asList()方法输出产生的对象需要注意一些问题,因为在这种情况下,它的底层表示仍然是数组,因此我们是不能够该表它的尺寸的。这时使用add和delete方法可能会引发改变数组尺寸的尝试,会在运行时得到Unsupported Operation错误。

如果要使用可以改变尺寸的List,我推荐大家在获取到asList()方法的输出后,再构造一个ArrayList。

迭代器

从之前的Collection接口中可以看出,任何容器类,都可以以某种方式插入、获取和删除元素。add()作为最基本的插入元素方法而get()则是基本取元素的方法。

但是如果我们仅仅使用get和add方法来进行元素操作,如果将一个类的方法实现了,如果想要将相同的代码用在其他容器类中就会遇到问题,那么我们如何解决这一问题呢?

在这里我们就引入了面向对象的设计模式迭代器模式。迭代器是一个对象,它的工作是遍历并选择序列中的对象。客户端不需要知道序列的底层架构。

Java的Iterator的定义如下:

public interface Iterator {

boolean hasNext();

E next();

void remove();

}

我们可以使用:next()方法来获取序列的下一个元素。

hasNext()检查序列中是否还有元素。

使用remove()将迭代器新近返回的元素删除。比如我们要遍历一个容器:

List keywords = new ArrayList<>();

keywords.add("hello");

keywords.add(0, "thank");

Iterator iterator = keywords.iterator();

while (iterator.hasNext()) {

System.out.println(iterator.next());

}

当然也可以使用foreach语法进行遍历:

List keywords = new ArrayList<>();

keywords.add("hello");

keywords.add(0, "thank");

for (String keyword : keywords) {

System.out.println(iterator.next());

}

Iterator还有一些功能更为强大的子类型,我会在下文予以介绍。在接下来的几节我会依次和大家介绍Java容器类中的几种接口。

List

List可以将元素维护在特定的序列中。List接口继承于Collection接口,并在此基础上添加了大量的方法,使得我们可以在List中间进行元素的插入和移动。

List有两种类型分别为:ArrayList,擅长随机访问元素,但是插入、删除元素较慢

LinkedList,擅长插入、删除和移动元素,但是随机访问元素性能较低。

提示

学过数据结构的朋友们应该都知道,ArrayList是我们平时所使用的数组,而LinkedList就是链表。

数组的存储在内存空间中是连续的。所以在底层,我们可以通过每个元素所占的内存大小以及偏移量计算出每个元素所在的起始地址。但是在删除、插入元素时,由于需要保证数据存储位置的连续性,我们需要对它周围的元素进行搬移,而周围元素的搬移又会引起后续其他元素的搬移需求,所以最终所导致的移动操作很多。

而链表在内存中并不是连续存储的。它是一种逻辑顺序结构,每个链表存储的对象,都会存储下一个元素以及上一个元素的引用,通过引用来进行迭代。在删除、移动和插入时,我们不需要对元素的实际位置进行搬移,仅仅需要改变引用就可以了。但是由于它是逻辑上的顺序表,我们不能够静态的计算它的位置,只能一个一个的寻找,所以它的随机存取性能较低。

List接口的实例化对象可以使用Collection的所有方法:

List keywords = new ArrayList<>();

List oldKeywords = new LinkedList<>();

keywords.add("hello");

keywords.add(0, "thank");

oldKeywords.add("you");

oldKeywords.add(0, "very");

keywords.addAll(oldKeywords);

keywords.addAll(2, oldKeywords);

keywords.remove(3);

keywords.removeAll(oldKeywords);

List subKeywords = keywords.subList(0, 1);

keywords.clear();

在使用时,我们会发现ArrayList类型的对象和LinkedList类型对象性能的不同。其中需要注意的是倒数第二行我们使用的subList函数是List接口独有的,它可以获取顺序表的一部分生成一个新的List。

ListIterator

ListIterator是更为强大的Iterator的子类型,但是它仅仅针对List的类进行访问。ListIterator可以进行双向移动、获取迭代器所处元素的前后元素的索引,还可以使用set()方法替换它访问过的最后一个元素。如:

List keywords = new ArrayList<>();

keywords.add("hello");

keywords.add(0, "thank");

ListIterator iterator = keywords.listIterator();

while (iterator.hasPrevious()) {

System.out.println(iterator.previous());

}

while (iterator.hasNext()) {

iterator.next();

iterator.set("you");

}

Stack

Stack实现了栈数据结构,它是一种LIFO(后进先出)的容器。也就是我们先放进栈的元素,在使用时会先获取到最后放入的元素。

Stack stack = new Stack<>();

stack.push("hello");

stack.push("thank");

while (!stack.empty()) {

System.out.println(stack.pop());

}

在运行上述程序时,我们会发现最后的输出是thank, hello。这就体现了栈的LIFO特性。

我们可以使用栈这种数据结构做许多事情,如函数递归调用的现场维护就是使用栈来实现的。

Set

Set是一种不保存重复元素的数据结构。如果我们将多个相同元素放入Set中,它仅仅会保存一个。使用Set很适合进行查找操作,Java中提供了一个HashSet类,它的查找速度很快,适合用作快速查找。

在使用时与其他Collection的使用类似:

Set keywords = new HashSet<>();

keywords.add("hello");

keywords.add("thank");

keywords.add("u");

keywords.add("thank");

keywords.add("u");

keywords.add("very");

keywords.add("much");

System.out.println(keywords);

我们在set中加入了一系列的词汇,其中有一些重复词汇,但是在实际输出时我们会发现,并不存在那么多的元素,而仅仅打印不重复元素。

Set有多种实现:HashSet,使用了散列方式进行存储。

TreeSet,将元素存储在红黑数当中。它会对集合元素进行排序。

LinkedHashSet,使用链表和哈希表来实现Set。

提示

具体的实现我们可以在数据结构的教程中深入了解,在这里我只与大家分享该如何在工程中选取数据结构。比如我们需要获取一个排好序的数列集合。我们就可以使用TreeSet,插入元素后,元素就会按照顺序存储。我们可以很方便的插入或删除元素同时保证排序质量。如果我们不需要排序,只需要保证插入和查找效率,那我们就可以仅仅使用HashSet来进行工作,我们可以很方便的通过它来测试元素的归属性,以及进行一系列的集合操作。

Map

Map可以将一个对象映射到另一个对象。在工程上,它是十分重要的数据结构。比如我们有一系列用户分组对象它保存了用户分组的信息,我们经常需要通过用户分组对象获取这个分组的所有用户。如果我们仅仅通过List进行存储,在查找时的工作量是很大的。因为我们需要从头开始遍历List,判断每个元素是否属于这一分组,但是引入Map后就简单许多了,我们可以将一个对象映射到另一个对象上,所以可以这样实现:

Map> departmentUsersMap = new HashMap<>();

departmentUsersMap.put(department1, users1);

departmentUsersMap.put(department2, users2);

//在获取时

List departmentUser = departmentUsersMap.get(department);

提示

这次我们第一次用到了英勇的哑铃的实现,Map中嵌套List,事实上容器的嵌套层次是可以很深的。我们甚至将在Map中的List再嵌套一个Set。但是我们使用何种数据结构,要取决于我们程序的需求,我们数据结构的组合选择需要最大程度的满足我们的需求并尽可能地提高程序的效率。

Map数据结构除了上述映射获取功能以外,还可以获取键、值或键值对的集合,分别使用keySet, value以及entrySet。比如我们要遍历map:

Map> departmentUsersMap = new HashMap<>();

departmentUsersMap.put(department1, users1);

departmentUsersMap.put(department2, users2);

for (Map.Entry departmentEntry : departmentUsersMap.entrySet()) {

System.out.println(String.format("key:%s value:%s", departmentEntry.getKey().toString(), departmentEntry.getValue()

.toString()));

}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。