201971010131-张兴盼《面向对象程序设计(java)》第十二周学习总结
阅读原文时间:2023年09月26日阅读:1

 

内容

这个作业属于哪个课程

https://www.cnblogs.com/nwnu-daizh/

这个作业的要求在哪里

https://www.cnblogs.com/nwnu-daizh/p/11867214.html

作业学习目标

(1) 掌握Vetor、Stack、Hashtable三个类的用途及常用API;

(2)  掌握ArrayList、LinkList两个类的用途及常用API;

(3) 了解java集合框架体系组成;

(4) 掌握Java GUI中框架创建及属性设置中常用类的API;

(5) 了解Java GUI中2D图形绘制常用类的API;

第一部分:总结第九章、第十章理论知识

第九章 集合

9.1 Java集合框架

一、集合框架图

简化图:

说明:对于以上的框架图有如下几点说明

1.所有集合类都位于java.util包下。Java的集合类主要由两个接口派生而出:CollectionMap,Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。
2. 集合接口:6个接口(短虚线表示),表示不同集合类型,是集合框架的基础。
3. 抽象类:5个抽象类(长虚线表示),对集合接口的部分实现。可扩展为自定义集合类。
4. 实现类:8个实现类(实线表示),对接口的具体实现。
5. Collection 接口是一组允许重复的对象。
6. Set 接口继承 Collection,集合元素不重复。
7. List 接口继承 Collection,允许重复,维护元素插入顺序。
8. Map接口是键-值对象,与Collection接口没有什么关系。
9.Set、List和Map可以看做集合的三大类:
List集合是有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问。
Set集合是无序集合,集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问(也是集合里元素不允许重复的原因)。
Map集合中保存Key-value对形式的元素,访问时只能根据每项元素的key来访问其value。

二、Collection接口

Collection接口是处理对象集合的根接口,其中定义了很多对元素进行操作的方法。Collection接口有两个主要的子接口ListSet,注意Map不是Collection的子接口,这个要牢记
Collection接口中的方法如下:

其中,有几个比较常用的方法,比如方法add()添加一个元素到集合中,addAll()将指定集合中的所有元素添加到集合中,contains()方法检测集合中是否包含指定的元素,toArray()方法返回一个表示集合的数组。

另外,Collection中有一个iterator()函数,它的作用是返回一个Iterator接口。通常,我们通过Iterator迭代器来遍历集合。ListIterator是List接口所特有的,在List接口中,通过ListIterator()返回一个ListIterator对象。

Collection接口有两个常用的子接口,下面详细介绍。

1.List接口

List集合代表一个有序集合,集合中每个元素都有其对应的顺序索引。List集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。

List接口继承于Collection接口,它可以定义一个允许重复有序集合。因为List中的元素是有序的,所以我们可以通过使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。

List接口为Collection直接接口。List所代表的是有序的Collection,即它用某种特定的插入顺序来维护元素顺序。用户可以对列表中每个元素的插入位置进行精确地控制,同时可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。

(1)ArrayList

ArrayList是一个动态数组,也是我们最常用的集合。它允许任何符合规则的元素插入甚至包括null。每一个ArrayList都有一个初始容量(10),该容量代表了数组的大小。随着容器中的元素不断增加,容器的大小也会随着增加。在每次向容器中增加元素的同时都会进行容量检查,当快溢出时,就会进行扩容操作。所以如果我们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容操作而浪费时间、效率。

size、isEmpty、get、set、iterator 和 listIterator 操作都以固定时间运行。add 操作以分摊的固定时间运行,也就是说,添加 n 个元素需要 O(n) 时间(由于要考虑到扩容,所以这不只是添加元素会带来分摊固定时间开销那样简单)。

ArrayList擅长于随机访问。同时ArrayList是非同步的。

(2)LinkedList

同样实现List接口的LinkedList与ArrayList不同,ArrayList是一个动态数组,而LinkedList是一个双向链表。所以它除了有ArrayList的基本操作方法外还额外提供了get,remove,insert方法在LinkedList的首部或尾部。

由于实现的方式不同,LinkedList不能随机访问,它所有的操作都是要按照双重链表的需要执行。在列表中索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。这样做的好处就是可以通过较低的代价在List中进行插入和删除操作。

与ArrayList一样,LinkedList也是非同步的。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List: 
List list = Collections.synchronizedList(new LinkedList(…));

(3)Vector

与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。它的操作与ArrayList几乎一样。

(4)Stack

Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop 方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

2.Set接口

Set是一种不包括重复元素的Collection。它维持它自己的内部排序,所以随机访问没有任何意义。与List一样,它同样允许null的存在但是仅有一个。由于Set接口的特殊性,所有传入Set集合中的元素都必须不同,同时要注意任何可变对象,如果在对集合中元素进行操作时,导致e1.equals(e2)==true,则必定会产生某些问题。Set接口有三个具体实现类,分别是散列集HashSet、链式散列集LinkedHashSet和树形集TreeSet。

Set是一种不包含重复的元素的Collection,无序,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。需要注意的是:虽然Set中元素没有顺序,但是元素在set中的位置是由该元素的HashCode决定的,其具体位置其实是固定的。

(1)HashSet

HashSet 是一个没有重复元素的集合。它是由HashMap实现的不保证元素的顺序(这里所说的没有顺序是指:元素插入的顺序与输出的顺序不一致),而且HashSet允许使用null 元素。HashSet是非同步的,如果多个线程同时访问一个哈希set,而其中至少一个线程修改了该set,那么它必须保持外部同步。 HashSet按Hash算法来存储集合的元素,因此具有很好的存取和查找性能。

HashSet的实现方式大致如下,通过一个HashMap存储元素,元素是存放在HashMap的Key中,而Value统一使用一个Object对象。

HashSet使用和理解中容易出现的误区:

a.HashSet中存放null值
  HashSet中是允许存入null值的,但是在HashSet中仅仅能够存入一个null值。

b.HashSet中存储元素的位置是固定的
  HashSet中存储的元素的是无序的,这个没什么好说的,但是由于HashSet底层是基于Hash算法实现的,使用了hashcode,所以HashSet中相应的元素的位置是固定的。
  
c.必须小心操作可变对象(Mutable Object)。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。

(2)LinkedHashSet

LinkedHashSet继承自HashSet,其底层是基于LinkedHashMap来实现的,有序,非同步。LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。

(3)TreeSet

TreeSet是一个有序集合,其底层是基于TreeMap实现的,非线程安全。TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。当我们构造TreeSet时,若使用不带参数的构造函数,则TreeSet的使用自然比较器;若用户需要使用自定义的比较器,则需要使用带比较器的参数。

注意:TreeSet集合不是通过hashcode和equals函数来比较元素的.它是通过compare或者comparaeTo函数来判断元素是否相等.compare函数通过判断两个对象的id,相同的id判断为重复元素,不会被加入到集合中。

9.2 具体的集合

9.2.1 链表

链表是一种数据结构,和数组同级。比如,Java中我们使用的ArrayList,其实现原理是数组。而LinkedList的实现原理就是链表了。链表在进行循环遍历时效率不高,但是插入和删除时优势明显。下面对单向链表做一个介绍。

单向链表是一种线性表,实际上是由节点(Node)组成的,一个链表拥有不定数量的节点。其数据在内存中存储是不连续的,它存储的数据分散在内存中,每个结点只能也只有它能知道下一个结点的存储位置。由N各节点(Node)组成单向链表,每一个Node记录本Node的数据及下一个Node。向外暴露的只有一个头节点(Head),我们对链表的所有操作,都是直接或者间接地通过其头节点来进行的。 
最左边的节点即为头结点(Head),但是添加节点的顺序是从右向左的,添加的新节点会被作为新节点。最先添加的节点对下一节点的引用可以为空。引用是引用下一个节点而非下一个节点的对象。因为有着不断的引用,所以头节点就可以操作所有节点了。 
       单向链表存储情况。存储是分散的,每一个节点只要记录下一节点,就把所有数据串了起来,形成了一个单向链表。 
节点(Node)是由一个需要储存的对象及对下一个节点的引用组成的。也就是说,节点拥有两个成员:储存的对象、对下一个节点的引用。

9.2.2 数组列表

List接口用于描述有序集合,且有两种中访问元素的协议,(a)用迭代器(b)用get和set方法随机地访问每个元素。第二章方法不适用于链表却适用于数组,集合类提供了熟悉的ArrayList类,这个类也实现了List接口。

ArrayList封装了一个每个列表称为桶动态再分配的对象数组。

9.2.3 散列集

散列表由米娜子就可看出时没有确定位置的。但是散列表会为每一个元素对象计算一个整数,称为散列码。散列码是由对象的实例域产生的一个整数。或者说,具有不同数据域的对象产生不同的散列码。

在java中,散列表用数组列表实现。在散列表中由有:    HashSet()//用来构造新散列表……..

9.2.4 树集

树集是一个有序集合。可以以任意顺序将元素插入到集合中。自对集合进行遍历时,每个值将自动地按排序后的顺序呈现。创建一个树集的方法为:TreeSet()

9.2.5 队列与双端队列

有两个端头的队列称为双端队列。可在头部和尾部同时添加或者删除元素。不支持在队列中间插入。

9.2.6 优先级队列

可按任意顺序插入的元素,但按照排序的顺序进行检索。优先级队列用了堆(可以自我调整的二叉树)。一个优先级对象可以保存实现了Comparable接口的类对象,也可以保存在构造器中提供的Comparator对象。

9.3 映射

映射是一种特殊的对应关系。

映射就是把两个对象对应起来。

对应的对象叫做象,被对应的对象叫做原象。

Java中有非常好的例子。实现了Map接口的HashMap和TreeMap。前面已经提到过Map类是实现键值对的双向链表,这里就是完成了key和value的映射,当然key要是唯一的才可以。

9.4 试图与包装袋

Arrays.asList方法:在Arrays类中有一个静态方法--asList方法,这个方法作用是:将普通的Java数组包装成一个List集合。

Collections.nCopies方法:与Arrays.asList方法类似的另一个方法那就是在Collection中的nCopies方法。

不可修改的视图:

Collections还有几个方法,用于产生集合的不可修改视图。这些视图对现有的集合增加了一个运行时的检查。如果发现对集合进行修改的话(这里不仅仅是改变数组的大小,并且包括set之类的方法),就会抛出一个异常,同时这个集合将保持未修改的状态。
       可以使用如下8种方法来获得不可修改的视图:

  1. Collections.unmodifiableCollection
  2. Collections.unmodifiableList
  3. Collections.unmodifiableSet
  3. Collections.unmodifiableSortedSet
  5. Collections.unmodifiableNavigableSet
  6. Collections.unmodifiableMap
  7. Collections.unmodifiableSortedMap
  8. Collections.unmodifiableNavigableMap

9.5 算法

一、排序与混排:

如今排序算法已经成为大多数编程语言标准库中的一个组成部分

1.1java.util.Collections 1.2:

    static void sort(List elements)

    使用稳定的排序算法,对列表中的元素进行排序。这个算法的时间复杂度是O(n logn),其中n为列表长度

    static void shuffle(List elements)

    static void shuffle(List elements , Random r)

    随机地打乱表中的元素。这个算法的时间复杂度是O(n a(n)),n是列表的长度,a(n)是访问元素的平均时间

1.2java.util.List 1.2:

    default void sort(Comparator comparator) 8

    使用给定比较器对列表排序

1.3java.util.Comparator 1.2:

    static > Comparator reverseOrder() 8

    生成一个比较器,将逆置Comparable接口提供的顺序

    default Comparator reversed() 8

    生成一个比较器,将逆置这个比较器提供的顺序

2.二分查找:

只有采用随机访问,二分查找才有意义

2.1java.util.Collections 1.2:

    static > int binarySearch(List elements , T key)

    static int binarySearch(List elements , T key , Comparator c)

    从有序列表中搜索一个键,如果元素拓展了AbstractSequentialList类,则采用线性查找,否则将采用二分查找。

    这个方法的时间复杂度为O(a(n) log n),n为列表的长度,a(n)是访问一个元素的平均时间。

    这个方法将返回这个键在列表中的索引,如果在列表中不存在这个键将返回负值i。

    这种情况下,应该将这个键插入到列表索引-i-1的位置上,以保持列表的有序性。

3.简单算法:

3.1java.util.Collections 1.2:

    static > T min(Collection elements)

    static > T max(Collection elements)

    static min(Collection elements , Comparator c)

    static max(Collection elements , Comparator c)

    返回集合中最小的或最大的元素(为清楚起见,参数的边界被简化了)

    static void copy(List to , List from)

    将原列表中的所有元素复制到目标列表的相应位置上。目标列表的长度至少与原列表一样

    static void fill(List l , T value)

    将列表中的所有位置设置为相同值

    static boolean addAll(Collection c , T… values) 5.0

    将所有的值添加到集合中,如果集合改变了则返回true

    static boolean replaceAll(List l , T oldValue , T newValue) 1.4

    用newValue取代所有值为oldValue的元素

    static int indexOfSubList(List l , List s) 1.4

    static int lastIndexOfSubList(List l , List s) 1.4

    返回l中第一个或者最后一个等于s子列表的索引。如果l中不存在等于s的子列表,则返回-1.

    static void swaq(List l, int i, int j) 1.4

    交换给定偏移量的两个元素

    static void reverse(List l)

    逆置列表中元素的顺序

    static void rotate(List l, int d) 1.4

    旋转列表中的元素,将索引i的条目移动到位置(i+d)%l.size()

    static int frequency(Collection c1 , Collection c2) 5.0

    返回c中与对象o相同的元素个数

    boolean disjoint(Collection c1 , Collection c2) 5.0

    如果两个集合没有共同元素,则返回true

3.2java.util.Collection 1.2:

    default boolean removeIf(Predicate filter) 8

    删除所有匹配的元素

3.3java.util.List 1.2

   default void replaceAll(UnaryOperator op) 8

   对这个列表的所有元素应用这个操作

4.批处理:

很多操作会“成批”复制或者删除元素,例如removeAll(…)等等,其实最好是对视图进行操作,这样既能够很好的完成任务,也能够界定范围。

5.集合与数组的转换:

如果需要把一个数组转换为集合,ArrayList.asList包装器可以达到这个目的

String[] values = …;

HashSet staff = new HashSet<>(ArrayList.asList(values));

从集合得到数组会更加困难一些。当然,可以使用toArray方法:

Object[] values = staff.toArray();

不过,这样的结果是一个Object数组还不能够强制转换,所以稍微改变String[] values = staff.toArray(new String[0]);   

9.6 遗留的集合

1.Hashtable类:

Hashtable类与HashMap类的作用一样,实际上,它们拥有相同的接口。Hashtable的方法是同步的。如果需要并发访问,则需要使用ConcurrentHashMap

2.枚举:

遗留集合使用Enumeration接口对元素进行遍历

2.1    java.util.Enumeration 1.0:

    boolean hasMoreElements()

    如果还有更多的元素可以查看,则返回true

    E nextElement()

    返回被检测的下一个元素。如果hasMoreElements()返回false,则不要调用这个方法

2.2   java.util.Hashtable 1.0:

    Enumeration keys()

    返回一个遍历散列表中键的枚举对象

    Enumeration elements()

    返回一个遍历散列表中元素的枚举对象

2.3   java.util.Vector 1.0:

    Enumeration elements()

    返回遍历向量中元素的枚举对象

3.属性映射:

属性映射是一个类型非常特殊的映射结构:键与值都是字符串,表可以保存到一个文件中,也可以从文件中加载,使用一个默认的辅助表。

实现属性映射的Java平台类称为Properties,通常用于程序的配置选项

3.1java.util.Properties 1.0:

    Properties()

    创建一个空的属性映射

    Properties(Properties defaults)

    创建一个带有默认值的空的属性映射

    String getProperty(String key)

    获得属性的对应关系;返回与键对应的字符串。如果映射不存在,返回默认表中与这个键对应的字符串

    String getProperty(String key,String defaultValue)

    获得在键没有找到时具有的默认值属性;它将返回与键对应的字符串,如果在映射中不存在,就返回默认的字符串

    void load(InputStream in)

    从InputStream加载属性映射

    void store(OutputStream out,String commentString)

    把属性映射存储到OutputStream

4.栈:

从1.0版本开始,就已经包含了Stack类,其中含有push方法和pop方法,但是,Stack类拓展为Vector类,就理论角度看,Vector类并不令人满意,它可以让栈使用不属于栈操作的insert和remove方法

4.1java.util.Stack 1.0:

    E push(E item)

    将item压入栈并返回item

    E pop()

    弹出并返回栈顶的item。如果栈为空,请不要使用

    E peek()

    返回栈顶元素,但是不弹出。如果栈为空,请不要使用

5.位集:

Java平台的BitSet类用于存放一个位序列(称为位向量或位数组更为合适),如果需要高效的存储位序列(例如,标志)就可以使用位集。由于位集将位包装在字节里,所以,效率极高。

5.1  java.util.BitSet 1.0:

    BitSet(int initialCapacity)

    创建一个位集

    int length()

    返回位集的“逻辑长度”,即1加上位集的最高设置位的索引

    boolean get(int bit)

    获得一个位

    void set(int bit)

    设置一个位

    void clear(int bit)

    清楚一个位

    void and(BitSet set)

    这个位集与另一个位集进行逻辑AND

    void or(BitSet set)

    这个位集与另一个位集进行逻辑OR

    void xor(BitSet set)

    这个位集与另一个位集进行逻辑XOR

    void andNot(BitSet set)

    清除这个位集中对应另一个位集中设置的所有位

第十章 图形程序设计

10.1 Swing概述

Swing新一代的图形界面工具。使用 Swing 来开发图形界面比 AWT 更加优秀,因为 Swing 是一种轻量级组件,它采用纯 Java 实现,不再依赖于本地平台的图形界面,所以可以在所有平台上保持相同的运行效果,对跨平台支持比较出色。除此之外,Swing 提供了比 AWT 更多的图形界面组件,因此可以开发出美观的图形界面程序。

10.2 创建框架

(1)创建空框架:

在Java中,常采用框架创建初始界面,即GUI的顶层窗口;

AWT库中有一个基于对等体的Frame类;

该类的Swing版本为JFrame,JFrame是Frame的子类;

(2)框架定位于框架属性:

定位:——常用Component类的setLocation和setBounds方法

常用属性:——Title:框架标题;

    ——IconImage:框架图标;

(3)确定框架大小:

通过调用Toolkit类的方法来得到屏幕尺寸信息;

10.3 在组件中显示信息

10.4 处理2D图形

Graphics类包含绘制直线,矩形或者椭圆的方法。但是绘制图形的能力有限,不能改变线的粗细,不能旋转这些图形 
  Java se 引入了Java 2D库,这个库实现了功能强大的图形操作。 
  要想使用Java 2D库绘制图形,需要获得一个Graphics2D类对象。这个类是Graphics的子类。自从JavaSE 2版本以来,paintComponent方法就会自动的获得一个Graphics2D类对象,我们只需要进行一次类型转换就可以了

public void paintComponent(Graphics g )
 {
  Graphics2D g2=(Graphics2D ) g;
 }

java 2D库采用面向对象的方式将几何图形组织起来,包含直线、矩形椭圆类:

Line2D
  Rectangle2D
  Ellipse2D

Java 2D 支持更加复杂的图形,如圆弧,二次曲线,三次曲线和通用路径。 
  要想绘制图形,首先要创建一个实现了Shape接口的类的对象。然后调用Graphics2D类中的draw方法。

10.6 使用颜色

Graphics 2D类的setPaint方法(Graphics  类为setColor方法)用来设置颜色;

1、Color类中定义的13种标准颜色:

BLACK、BLUE、CYAN   DARK_GRAY  GRAY   GREEN   LIGHT_GRAY   MAGENTA    ORANGE    PINK   RED   WHITE   YELLOW

2、复合色:

通过指定红绿蓝三色比例,用color类对象来复合成一种新的颜色;

Color的构造器:

Color(int   redness , int  greenness,  int  blueness)

3、图形颜色常用的API:

——void   Color(int  r,   int  g, int  b)

——void  setColor(color  c)

——void  getColor();

——void   setPaint(Paint  p);

——void  fill(Shape  s);

——void  setBackground(Color   c)

——void   setForeground(Color  c)

10.7 文本使用特殊字体

1、AWT的五种逻辑字体名:

SanaSerif      Serif     Monospaced    Dialog    Dialoginput。这些逻辑字体在不同语言和操作系统上映射为不同的物理字体;

2、字体风格:

Font.PLAIN        Font.BOLD     Font.ITALIC     Font.BOLD+Font.ITALIC

3、设置字体:

10.8 显示图像

可以使用Graphics类的drawImage方法将图像显示出来:

注意:这个调用可能会在图像还没有绘制完毕就返回。

boolean drawImage(Image img, int x, int y, ImageObserver observer);

绘制一幅非比例图像。

boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer);

绘制一幅比例图像。系统按照比例将图像放入给定宽和高的区域。

xy是图像左上角的坐标,observer是绘制进程中以通告为目的的对象(可能为null) v。

第二部分:实验部分

1、实验目的与要求

(1) 掌握Vetor、Stack、Hashtable三个类的用途及常用API;

(2) 掌握ArrayList、LinkList两个类的用途及常用API。

(3) 掌握Java GUI中框架创建及属性设置中常用类的API;

(4) 应用结对编程(Pair programming),体验程序开发中的两人合作。

2、实验内容和步骤

实验1 导入第9章示例程序,测试程序并进行代码注释。

测试程序1:

l 使用JDK命令运行编辑、运行以下三个示例程序,结合运行结果理解程序;

l 掌握Vetor、Stack、Hashtable三个类的用途及常用API。

示例一程序代码如下:

package chart10;
//示例程序1

import java.util.Vector; //矢量类包
class Cat {
private int catNumber; //Cat类的整型私有变量catNumber
Cat(int i) { //Cat构造器
catNumber = i;
}
void print() { //print方法定义
System.out.println("Cat #" + catNumber);
}
}
public class Cats{
public static void main(String[] args){
Vector cats= new Vector(); //创建一个Vector类对象cats
for(int i=0; i<7; i++) //for循环通过Vector类对象cats来调用addElement()方法
cats.addElement(new Cat(i));
for(int i=0; i类对象cats来调用elementAt()方法以及Cat类的print()方法
}
}

运行结果如下:

示例二程序代码如下:

package Stacks;

//示例程序2
import java.util.*;
public class Stacks //堆栈类
{
static String[] months={"金","银","铜","铁"}; //定义一个字符类数组months[],其中元素为金、银、铜、铁
public static void main(String[] args){
Stack stk = new Stack (); //创建一个Stack类对象stk
for(int i=0; i<months.length; i++)
stk.push(months[i]); //通过对象名来调用push()方法
System.out.println(stk);
System.out.println("element 2=" + stk.elementAt(2));
while(!stk.empty()) //当stk不为空时,将通过对象名调用pop()方法
System.out.println(stk.pop());
}
}

运行结果如下:

示例三程序代码如下:

package Counter;

//示例程序3
import java.util.*;
class Counter { //Counter类
int i = 1; //定义一个整型的Counter类变量i
public String toString() { //toString()方法
return Integer.toString(i);
}
}

public class Statistics {
public static void main(String[] args) {
Hashtable ht = new Hashtable(); //创建一个Hashtable类对象ht。Hashtable保存了一批键值对
for (int i = 0; i < 10000; i++) {
Integer r = new Integer((int) (Math.random() * 20));
//创建一个Integer类对象r,调用Math包的random()方法随机生成10000个1-20之间的随机数,强制类型转换为int型
if(ht.containsKey(r)) //如果r的键值不为空
((Counter)ht.get(r)).i++; //将Hashtable类对象ht强制转换为Counter类,调用get()方法然后再让i(r的出现次数)加一
else
ht.put(r, new Counter()); //否则Hashtable类对象ht调用put()方法,再创建一个Counter类对象
}
System.out.println(ht); //将ht输出在控制台上
}
}

运行结果如下:

测试程序2:

l 使用JDK命令编辑运行ArrayListDemo和LinkedListDemo两个程序,结合程序运行结果理解程序;

l 掌握ArrayList、LinkList两个类的用途及常用API。l 在Elipse环境下编辑运行调试教材360页程序9-1,结合程序运行结果理解程序;

ArrayListDemo类程序代码如下:

package ArrayListDemo;
import java.util.*;

public class ArrayListDemo {
public static void main(String[] args) {
ArrayList al = new ArrayList(); //创建一个ArrayList类对象al
// Add lots of elements to the ArrayList…
al.add(new Integer(11)); //通过al调用add()方法添加元素
al.add(new Integer(12));
al.add(new Integer(13));
al.add(new String("hello"));
// First print them out using a for loop.
System.out.println("Retrieving by index:"); //将Retrieving by index:(按索引搜索)输出在控制台上
for (int i = 0; i < al.size(); i++) { //i小于数组类对象al的大小时,输出i的值
System.out.println("Element " + i + " = " + al.get(i));
}
}
}

运行结果如下:

LinkedListDemo 类程序代码如下:

package LinkedListDemo;

import java.util.*;
public class LinkedListDemo {
public static void main(String[] argv) {
LinkedList l = new LinkedList(); //创建一个LinkedList类的对象l
l.add(new Object()); //通过l调用add()方法增加元素
l.add("Hello");
l.add("zhangsan");
ListIterator li = l.listIterator(0); //创建一个ListIterator类的对象li
while (li.hasNext()) //这是java的迭代器的用法。使用hasNext()检查序列中是否还有元素。
System.out.println(li.next()); //使用next()获得序列中的下一个元素。

     if (l.indexOf("Hello") < 0)          //indexOf检测如果不存在就会返回Lookup does not work  
         System.err.println("Lookup does not work");  
     else  
         System.err.println("Lookup works");  
}  

}

运行结果如下:

LinkedListTest类程序代码如下:

package linkedList;

import java.util.*;

/**
* This program demonstrates operations on linked lists.
* @version 1.12 2018-04-10
* @author Cay Horstmann
*/
public class LinkedListTest
{
public static void main(String[] args)
{
LinkedList a = new LinkedList();//创建一个LinkedList类对象
a.add("Amy"); //通过a调用add()方法添加元素
a.add("Carl");
a.add("Erica");

   LinkedList<String> b = new LinkedList<String>();//创建一个LinkedList<String>类对象  
   b.add("Bob");                 //通过b调用add()方法添加元素  
   b.add("Doug");  
   b.add("Frances");  
   b.add("Gloria");

   // merge the words from b into a

   ListIterator<String> aIter = a.listIterator();  //listIterator接口是iterator的子接口  
   Iterator<String> bIter = b.iterator();

   while (bIter.hasNext())                   //如果存在访问的元素,返回ture  
   {  
      if (aIter.hasNext()) aIter.next();    //如果aIter中存在访问的元素使用next()获得序列中的下一个元素。  
      aIter.add(bIter.next());               //添加bIter.next()得到的元素到aIter中  
   }

   System.out.println(a);

   // remove every second word from b

   bIter = b.iterator();  
   while (bIter.hasNext())  
   {  
      bIter.next(); // skip one element  
      if (bIter.hasNext())    //如果bIter中存在访问的元素使用next()获得序列中的下一个元素。  
      {  
         bIter.next(); // skip next element    使用next()获得序列中的下一个元素。  
         bIter.remove(); // remove that element   删除bIter中的元素  
      }  
   }

   System.out.println(b);

   // bulk operation: remove all words in b from a

   a.removeAll(b);       //删除b中所有的来自a的元素

   System.out.println(a);  
}  

}

运行结果如下:

实验2导入第10章示例程序,测试程序并进行代码注释。

测试程序1:

l 运行下列程序,观察程序运行结果

import javax.swing.*;

public class SimpleFrameTest

{

public static void main(String[] args)

{

JFrame  frame = new JFrame();

frame.setBounds(0, 0,300, 200);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setVisible(true);

}

}

l 在elipse IDE中调试运行教材407页程序10-1,结合程序运行结果理解程序;与上面程序对比,思考异同;

l 掌握空框架创建方法;

l 了解主线程与事件分派线程概念;

l 掌握GUI顶层窗口创建技术。

程序代码如下:

package SimpleFrameTest;

import javax.swing.*;
public class SimpleFrameTest
{
public static void main(String[] args)
{
JFrame frame = new JFrame(); //创建一个JFrame类对象frame,
frame.setBounds(0, 0,300, 200); //通过frame来调用setBounds()方法,后面的参数分别是像素最初始位置,以及框架的宽度和长度
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //通过调用setDefaultCloseOperation()方法。可关闭
frame.setVisible(true); //调用setVisible()方法,
}
}

程序运行结果如下:

package sizedFrame;

import java.awt.*;
import javax.swing.*;

/**
* @version 1.35 2018-04-10
* @author Cay Horstmann
*/
public class SizedFrameTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(() -> //lambda表达式
{
SizedFrame frame = new SizedFrame(); //创建一个SizedFrame类对象frame
frame.setTitle("SizedFrame"); //通过frame对象来调用setTitle()方法,来设置标题
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //调用setDefaultCloseOperation()方法来设置取消窗口界面
frame.setVisible(true); //调用setVisible()方法来决定窗口是否可见
});
}
}

class SizedFrame extends JFrame //创建一个类SizedFrame类来继承JFrame类
{
public SizedFrame() //构造器
{
// get screen dimensions

   Toolkit kit = Toolkit.getDefaultToolkit();  //创建一个Toolkit类对象kit,通过类名来调用getDefaultToolkit()方法  
   Dimension screenSize = kit.getScreenSize();   //调用getScreenSize()方法来得到框的大小,返回维度类型  
   int screenHeight = screenSize.height;  
   int screenWidth = screenSize.width;

   // set frame width, height and let platform pick screen location

   setSize(screenWidth / 2, screenHeight / 2);     //设置大小  
   setLocationByPlatform(true);

   // set frame icon

   Image img = new ImageIcon("icon.gif").getImage();    //创建一个Image对象来设置灰度  
   setIconImage(img);  
}  

}

运行结果如下:

测试程序2:

l 在elipse IDE中调试运行教材412页程序10-2,结合运行结果理解程序;

l 掌握确定框架常用属性的设置方法。

程序代码如下;

package simpleFrame;

import java.awt.*;
import javax.swing.*;

/**
* @version 1.34 2018-04-10
* @author Cay Horstmann
*/
public class SimpleFrameTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(() -> //lambda表达式
{
SimpleFrame frame = new SimpleFrame(); //创建一个SimpleFrame类对象
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //调用setDefaultCloseOperation()方法来取消窗口
frame.setVisible(true); //调用setVisible()方法决定窗口是否可见
});
}
}

class SimpleFrame extends JFrame //创建一个SimpleFrame类继承JFrame类
{
private static final int DEFAULT_WIDTH = 300; //定义私有常量DEFAULT_WIDTH和DEFAULT_HEIGHT的值
private static final int DEFAULT_HEIGHT = 200;

public SimpleFrame()    //SimpleFrame构造器  
{  
   setSize(DEFAULT\_WIDTH, DEFAULT\_HEIGHT);     //设置宽度和长度的大小  
}  

}

运行结果如下:

测试程序3:

l 在elipse IDE中调试运行教材418页程序10-3,结合运行结果理解程序;

l 掌握在框架中添加组件;

l 掌握自定义组件的用法。

程序代码如下:

package notHelloWorld;

import javax.swing.*;
import java.awt.*;

/**
* @version 1.34 2018-04-10
* @author Cay Horstmann
*/
public class NotHelloWorld
{
public static void main(String[] args)
{
EventQueue.invokeLater(() -> //lambda表达式
{
NotHelloWorldFrame frame = new NotHelloWorldFrame(); //创建一个NotHelloWorldFrame类对象
frame.setTitle("NotHelloWorld"); //通过frame来调用setTitle()方法,来设置标题
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//调用setDefaultCloseOperation()方法取消窗口
frame.setVisible(true); //调用setVisible()方法设置窗口是否可见
});
}
}

/**
* A frame that contains a message panel.
*/
class NotHelloWorldFrame extends JFrame //创建一个NotHelloWorldFrame类来继承JFrame类
{
public NotHelloWorldFrame() //NotHelloWorldFrame构造器
{
add(new NotHelloWorldComponent()); //add()方法添加窗口
pack();
}
}

/**
* A component that displays a message.
*/
class NotHelloWorldComponent extends JComponent //创建一个NotHelloWorldComponent类继承JComponent类
{
public static final int MESSAGE_X = 75; //私有属性,常量MESSAGE_X以及MESSAGE_Y 的定义
public static final int MESSAGE_Y = 100;

private static final int DEFAULT\_WIDTH = 300;  //私有属性,常量DEFAULT\_WIDTH以及DEFAULT\_HEIGHT 的定义  
private static final int DEFAULT\_HEIGHT = 200;

public void paintComponent(Graphics g)    //paintComponent()方法定义来实现绘图  
{  
   g.drawString("Not a Hello, World program", MESSAGE\_X, MESSAGE\_Y);  
}

public Dimension getPreferredSize()     //getPreferredSize()得到维度  
{  
   return new Dimension(DEFAULT\_WIDTH, DEFAULT\_HEIGHT);  
}  

}

运行结果如下:

第三部分 实验总结

这个星期我们学习了有关java集合框架和图形程序设计两章的知识。在第九章中我们结合前面学过的接口以及泛型接口的知识,又学习了一些具体的集合,比如链表、树集、队列等知识我们在数据结构中其实已经进行了比较深入的学习,在java中再次学习的时候就觉得相对比较容易理解了。这个星期我们也首次在java中学习到算法的知识,我觉得算法对我来说很难,但我会努力去学习。第十章图形程序设计的知识老师在理论课上介绍的比较少,主要需要我们自己在课后学习。课后我也系统翻看了一遍课本知识,对我而言第十章的知识更容易理解。