第六天
自己编写一种容器
对比ArrayList,要求实现以下功能:
add(value)
add(value,index)
get(index)
clear()
erase(index)
1.首先容器是一种泛型工具,java中泛型跟C++差不多,直接拿来用就可以了。
2.思考ArrayList如何实现自动改变大小的功能。之前在C++的书上只说了容器会自动分配内存空间,并随着自身大小调节新分配的内存空间。
打开ArrayList源码,发现容器将内容都存储在数组中,不断在内存中分配一个大于现容量的固定数组,并重新为数组赋值,不断重复此过程从而实现容器的功能。
3.如何将泛型存入数组呢?java中无法创建泛型的数组,查看ArrayList源码,发现其利用了向上向下转型功能,将各类类型数组都统一为Object类型(java中所有类型都继承自Object),在存入时自动向上转型,在取出时自动向下转型。(尽量少使用向上转型,或总是跟向下转型成对出现)。
4.方法都知道了,开始实践。
package com.zht0109.mylist;
public class MyList<T>
{
public static int initLength=2;
public int activitySize=0;
public int size=initLength;
private int growLength=initLength;
private Object[] elementData;
private Object[] value=new Object[initLength];
public T get(int index)
{
if(index<0||index>activitySize-1)
{
System.out.println("超出范围");
return null;
}
return (T)value[index];
}
public int size()
{
return activitySize;
}
public void clear()
{
value=new Object[initLength];
activitySize=0;
size=initLength;
growLength=this.initLength;
}
public void show()
{
for(int i=0;i<activitySize;i++)
{
System.out.println((T)value[i]);
}
}
public void erase(int index)
{
if(index<0||index>activitySize-1)
{
System.out.println("超出范围");
return;
}
if(size-activitySize>2*growLength)
{
value=cut(index);
growLength=calculationGrow();
}
else
{
Object[] tempValue=value;
copy(tempValue,value,index+1,activitySize,-1);
}
--activitySize;
}
public void add(T data,int index)
{
if(index<0||index>activitySize-1)
{
System.out.println("索引超出范围");
}
if (!checkSize(activitySize+1))
{
growLength=calculationGrow();
value=grow(growLength,index);
}
value[index]=data;
++activitySize;
}
public void add(T data)
{
if (!checkSize(activitySize+1))
{
growLength=calculationGrow();
value=grow(growLength);
}
value[activitySize]=data;
++activitySize;
}
private boolean checkSize(int newsize)
{
if (newsize>size||newsize<0)
{
return false;
}
else
{
return true;
}
}
private Object[] grow(int gl)
{
Object[] tempValue=new Object[gl+size];
copy(value,tempValue,0,value.length,0);
size=gl+size;
return tempValue;
}
private Object[] grow(int gl,int index)
{
Object[] tempValue=new Object[gl+size];
copy(value,tempValue,0,index,0);
copy(value,tempValue,index,value.length,1);
size=gl+size;
return tempValue;
}
private void copy(Object[] old,Object[] fresh,int begin,int end,int de)
{
for(int n=begin;n<end;++n)
{
fresh[n+de]=old[n];
}
}
private int calculationGrow()
{
return Math.max((size-growLength)/2, 2);
}
private Object[] cut(int index)
{
Object[] tempValue=new Object[activitySize-1];
copy(value,tempValue,0,index,0);
copy(value,tempValue,index+1,activitySize,-1);
size=activitySize-1;
return tempValue;
}
}
这其中每次growLength的大小可以自己设计方法调节,如果每次都只增长固定大小,则该容器很节省内存,但是运行速度慢。如果增长数目很大,程序运行快,但内存消耗大。
初始空间为2,Mylist与ArrayList进行运算速度比较如下:
MyList add程序运行时间: 879600ns
ArrayList add程序运行时间: 413400ns
MyList erase程序运行时间: 593800ns
ArrayList remove程序运行时间: 504000ns
将初始空间设置足够大,Mylist与ArrayList进行运算速度比较如下:
MyList add程序运行时间: 367300ns
ArrayList add程序运行时间: 361000ns
MyList erase程序运行时间: 505600ns
ArrayList remove程序运行时间: 516600ns
由于ArrayList源码无法修改,所以ArrayList始终是使用java容器的内存分配方法。
可以看出自己定义的MyList内存分配方式还是十分耗时的。
似乎ArrayList分配内存时参考了硬件中内存的区块进行分配,在add时每次ArrayList运行结果差异较大。
用时:3小时
第七天
重绘
在之前的画图板程序中,当窗口变动时,之前绘制的图案会消失,原因是该类只会向屏幕硬件发送一次性的数据,当缓存刷新后,原来的图案就会被覆盖。
JFrame中只刷新了元件的基础图案,该方法被写在JFrame的public void paint(Graphics g);如果我们想要实时重绘画图板的话,需要重写该函数。
于是自己定义一个新类,继承自JFrame,在paint中调用super并加入自己的代码。
重绘方法:
1.记录每一种基础图案的数据,并在paint中更新
2.记录每一次绘画的操作,并在paint中再次进行该操作
这两种方法都需要将需要保存的信息存入列表中,然后依次取出。我们可以为每一种对象都定义一个列表,也可以将这些对象同时继承自一个父类,只定义父类的列表。再取出时按照某种编码自行转换为需要的类型。
package com.zht0106.ProcessDraw;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import javax.swing.JFrame;
public class MyFrame extends JFrame
{
static int paintMode=0;
ArrayList<Shape> lines=new ArrayList<Shape>();
ArrayList<Color> lineColors=new ArrayList<Color>();
ArrayList<Shape> rects=new ArrayList<Shape>();
ArrayList<Color> rectColors=new ArrayList<Color>();
ArrayList<Shape> ovals=new ArrayList<Shape>();
ArrayList<Color> ovalColors=new ArrayList<Color>();
ArrayList<Shape> shapes=new ArrayList<Shape>();
ArrayList<Short> codes=new ArrayList<Short>();
ArrayList<Color> shapeColors=new ArrayList<Color>();
ArrayList<Method> methods=new ArrayList<Method>();
ArrayList<Short> methodCodes=new ArrayList<Short>();
ArrayList<ArrayList<Color>> methodColors=new ArrayList<ArrayList<Color>>();
public void paint(Graphics g)
{
super.paint(g);
if (paintMode==0)
{
for(int i=0;i<lines.size();++i)
{
g.setColor(lineColors.get(i));
int x1,y1,x2,y2;
x1=((Line) lines.get(i)).x1;
y1=((Line) lines.get(i)).y1;
x2=((Line) lines.get(i)).x2;
y2=((Line) lines.get(i)).y2;
g.drawLine(x1,y1,x2,y2);
}
for(int i=0;i<rects.size();++i)
{
g.setColor(rectColors.get(i));
int x,y,w,h;
x=((Rect) rects.get(i)).x;
y=((Rect) rects.get(i)).y;
w=((Rect) rects.get(i)).w;
h=((Rect) rects.get(i)).h;
g.fillRect(x,y,w,h);
}
for(int i=0;i<ovals.size();++i)
{
g.setColor(ovalColors.get(i));
int x,y,w,h;
x=((Oval) ovals.get(i)).x;
y=((Oval) ovals.get(i)).y;
w=((Oval) ovals.get(i)).w;
h=((Oval) ovals.get(i)).h;
g.fillOval(x,y,w,h);
}
}
else if(paintMode==1)
{
for(int i=0;i<shapes.size();++i)
{
if(codes.get(i)==Line.code)
{
((Line) shapes.get(i)).paint(shapeColo