下周就考Java了,这学期的Java学习报告就到这里结束了。寒假的时候可能会写几篇复习的,或者写写自己的程序吧。
教材内容总结
十四、图形、图像与音频
组件类Component类有一个方法public void paint(Graphics g),程序可以在其子类中重写,当程序运行时,Java运行环境会用Graphics2D将参数g实例化,对象g就可以在重写paint方法的组件上绘制图形、图像。(图形是矢量的概念,基本元素是图形指令;图像是位图的概念,基本元素是像素)
Graphics2D的“画笔”分别使用draw和fill方法绘制和填充一个图形。
(1)绘制基本图形
在java.awt.geom包中的有很多类用来绘图
new Line2D.Double(double x1,double y1,double x2,double y2);
//创建起点(x1,y1)到终点(x2,y2)的直线
new Rectangle2D.Double(double x,double y,double w,double h);
//创建一个左上角坐标是(x,y)宽是w,高是h的矩形对象
new RoundRectangle2D.Double(double x,double y,double w,double h,double arcw,double arch);
//创建左上角坐标是(x,y),宽w,高h,圆角长轴和短轴分别是arcw和arch的圆角矩形对象
new Ellipse2D.Double (double x,double y,double w,double h);
//创建一个外接矩形的左上角坐标是(x,y),宽是w,高是h的椭圆对象
new Arc2D.Double(double x,double y,double w,double h,double start,double extent,int type);
//创建圆弧对象。圆弧是椭圆的一部分,参数x,y,w,h指定椭圆的位置和大小,参数start和extent单位是度,从start的角度开始逆时针或顺时针方向画出extent度的弧,当extent为正时,为逆时针。type取值Arc2D.OPEN、Arc2D.CHORD、Arc2D.PIE决定弧是开弧、弓弧还是饼弧。
Graphics2D对象调用drawString(String s,int x,int y)方法从参数x、y指定的坐标位置,从左向右绘制参数s指定的字符串。
QuadCurve2D.Double类绘制二次曲线和三次曲线。如一条二次曲线需要三个点来确定,所以
QuadCurve2D curve = new QuadCurve2D.Double(50,30,10,10,50,100)
//绘制一条断电为(50,30)(50,100),控制点为(10,10)的二次曲线。
//三次曲线类似,需要四个点
java.awt包中的Polygon类可以创建空多边形,然后多边形调用addPoint(int x,int y)方法向多边形添加顶点,下面例子绘制了太极图和四边形
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
class MyCanvas extends JPanel {
public void paint(Graphics g) {
Graphics2D g_2d=(Graphics2D)g;
Arc2D arc=new Arc2D.Double(0,0,100,100,-90,-180,Arc2D.PIE);
g_2d.setColor(Color.black);
g_2d.fill(arc);
g_2d.setColor(Color.white);
arc.setArc(0,0,100,100,-90,180,Arc2D.PIE);
g_2d.fill(arc);
arc.setArc(25,0,50,50,-90,-180,Arc2D.PIE);
g_2d.fill(arc);
g_2d.setColor(Color.black);
Ellipse2D ellipse=new Ellipse2D.Double(40,15,20,20);
g_2d.fill(ellipse);
arc.setArc(25,50,50,50,90,-180,Arc2D.PIE);
g_2d.fill(arc);
g_2d.setColor(Color.white);
ellipse.setFrame(40,65,20,20);
g_2d.fill(ellipse);
g.setColor(Color.black);
Polygon polygon=new Polygon();
polygon.addPoint(150,10);
polygon.addPoint(100,90);
polygon.addPoint(210,90);
polygon.addPoint(260,10);
g_2d.draw(polygon);
}
}
public class Example14_1{
public static void main(String args[]) {
JFrame win = new JFrame();
win.setSize(400,400);
win.add(new MyCanvas());
win.setVisible(true);
}
}
(2)变换图形
用AffineTransform类实现对图形的平移、缩放或旋转,先创建一个对象,然后该对象有下列三个方法实现对图形变换操作
translate(double a,double b)将图形在x轴方向移动a个像素单位,a为正值时向右移动;y轴方向移动b个像素单位,b是正值时向下。
scale(double a,double b),将图形在x轴方向缩放a倍,y轴方向缩放b倍
rotate(doble number,doble x,double y)将图形眼顺时针或逆时针方向以(x,y)为轴旋转number个弧度
(3)图形的布尔运算
两个图形进行布尔运算之前,必须分别用这两个图形创建两个Area区域对象,如
Area a1 = new Area(t1); Area a2 = new Area(t2); 这样a1就是图形t1所围成的区域,a1调用add方法,a1.add(a2);之后,a1就变成a1和a2经过“或”运算后的区域。
public void add(Area r) //或 两个图形重叠部分
public void intersect(Area r) //与 两个图形的合并
public void exclusiveOr(Area rhs) //异或 a1去掉a1和a2的重叠部分
public void subtract(Area rhs) //差 两个图形非重叠部分
(4)绘制图像
组件上可以显示图像,如为了让按钮上显示名称为cat.jpg的图像,可以先用Icon类的子类ImageIcon创建封装cat.jpg图形文件的ImageIcon对象,然后让按钮button调用方法设置其上的图像,除此之外,可以使用Graphics绘制图像
1、加载图像
Java运行环境提供一个Toolkit对象,任何一个组件调用getToolkit()方法可以返回这个对象的引用。Toolkit类的对象调用方法Image getImage(String fileName)或者Image getImage(File file),可以返回一个Image对象,该对象封装着参数file或参数filename指定的图像文件。
2、绘制
图像被加载之后,就可以在paint()方法中绘制它。Graphics提供了几个名为drawImage()的方法用于绘制图像,他们功能相似,都是在指定位置绘制一幅图像,不同之处在于确定图像大小的方式、解释图像中透明部分的方式、以及是否支持图像的剪辑和拉伸。
public boolean drawImage(Image img,int x,int y,ImageObserver);参数img 是被绘制的Image对象,x,y是要绘制指定图像的矩形的左上角所处的位置,observer是加载图像时的图像观察器。调用该方法时,若组件的宽和高设计不合理,可能图像某些部分未能绘制到组件上。
(5)播放音频
Java可以编写播放.au、.aiff、.wav、.midi、.rfm格式的音频程序。假设音频问价hello.wav位于应用程序当前目录中,那么播放音频的步骤是:
1、创建file对象, 2、创建URI对象 3、获取URI对象 4、创建音频对象 5 、 播放、循环和停止
clip.play() //开始播放
clip.loop() //循环播放
clip.stop() //停止播放
十五 泛型与集合框架
为实现如链表这种数据结构,需要实现往链表中插入结点或从链表中删除结点的算法,有些繁琐。在JDK 1.2后,Java提供了实现常见数据结构的类,这些类成为Java集合框架。在JDK1.5后,Java集合框架支持泛型。
(1)泛型
泛型是在JDK 1.5中推出,目的是建立具有类型安全的结合框架,如链表、散列映射等数据结构。
1、泛型类声明
class 名称<泛型列表> 这样声明得到类称作泛型类。如 class People <E> People是泛型类的名称,E是其中的泛型,E可以是任何对象或接口,但不能是基本类型数据。泛型列表给出的泛型可以作为类的成员变量的类型、方法的类型以及局部变量的类型
泛型类声明和创建对象时,必须用具体的类型替换<>中的泛型,如下列例子
public class Example15_1 {
public static void main(String args[]) {
Circle circle=new Circle(10);
Cone<Circle> coneOne=new Cone<Circle>(circle);//创建一个(圆)锥对象
coneOne.setHeight(16);
System.out.println(coneOne.computerVolume());
Rect rect=new Rect(15,23);
Cone<Rect> coneTwo=new Cone<Rect>(rect);//创建一个(方)锥对象
coneTwo.setHeight(98);
System.out.println(coneTwo.computerVolume());
}
}
public class Circle {
double area,radius;
Circle(double r) {
radius=r;
}
public String toString() { //重写Object类的toString()方法
area=radius*radius*Math.PI;
return ""+area;
}
}
public class Cone<E> {
double height;
E bottom; //用泛型类E声明对象bottom
public Cone (E b) {
bottom=b;
}
public void setHeight(double h) {
height=h;
}
public double computerVolume() {
String s=bottom.toString();//泛型变量只能调用从Object类继承的或重写的方法
double area=Double.parseDouble(s);
return 1.0/3.0*area*height;
}
}
public class Rect {
double sideA,sideB,area;
Rect(double a,double b) {
sideA=a;
sideB=b;
}
public String toString() {
area=sideA*sideB;
return ""+area;
}
}
Java中的泛型类和C++的类模板有很大不同,上述例子中,泛型类中欧冠的泛型变量bottom只能调用Object类中的方法。
Java泛型主要目的是建立具有类型安全的数据结构。最重要的有点事,使用泛型类建立的数据结构,不必进行强制类型转换,级不要求进行运行时的类型坚持。
(2)链表
链表这种数据结构的特点在数据结构一课中已经讲明,这里不赘述。
Java.util包中的LinkedList<E>泛型类创建的对象以链表结构存储数据,链表使用add方法添加结点,结点是自动连接在一起,不需要操作安排结点中所存放的下一个或上一个结点,即链表是双链表
LinkedList<E>泛型类实现List<E>泛型接口中的一些常用方法一般要使用接口回调技术才可以实现。其中方法不一一赘述。
无论何种集合,应当允许用户以某种方法遍历集合中的对象,而不需要知道这些对象在集合中式如何表示及存储。Java集合框架为各种数据结构的集合提供了迭代器。由于迭代器遍历集合的方法在找到集合中的一个对象的同时,也的到待遍历的后继对象的引用,因此迭代器可以快速地遍历集合。链表对象可以使用iterator()方法获取一个iterator对象,该对象就是针对当前链表的迭代器。
import java.util.*;
public class Example15_2 {
public static void main(String args[]){
List<String> list=new LinkedList<String>();
for(int i=0;i<=60096;i++){
list.add("speed"+i);
}
Iterator<String> iter=list.iterator();
long starttime=System.currentTimeMillis();
while(iter.hasNext()){
String te=iter.next();
}
long endTime=System.currentTimeMillis();
long result=endTime-starttime;
System.out.println("使用迭代器遍历集合所用时间:"+result+"毫秒");
starttime=System.currentTimeMillis();
for(int i=0;i<list.size();i++){
String te=list.get(i);
}
endTime=System.currentTimeMillis();
result=endTime-starttime;
System.out.println("使用get方法遍历集合所用时间:"+result+"毫秒");
}
}
该例子比较了使用迭代器遍历链表和get(int index)方法遍历链表所用的时间。
程序可能需要对链表按着某种大小关系排序,一边查找一个数据是否和链表中某个节点的数据相等,Collections类提供用于排序和查找的类方法如下
public static sort(List<E>list)该方法可以将list中的元素按升序排列。 int binarySearch(List<T>list,T key, CompareTo<T> c)使用折半法查找list是否含有和参数key相等的元素,如果相等,方法返回和key相等的元素在链表中的索引位置(索引位置从0开始),否则返回-1。
String类实现了Compareable接口,规定字符串按字典序比较大小,如果链表中存放的对象不是字符串数据,那么创建对象的类必须实现Compareable接口,即实现Compareable接口中的方法int compareTo(object b),来规定对象的大小关系。例子如下
import java.util.*;
class Student implements Comparable {
int height=0;
String name;
Student(String n,int h) {
name=n;
height = h;
}
public int compareTo(Object b) { // 两个Student对象相等当且仅当二者的height值相等
Student st=(Student)b;
return (this.height-st.height);
}
}
public class Example15_4 {
public static void main(String args[ ]) {
List<Student> list = new LinkedList<Student>();
list.add(new Student("张三",188));
list.add(new Student("李四",178));
list.add(new Student("周五",198));
Iterator<Student> iter=list.iterator();
System.out.println("排序前,链表中的数据");
while(iter.hasNext()){
Student stu=iter.next();
System.out.println(stu.name+ "身高:"+stu.height);
}
Collections.sort(list);
System.out.println("排序后,链表中的数据");
iter=list.iterator();
while(iter.hasNext()){
Student stu=iter.next();
System.out.println(stu.name+ "身高:"+stu.height);
}
Student zhaoLin = new Student("zhao xiao lin",178);
int index = Collections.binarySearch(list,zhaoLin,null);
if(index>=0) {
System.out.println(zhaoLin.name+"和链表中"+list.get(index).name+"身高相同");
}
}
}
Collections类还提供了将链表中的数据重新随机排列的类方法以及旋转链表中数据的类方法
public static void shuffle(List<E>list) 将list中的数据按洗牌算法重新排列 static void rotate(List<E>list,int distance) 旋转链表中的数据 public static void reverse(List<E>list ) 翻转list中的数据。
(3)堆栈 跳过
(4)散列映射 采用散列表的数据结构存储数据,跳过
(5)树集 TreeSet<E>类实现Set<E>接口的类,它的大部分犯法都是接口方法。具体结构跳过。
树集结点的排列和链表不同,不按添加的先后顺序排列。树集用add方法添加结点,结点会按其存放的数据的“大小”顺序一层一层地依次排列,同一层中的结点从左到右岸“大小”顺序递增排列,下一层都比上一层小。和链表中排序一样,只有String类实现了Comareable接口中的compareTo(String s)方法,别的数据类型要另外实现方法。
(6)树映射 TreeMap<K,V>实现了Map<K,V>接口,称其为树映射。树映射使用public V put(K key,V value)方法添加结点,该结点不仅存储数据value,也存储器关联的关键字key。和树集不同,树映射保证结点是按照节点中的关键字升序排列。
(7)自动装箱和拆箱 JDK 1.5后,程序允许吧一个基本数据类型添加到类似链表等数据结构中,系统会自动完成基本类型到相应对象的转换(自动装箱)。当从一个数据结构中获取对象时,如果该对象是基本数据的封装对象,那么系统自动完成对象到基本类型的转换(自动拆箱)。下面例子展现其应用
import java.util.*;
public class Example15_10 {
public static void main(String args[]) {
ArrayList<Integer> list=new ArrayList<Integer>();
for(int i=0;i<10;i++) {
list.add(i); //自动装箱,实际添加到list中的是new Integer(i)。
}
for(int k=list.size()-1;k>=0;k--) {
int m=list.get(k); //自动拆箱,获取Integer对象中的int型数据
System.out.printf("%3d",m);
}
}
}
教材学习中遇到的问题
马上考试了,课才刚刚上完,经过上周和这周的梳理,基本上对教材中所提到的知识都有了大概的印象,但仍有很多知识点处于一知半解的状态,还有几天时间,fighting吧
敲代码遇到的问题
很多啊......,之前作业有一道题是敲简单地聊天室,关于while(scanner.hasnext())这个判断语句完全没有办法,想要改成输出指定字符串后自动断开服务器连接,但改动之后就变成什么都还没输入就自动断开服务器这种情况。在代码之路上艰难爬行......这个问题没能解决,或许我应该使用组件来避开这个问题。
代码行数 | 博客量 | 学习时长 | |
目标 | 3500 | 14 | 100 |
第一周 | 53 | 1 | 3 |
二 | 186 | 1 | 5 |
三 | 134 | 1 | 4 |
五 | 233 | 1 | 6 |
六 | 425 | 1 | 9 |
七 | 202 | 1 | 5 |
八 | 62 | 1 | 4 |
九 | 176 | 1 | 7 |
十 | 130 | 0 | 6 |
十一 | 56 | 1 | 8 |
十二 | 442 | 2 | 14 |
十三 | 462/2535 | 1/12 | 18/89 |