201871010121-王方-《面向对象程序设计(java)》第十二周学习总结
项目 |
内容 |
这个作业属于哪个课程 |
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;
|
第一部分 基础知识总结
一、Java集合框架
Java提供的一组类:Vector、Stack、Hashtable、BitsSet与Enumeration接口。其中Enumeration接口提供了一种用于访问任意容器中各个元素的抽象机制。
1.将集合的接口与实现分离
(a)队列接口指出可以在队列尾部添加元素,在队列的头部添加元素,并且可以查找队列中元素的个数。有“先进先出”的规则。
队列接口的简单形式,例如:
public interface Queue<E>//a simplified form of the interface in the standard library
{
void add(E element);
E remove();
int size();
}
(b)队列的两种实现方式:
(1)使用循环数组:例ArrayQueue类(2)使用链表:例 LinkedList类; 每一个实现都可以通过一li个实现了Queue接口的类表示。
(c)只有在构建集合对象时,使用具体的类才有意义。可以使用接口类型存放集合的引用。
Queue<Customer> expressLane = new CircularArrayQueue<>(100);
expressLane.add(new Customer("Harry"));
利用这种方式,当想法改变时,是需要改变调用构造器的地方即可。循环数组是一个游街集合,即容量有限。
2.Collection接口
java中集合的基本接口为Collection接口。这个接口有两个基本方法,例如下:
public interface Collection<E> { boolean add(E element); Iterator<E> iterator(); ... }
add方法用于向集合中添加元素,如果添加的元素确实改变了集合就返回true,如果集合没有发生改变就返回false. iterator方法用于返回一个实现了Iterator接口的对象。可以使用这个迭代对象一次访问集合中的元素。
3.迭代器
iterator接口包含四个方法:
public interface Iterator<E> { E next(); boolean hasNext(); void remove(); default void forEachRemaning(Consumer<? super E>action); }
反复调用next方法,可以逐个访问集合中的每个元素。当到达集合末尾时,next将会输出NoSuchElementException.因此,在调用next之前调用hasNext方法。如果迭代对象还有多个供访问的元素,这个方法就返回true。
如果想要查看集合中的所有元素,就请求一个迭代器,并在hasNext返回ture时反复地调用next方法。Collection接口扩展Iterable接口。因此,标准类库中的任何集合都可以使用“for each”循环。
元素被访问的顺序取决于于集合类型。应该将java迭代器认为是 位于两个元素之间的。当调用next时,迭代器就超过下一个元素,并返回刚刚越过的哪个元素的引用。
Interator接口的remove方法将会删除上次调用next时返回的元素。next和remove方法的调用具有相互依赖性。如果调用remove之前没有调用next时不合法的。例如:
it.remove(); it.next(); it.remove();//OK
4.泛型实用方法
Collection与Iterator都是泛型接口,可以编写操作任何集合类型的实用方法。另外,Collectio接口声明了很多方法。例如:
Iterator<E> iterator()//返回一个用于访问集合中每个元素的迭代器
int size()//返回当前存储在集合中的元素个数
boolean add(Object element)//将一个元素添加在集合中。如果这个调用改变了集合,返回true。
boolean remove(Object obj)从这个集合中删除等于obj的对象。如果有匹配的对象被删除,返回true.
List是一个有序集合。元素会增加到容器中的特定位置。有两种方法:(1)使用迭代器访问(2)使用一个整数索引来访问(随机访问),因为这样可以按任意顺序访问元素。但是,使用迭代器访问时,必须顺序地访问元素。List接口定义的多个随机访问方法:void add(int index,E element) void remove(int index) E get(int index) E set(int index, E element)
ListIterator接口时Iterator的一个子接口。它定义了一个方法用于在迭代器位置前面增加一个元素:void add(E element).
二、具体的集合
1.链表
在java语言中,,所有列表实际上都是双向链接的——每一个还存放着指向前驱节点的引用。链表是一个有序集合。
2.数组列表
List接口用于描述有序集合,且有两种中访问元素的协议,(a)用迭代器(b)用get和set方法随机地访问每个元素。第二章方法不适用于链表却适用于数组,集合类提供了熟悉的ArrayList类,这个类也实现了List接口。
ArrayList封装了一个每个列表称为桶动态再分配的对象数组。
3.散列表
散列表由米娜子就可看出时没有确定位置的。但是散列表会为每一个元素对象计算一个整数,称为散列码。散列码是由对象的实例域产生的一个整数。或者说,具有不同数据域的对象产生不同的散列码。
在java中,散列表用数组列表实现。在散列表中由有: HashSet()//用来构造新散列表........
4.树集
树集是一个有序集合。可以以任意顺序将元素插入到集合中。自对集合进行遍历时,每个值将自动地按排序后的顺序呈现。创建一个树集的方法为:TreeSet()
5.队列与双端队列
有两个端头的队列称为双端队列。可在头部和尾部同时添加或者删除元素。不支持在队列中间插入。
6.优先级队列
可按任意顺序插入的元素,但按照排序的顺序进行检索。优先级队列用了堆(可以自我调整的二叉树)。一个优先级对象可以保存实现了Comparable接口的类对象,也可以保存在构造器中提供的Comparator对象。
三、映射
当我们知道某些关键信息且想茶轴与之对应的元素时的这种接口可称之为映射。映射用来存放键/值对。
1.映射的基本操作
java类库为映射提供了两个实现:HashMap和TreeMap。这两个类都实现了Map接口。每当往映射中添加对象时,必须同时提供一个键,这里,键是一个字符串,对应的值是Employee对象。
而且,键必须是唯一的,不能对同一个键存放两个值。
2.更新映射项
(1)可以用getOrDefault方法(2)调用putIfAbsent方法,只有当键原先存在时才会放入一个值。merge方法可以简化这个操作。
3.映射视图
集合框架可以得到映射的视图。这是实现了Collection接口或某个子接口的对象。
4.弱散列映射
5.链接散列集与映射
链接散列映射将用访问顺序,而不是插入顺序,对映射条目进行迭代。
6.枚举集与映射
EnumSet是一个枚举类型元素集的高效实现。枚举类型只有有限个实例,所以EnumSet内部用序列实现。EnumMap是一个键类型为美剧类型的映射。它可以直接且有效的用一个数值组实现。
7.标识散列映射
四、视图与包装器
1.什么时视图?
(1). Arrays.asList方法
在Arrays类中有一个静态方法--asList方法,这个方法作用是:将普通的Java数组包装成一个List集合。例如:
String []strings = new String[10]; strings[0] = "pby"; strings[1] = "pby1"; strings[2] = "pby2"; List<String> stringList = Arrays.asList(strings);
返回的对象不是一个ArrayList对象。它就是一个视图对象,这个对象带有底层数组的get和set方法。
那这个视图对象与普通的List或者ArrayList对象有什么区别吗?
在这里,视图对象不能操作所有改变数组大小的方法(比如说,add方法和remove方法),在调用这些方法的时候,程序会抛出一个UnsupportedOperationException异常;但是普通的List对象能够正常的调用改变数组大小的方法。
(2). Collections.nCopies方法
与Arrays.asList方法类似的另一个方法那就是在Collection中的nCopies方法。例如:
List<String> stringList = Collections.nCopies(100, "pby");
上面的代码将创建一个包含100个"pby"字符串的List集合对象。这样的操作优势在于存储代价很小,因为这个对象不能修改大小。这就是视图技术的一种巧妙应用。
List<String> list = new ArrayList<>(); for (int i = 0; i < 20; i++) { list.add("" + i); } System.out.println(list); //获取第10个~第19个 List<String> list2 = list.subList(9, 20); System.out.println(list2); System.out.println(list); //清空自子范围视图之后,原来的List集合对象相应位置的数据也会被自动清空的 list2.clear(); System.out.println(list2); System.out.println(list);
4,不可修改的视图
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
每个方法都定义于一个接口。例如,Collections.unmodifiableList方法定义于List接口,与ArrayList、LinkedList或者任何实现了List接口的其他类一起协同工作。
例如,假设想要查看某个集合的内容,但是又能避免这个集合会被修改的情况,就可以进行下列的操作:
LinkedList<String> list = new LinkedList<>(); list.add("pby"); list.add("pby2"); List<String> list2 = Collections.unmodifiableList(list); //是不能被修改的 //list2.set(0, "dasdas");
但是我们这里需要注意的是,不可更改的视图对象并不是指集合本身不可修改,我们仍然可以通过集合原来的引用来(犹如上面例子中的list)对集合进行修改。同时,如果原来的引用修改了集合,那么视图对象的内容也是跟着变化的。
但是我们使用视图机制来确保常规集合的线程安全,而不是实现线程安全的集合类。例如,Collections类的静态方法synchronizedMap方法可以将任何一个映射表转换成为具有同步访问方法的Map:
Map<String, String> map = Collections.synchrizedMap(new HashMap<String, String>());
就可以自由的使用多线程来访问map对象了。像get和put这类方法都是同步操作的,即在另一个线程中调用另一个方法之前,刚才的方法调用必须彻底执行完毕。
6.受查视图
受查视
List<String> list = new ArrayList<>(); List list2 = list; //程序运行到这里是不会报错的,但是如果后面访问这里元素, //并且试图强制转换为String类型的变量才会抛出一个ClassCastException的异常 list2.add(10); //这里会抛出ClassCastException异常 //String string = (String) list2.get(0);
如果我们使用受查视图的话,例如:
List<String> list3 = Collections.checkedList(list, String.class); List list4 = list3; //程序运行到这里就会抛出一个ClassCastException的异常 list4.add(10);
虽然在编译时,程序是没有报错的,但是程序一旦运行到add方法那里直接会抛出一个ClassCastException的异常。也就是说,通过受查视图,可以逃避编译时的检查,但是躲不过运行时的检查。
五、算法
第十章 图形程序设计
1.Swing概述
swing并没有完全取代AWT,而是基于AWT架构之上。swing仅仅提供了功能更加强大的用户界面组件。,尤其是在用swing编写程序是,还是需要使用基本的AWT处理时间。从现在开始,swing是指被绘制的用户界面类,而awt是指像事件处理这样抽象窗口工具箱的底层机制。
虽然在用户屏幕上显示基于swing的用户界面组件比现实awt基于对等体的界面元素要慢一些,但在计算机快速运行下这没什么。以下原因让人们选择swing:
1.swing拥有一个丰富、便捷的用户界面元素集合。2、swing对平台的依赖很小,意味着他有很少的关于平台的bug。3.给予用户一致的感觉。
对于第三点存在一些潜在问题,若在所有平台上用户界面元素看起来都一样,他们可能与平台的本地控件不一样,而这些平台的用户对此可能并不熟悉。swing采取一种巧妙的方式解决。指定观感(look and feel)。
注意:
1. swing类位于javax.swing包中。包名表示这是Java的一个扩展包。不过在1.2版本后,每个Javase实现中都必须包含他。
2. 所有的swing组件都必须由事件分派线程(Event dispatch thread)进行配置,线程将按键控制和鼠标点击转移 到用户接口组件中。但是许多swing程序并没有这么做,而是直接在主程序中完成初始化。由于swing 组件很复杂,jdk程序员不能保证这种方式的安全性 ,为了以防万一,尽管代码看起来神秘,但是最好的 选择。
2.创建框架
创建框架
在Java中,顶层窗口(就是没有包含在任何其他窗口中的窗口)被称为框架(frame)。
在AWT库中有一个称为Frame的类,用于描述顶层窗口。这个类的Swing版本名为JFrame,它扩展于Frame类。
JFrame是极少数几个不绘制在画布上的Swing组件之一。因此,它的修饰部件(按钮、标题栏、图标等)由用户的窗口系统绘制,而不是由Swing绘制。
注意:绝大多数Swing组件类都以“J”开头,例如,JButton,JFrame等。在Java中有Button和Frame这样的类,但它们属于AWT组件。如果偶尔忘记了“J”程序仍然可以编译和运行,但是将Swing和AWT组件混合在一起使用将会导致视觉和行为的不一致。
现在我们来做一个示例,依然是选择使用工具Eclipse。
首先为了便于管理和维护,我们建立一个包,包名起为SwingDemo。然后建立它的子包No1。
在首先编写框架代码JframeDemo.java子包内我们先建立两个文件,一个是用于建立框架的文件JframeDemo.java,用来存放框架代码,另一个用于演示的文件Demo.java用来编写main方法做演示。
首先编写框架代码JframeDemo.java:
public class JframeDemo extends JFrame{ private static final int DEFAULT_WIDTH=300; private static final int DEFAULT_HEIGHT=300; public JframeDemo(){ setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT); } }
Demo演示文件编写如下:
public class Demo{ public static void main(String[] args){ EventQueue.invokeLater(()->{ JFrame frame=new JframeDemo(); frame.setDefaultCloseOperation("JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } }
3.框架定位
JFrame类本身只包含若干个改变外观的方法。然而,继承了各个超类中许多处理框架大小和位置的方法。如:
dispose方法用于关闭窗口,并回收创建窗口所使用的全部系统资源。
setIconImage方法用于将窗口极小化时的图标设置为Image对象。
setTitle方法用于改变标题栏中的文本。
setResizable方法利用一个boolean值确定框架的大小是否允许用户改变。
setLocation(x,y)方法将窗口放置在坐标为x,y的位置。
setBounds(x,y,width,height)方法将窗口指定位置,同时设定窗口大小。
但是对于不同分辨率的屏幕,框架的大小不同,所以应先检查用户屏幕的分辨率,并根据其分辨率编写代码重置框架的大小。这就需要用到Toolkit类,它包含了很多与本地窗口系统进行交付的方法。先调用静态方法getDefaultToolkit得到一个Toolkit对象。然后调用getScreenSize方法,该方法以Dimension对象的形式返回屏幕的大小。Dimension对象用公有实例变量width和height保存屏幕的宽度和高度
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
int screenWidth = screenSize.width;
int screenHeight = screenSize.height;
4.在组件中显示信息
- 在JFrame中有四层面板。其中的根面板、层级面板和玻璃面板人们并不太关心;它们是用来组织菜单栏和内容窗格以及实现观感的。Swing程序员最关心的是内容窗格(content pane)。在设计框架的时候,将所有的组件添加到内容窗格中。
- 绘制一个组件,需要定义一个扩展JComponent的类,并覆盖其中的paintComponent方法。paintComponent方法有一个Graphics类型的参数,这个参数保存着用于绘制图像和文本的设置。在Java中,所有的绘制都必须使用Graphics对象,其中包含了绘制图案、图像和文本的方法。
- 无论何种原因,只要窗口需要重新绘图,事件处理器就会通告组件,从而引发执行所有组件的paintComponent方法。
- 一定不要自己调用paintComponent方法。在应用程序需要重新绘图的时候,这个方法将被在佛那个地调用,不要人为的干预这个自动的处理过程。
- 如果需要强制刷新屏幕,就需要调用repaint方法,而不是paintComponent方法。它将引发采用相应配置的Graphics对象调用所有组件的paintComponent方法。
- 在框架中添加一个或多个组件时,如果只想使用它们的首选大小,可以调用pack方法而不是setSize方法。
- 有些程序员更喜欢扩展JPanel,而不是JComponent。JPanel是一个可以包含其他组件的容器(container),但同样也可以在其上面进行绘制。有一点不同之处是,面板不透明,这意味着需要在面板的边界内绘制所有的像素。最容易实现的方法是,在每个面板子类的paintComponent方法中调用super.paintComponent来用背景色绘制面板。
- javax.swing.JFrame 1.2
- Container getContentPane()
返回这个JFrame的内容窗格对象。 - Component add(Component c)
将一个给定的组件添加到改框架的内容窗格中(在Java SE 5.0以前的版本中,这个方法将抛出一个异常)。
- Container getContentPane()
- java.awt.Component 1.0
- void repaint()
“尽可能快地”重新绘制组件。 - Dimension getPreferredSize()
要覆盖这个方法,发挥这个组件的首选大小。
- void repaint()
- javax.swing.JComponent 1.2
- void paintComponent(Grphics g)
覆盖这个方法来描述应该如何绘制自己的组件。
- void paintComponent(Grphics g)
- java.awt.Window 1.0
- void pack()
调整窗口大小,要考虑到其组件的首选大小。
- void pack()
5.处理2D图形
- Graohics类包含绘制直线、矩形和椭圆等方法。但是,这些绘制图形的操作能力非常有限。例如,不能改变先的粗细,不能旋转这个图形。
- Java SE 1.2引入了Java 2D库,这个库实现了一组功能强大的图形操作。
- 要想使用Java 2D库绘制图形,需要获得一个Graphics2D类对象。这个类是Graphics类的子类。自从Java SE 2版本依赖,paintComponent方法就会自动地获取一个Graphics2D类对象,只需要进行一次类型转换就可以了。
- Java 2D库采用面向对象的方式将几何图形组织起来。包括描述直线、矩形的椭圆的类:LINE2D、Rectangle2D、Ellipse2D这些类都实现了Shape接口。
- 要想绘制图形,首先要创建一个实现了Shape接口的类的对象,然后调用Graphics2D类中的draw方法。
- 使用Java 2D图形或许会增加一些复杂度。在1.0的绘制方法中,采用的是整型像素坐标,而Java 2D图形采用的是浮点坐标。在很多情况下,用户可以使用更有意义的形式(例如,微米或英寸)指定图形的坐标,然后再将其转换成像素,这样做很方便。在Java 2D库中,内部的很多浮点极端都采用单精度float。毕竟,几何计算的最终目的是要设置屏幕或打印机的像素,所以单精度完全可以满足要求了。只要舍入误差限制在一个像素的范围内,视觉效果就不会受到任何影响。另外,在某些平台上,float计算的速度比较快,并且只占据double值的一般存储量。
- 由于后缀和类型转换都有点麻烦,所以2D库的设计者决定为每个图形类提供两个版本:一个是为那些节省空间的程序员提供的float类型的坐标;另一个是为那些懒惰的程序员提供的double类型的坐标。
- Rectangle2D方法的参数和返回值均为double类型。
- 直接使用Double图形类可以避免处理float类型的值,然后如果需要创建上千个图形对象,还是应该考虑使用Float类,这样可以节省存储空间。
- Rectangle2D和Ellipse2D类都是由公共超类RectangularShape继承来的。
- RectangularShape类定义了20多个有关图形操作的通用方法,其中比较常用的方法有getWidth、getHeight、getCenterX、getCenterY等。
- 从Java 1.0遗留下来的两个类也被放置在图形类的继承层次中。它们是Rectangle和Point类,分别扩展于Rectangle2D和Point2D类,并用整型坐标存储矩形和点。
- Rectangle2D和Ellipse2D对象很容易构造,需要给出左上角的x和y坐标,宽和高。
6.使用颜色
- 使用Graphics2D类的setPaint方法可以为图形环境上的所有后续的绘制操作选择颜色。
- 只需要将调用dra替换为调用fill就可以用一种颜色填充一个封闭图形的内部。
- 要想绘制多种颜色,就需要按照选择颜色、绘制图形、再选择另外一种颜色、再绘制图形的过程实施。
- fill方法会在右侧和下方少绘制一个像素。
- Color类用于定义颜色。在java.awt.Color类中提供了13个预定义的常量,它们分别表示13种标准颜色。BLANK、BLUE、CYAN、DARK_GRAY、GRAY、LIGHT_GRAY、MAGENTA、ORANGE、PINK、RED、WHITE、WELLOW。
- 可以通过提供红、绿和蓝三色成分来创建一个Color对象,以达到定制颜色的目的。
- 要想设置背景颜色,就需要使用Component类中的setBackground方法。Component类是JComponent类的祖先。
- setForeground方法是用来设定在组件上进行绘制时使用的默认颜色。
- Color类中的brighter()方法和darker()方法的功能,它们分别加亮或变暗当前的颜色。使用brighter方法也是加亮条目的好办法。实际上,brighter()只微微地加亮一点。要达到耀眼的效果,需要调用三次这个方法:
c.brighter().brighter().brighter()
。 - java在SystemColor类中与定义了很多颜色的名字。在这个类中的常量,封装了用户系统的各个元素的颜色。
7.使用文本特殊字体
- 可以通过字体名(font dace name)指定一个字体。字体名由”Helvetica”这样的字体家族名(font family name)和一个可选的”Bold”后缀组成。
- 要想知道某台特定计算机上允许使用的字体,就需要调用GraphicsEnvironment类中的getAvailableFontFamilyNames方法。这个方法将返回一个字符型数组,其中包了所有可用的字体名。GraphicsEnvironment类描述了用户系统的图形环境,为了得到这个类的对象,需要调用静态的getLocalGraphicsEnvironment方法。
- 点数目是排版中普遍使用的表示字体大小的单位,每英寸包含72个点。
- 字体风格值:Font.PLAIN、Font.BOLD、Font.ITALIC、Font.BOLD+Font.ITALIC。
- 要想得到屏幕设备字体属性的描述对象,需要调用Graphics2D类中的getFontRenderContext方法。它将返回一个FontRenderContext类对象。
- 基线(baseline)是一条虚构的线。上坡度(ascent)是从基线到坡顶(ascenter)的距离。下坡度(descent)是从基线到坡顶(descenter)的距离。
- 行间距(leading)是某一行的坡底与其下一行的坡顶之间的空隙。字体的高度是连续两个基线之间的距离,它等于下坡度+行间距+上坡度。
- getStringBounds方法返回的矩形宽度是字符串水平方向的宽度。矩形的高度是上坡度、下坡度、行间距的总和,如果需要知道下坡度或行间距,可以使用Font类的getLineMetrics方法,这个方法将返回一个LineMetrics类对象。
- 为了能够获得中央的位置,可以使用getWidth()得到组件的宽度。使用bounds.getWidth()得到字符串的宽度。前者减去后者就是两侧应该剩余的空间,因此,每侧剩余的空间应该是这个差值的一般。高度也一样。
- java.awt.Font 1.0
- Font(String name,int style,int size)
创建一个字体对象。
参数: name 字体名。不是字体名(例如,“Helvetica Bold”),就是逻辑字体名(例如,“Serif”、“SansSerif”)。style 字体风格(Font.PLAIN、Font.BOLD、Font.ITALIC或Font.BOLD+Font.ITALIC)。size 字体大小(例如,12)。 - String getFontName()
返回字体名,例如,“Helvetica Bold”。 - String getFamily()
返回字体家族名,例如,“Helvetica”。 - String getName()
如果采用逻辑字体名创建字体,将返回逻辑字体,例如,“SansSerif”;否则,返回字体名。 - Rectangle2D getStringBounds(String s,FontRenderContext context) 1.2
返回包围这个字符串的矩形。矩形的起点为基线。矩形顶端的y坐标等于上坡度的负值。矩形的高度等于上坡度、下坡地和行间距之和。宽度等于字符串的宽度。 - LineMetrics getLineMetrics(String s,FontRenderContext context) 1.2
返回测定字符串宽度的一个线性metrics对象。 - Font deriveFont(int style) 1.2
- Font deriveFont(float size) 1.2
- Font deriveFont(int style,float size) 1.2
返回一个新字体,除给定大小和字体风格外,其余与原字体一样。 - java.awt.font.LineMetrics 1.2
- float getAscent()
返回字体的上坡度—从基线到大写字母顶端的距离。 - float getDescent()
返回字体的下坡度—从基线到坡底的距离。 - float getLeading()
返回字体的行间距—从一行文本底端到下一行文本顶端之间的空隙。 - float getHeight()
返回字体的总高度—两条文本基线之间的距离(下坡度+行间距+上坡度)。
- float getAscent()
- java.awt.Graphics 1.0
- Font getFont()
- void setFont(Font font)
获取或设置当前的字体。这种字体将被应用于后续的文本绘制操作中。
参数:font 一种字体。- void drawString(String str,int x,int y)
参数:str 将要绘制的字符串。x 字符串开始的x坐标。y 字符串基线的y坐标。
- void drawString(String str,int x,int y)
- java.awt.Graphics 1.2
- FontRenderContext getFontRenderContext()
返回这个图形文本中,指定字体特征的字体绘制环境。 - void drawString(String str,float x,float y)
采用当前的字体和颜色绘制一个字符串。
参数:str 将要绘制的字符串。 x 字符串开始的x坐标。y 字符串基线的y坐标。
- FontRenderContext getFontRenderContext()
- javax.swing.JComponent 1.2
- FontMetrics getFontMetrics(Font f) 5.0
获取给定字体的度量。FontMetrics类是LineMetrics类的早先版。
- FontMetrics getFontMetrics(Font f) 5.0
- java.awt.FontMetrics 1.0
- FontRenderContext getFontRenderContext() 1.2
返回字体的字体绘制环境。
- FontRenderContext getFontRenderContext() 1.2
- Font(String name,int style,int size)
8.显示图像
1.使用Graphics类的drawImage方法将图像显示出来。
2.java.awt.Graphics 1.0
(1)boolean drawImage(Image img,int x,int y,ImageObserver observer)绘制一副非比例图像。注意:这个调用可能会在图像还没有绘制完毕就返回。
参数:img 将要绘制的图像。x 左上角的x坐标。y 左上角的y坐标。observer 绘制进程中以通告为目的的对象(可能为null)。
(2)boolean drawImage(Image img,int x,int y,int width,int height,ImageObserver observer)
绘制一副比例图像。系统按照比例将图像放入给定宽和高的区域。注意:这个调用可能会在图像还没有绘制完毕就返回。
参数:img 将要绘制的图像。x 左上角的x坐标。y 左上角的y坐标。width 描述图像的宽度。height 描述图像的高度。observer 绘制进程中以通告为目的的对象(可能为null)。
(3)void copyArea(int x,int y,int width,int height,int dx,int dy)
拷贝屏幕的一块区域。
参数:x 原始区域左上角的x坐标。y 原始区域左上角的y坐标。width 原始区域的宽度。 height 原始区域的高度。dx 原始区域到目的区域的水平距离。dy 原始区域到目的区域的数值距离。
第二部分 实验部分
实验1: 导入第9章示例程序,测试程序并进行代码注释。
测试程序1:
l 使用JDK命令运行编辑、运行以下三个示例程序,结合运行结果理解程序;
l 掌握Vetor、Stack、Hashtable三个类的用途及常用API。
//示例程序1 import java.util.Vector; class Cat { private int catNumber; Cat(int i) { catNumber = i; } void print() { System.out.println("Cat #" + catNumber); } } public class Cats{ public static void main(String[] args){ Vector<Cat> cats= new Vector<Cat>(); for(int i=0; i<7; i++) cats.addElement(new Cat(i)); for(int i=0; i<cats.size(); i++) (cats.elementAt(i)).print(); } } //示例程序2 import java.util.*; public class Stacks { static String[] months={"金","银","铜","铁"}; public static void main(String[] args){ Stack<String> stk = new Stack<String> (); for(int i=0; i<months.length; i++) stk.push(months[i]); System.out.println(stk); System.out.println("element 2=" + stk.elementAt(2)); while(!stk.empty()) System.out.println(stk.pop()); } } //示例程序3 import java.util.*; class Counter { int i = 1; public String toString() { return Integer.toString(i); } } public class Statistics { public static void main(String[] args) { Hashtable ht = new Hashtable(); for (int i = 0; i < 10000; i++) { Integer r = new Integer((int) (Math.random() * 20)); if(ht.containsKey(r)) ((Counter)ht.get(r)).i++; else ht.put(r, new Counter()); } System.out.println(ht); } }
实验运行源代码为:
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<Cat> cats= new Vector<Cat>(); //创建一个Vector<Cat>类对象cats for(int i=0; i<7; i++) //for循环通过Vector<Cat>类对象cats来调用addElement()方法 cats.addElement(new Cat(i)); for(int i=0; i<cats.size(); i++) (cats.elementAt(i)).print(); //通过Vector<Cat>类对象cats来调用elementAt()方法以及Cat类的print()方法 } }
实验运行结果截图为:
程序运行源代码为:
package Stacks; //示例程序2 import java.util.*; public class Stacks //堆栈类 { static String[] months={"金","银","铜","铁"}; //定义一个字符类数组months[],其中元素为金、银、铜、铁 public static void main(String[] args){ Stack<String> stk = new Stack<String> (); //创建一个Stack<String>类对象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两个程序,结合程序运行结果理解程序;
import java.util.*; public class ArrayListDemo { public static void main(String[] argv) { ArrayList al = new ArrayList(); // Add lots of elements to the ArrayList... al.add(new Integer(11)); 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:"); for (int i = 0; i < al.size(); i++) { System.out.println("Element " + i + " = " + al.get(i)); } } } import java.util.*; public class LinkedListDemo { public static void main(String[] argv) { LinkedList l = new LinkedList(); l.add(new Object()); l.add("Hello"); l.add("zhangsan"); ListIterator li = l.listIterator(0); while (li.hasNext()) System.out.println(li.next()); if (l.indexOf("Hello") < 0) System.err.println("Lookup does not work"); else System.err.println("Lookup works"); } }
程序运行源代码为:
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)); } } }
程序运行结果截图为:
程序源代码为:
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"); } }
程序运行结果截图为:
实验代码如下:
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<String> a = new LinkedList<String>();//创建一个LinkedList<String>类对象 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); } }
掌握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()方法, } }
程序运行输出截图为:
在elipse IDE中调试运行教材407页程序10-1,结合程序运行结果理解程序;与上面程序对比,思考异同;
掌握空框架创建方法;
了解主线程与事件分派线程概念
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); } }
实验结果输出截图为:
实验总结:
(1)这周我们主要学习了两个方面的知识,主要学习了有关集合和图形程序设计的知识。对于我来说相对容易理解的是图形程序设计部分,而集合相关知识对我来说相对更难一点。这次的实验没有太难,
因为这次都是验证性的实验,实验过程当中也没有出现验证错误等问题。当然,通过实验我才更加深入的了解了程序的逻辑性。
(2)通过这次实验基础总结,更加系统的看了一遍书,理解了在老师讲解过程中没有理解的细微的知识点。