■ 1. 引言
在上讲中,我们对网络的相关功能进行了解说。截止上讲以前的讲座,我们讲述的都是关于midp的java相关技术的内容,本讲将收尾,介绍nec扩展api。
■ 2. nec扩展
nec扩展api中有如下的类。
| 类 | |
| audioclip | 处理声音数据类。已在第五讲解说。 |
| audiolistener | audio事务监听器。已在第五讲解说。 |
| imageeffector | 颜色变换类。将在本讲解说。 |
| imagemap | 模拟pcg类。因为能轻松的把多种画面分配在格子里,所以能很容易的制作出背景和版面(imagemap)。不在本讲解说。 |
| media | 取得媒体数据类。已在第五讲解说。 |
| nxcanvas | nec扩展canvas,支持多重按键。将在本讲解说。 |
| nxgraphics | nec扩展graphics。描画sprite、imagemap。将在本讲解说。 |
| phonecontrol | 控制震动、逆光类。不在本讲解说。 |
| sprite | sprite类。将在本讲解说。 |
| spriteset | 管理sprite类。将在本讲解说。 |
关于上表的imageeffector、nxcanvas、nxgraphics、sprite、spriteset,我们将按顺序展开介绍。
2.1. 扩展图形类
nxgraphics 类是graphics 的扩展类。下面介绍可以实现的sprite、imagemap的描画以及矩形区域的复制。nxgraphics 类定义了以下方法。
void copyarea(int sx, int sy, int width, int height, int dx, int dy)
把canvas描画的矩形区域复制后描画。利用此功能能够把描画过一次的东西复制下来进行描画,因此当描画相同内容的拷贝时,可以简化步骤。
void drawimagemap(imagemap map, int x, int y)
对将多种画面分配在格子里的imagemap进行描画。
void drawspriteset(spriteset sprites)
描画sprite。后面有sprite的相关介绍。
static nxgraphics getnxgraphics(javax.microedition.lcdui.graphics g)
取得nxgraphics对象。
下面展示的是使用copyarea方法的范例。该范例使用copyarea对移动球的一部分进行复制。
import java.util.timer; import java.util.timertask; import javax.microedition.lcdui.canvas; import javax.microedition.lcdui.graphics; import javax.microedition.lcdui.image; import com.nec.graphics.nxgraphics; /** * copyarea范例动画canvas */ public class copyareamovingballcanvas extends canvas { private int x; //球的x坐标 private image img; private timer timer; private timertask task; /** * 构造函数 */ public timermovingballcanvas() { //读取画面 try{ img = image.createimage("/back.png"); }catch(exception e){ e.printstacktrace(); }
// 设定timer,timertask timer = new timer(); task = new timermovingballtask(this); timer.schedule(task, 100, 100); //从100毫秒后起每100毫秒执行一次任务 } /** * 描画方法 */ protected void paint(graphics g) { //清除画面 g.setcolor(255, 255, 255); //白 g.fillrect(0, 0, getwidth(), getheight()); //查看球 g.setcolor(255, 0, 0); g.drawstring("copyarea test",0,0,graphics.top|graphics.left); g.fillarc(x, 50, 40, 40, 0, 360);
//复制矩形区域 nxgraphics ng = nxgraphics.getnxgraphics(g); ng.copyarea(x,50,20,20,x,100); } /** * 改变球的x坐标 */ public void increment() { x += 3; } /** * timer task * 根据计时器设定的时间表执行run()方法。 */ class timermovingballtask extends timertask { private timermovingballcanvas canvas; /** * 构造函数 * @param canvas */ public timermovingballtask(timermovingballcanvas canvas) { this.canvas = canvas; } /** * 被计时器呼叫时进行的处理 */ public void run() { canvas.increment(); canvas.repaint(); } } }
|
运行结果如下所示。
2.2. sprite
sprite是指具有描画位置与大小的对象。sprite的特征有以下三点。
1.把spriteimage分配、移动到任意位置
2.设定spriteimage中的优先顺序
3.进行spriteimage同类的碰撞判定
比如,在canvas类中,根据描画顺序对画面进行描画,其中重复的部分,需要对描画的处理顺序进行正确的编程,很繁琐。在这种情况下,如果利用sprite优先顺序,就不用担心描画顺序,很方便。而且,sprite的碰撞判定,对于经常发生碰撞判定处理的shooting game等应用程序,非常有效。
为了利用sprite,在nec扩展api中准备了以下两类。
• sprite
• spritemape
sprite类中有以下方法。
| 方法 | 作用 |
| boolean isvisible() | 取得sprite的可视/非可视信息。 |
| void setimage(javax.microedition.lcdui.image image) | 设定sprite使用画面。 |
| void setlocation(int x, int y) | 设定sprite查看位置。 |
| void setvisible(boolean b) | 设定sprite的可视/非可视信息。 |
spritemap 类使用sprite对象,因此能够进行sprite对象的同类碰撞判定和设定sprite对象的描画优先顺序。spritemap中有以下方法。
| 方法 | 作用 |
| int getcollisionflag(int index) | 取得由自变量index指定的sprite碰撞判定flag。 |
| int getcount() | 返回保持的sprite数。 |
| sprite getsprite(int index) | 返回由自变量index指定的索引sprite。 |
| sprite[] getsprites() | 返回sprite排列。 |
| boolean iscollision(int index1, int index2) | 取得由自变量index1和index2指定的sprite碰撞判定结果 |
| void setcollisionall() | 进行全体sprite的相互碰撞判定。 |
| void setcollisionof(int index) | 进行由自变量index指定的sprite碰撞判定。 |
| void setpriority(int index, int prior) | 设定sprite优先顺序。 |
sprite查看利用上述nxgraphics类的方法drawspriteset。利用drawspriteset方法,能够在画面上查看在spriteset注册的sprite。但是,visible被false指定的sprite却不能在画面上查看。
ng.drawspriteset(spriteset); |
下面是sprite中两球发生碰撞的演示程序的source code。
该演示中,使球运动发生碰撞,则相撞的球就会消失。
import javax.microedition.lcdui.display; import javax.microedition.midlet.midlet; import javax.microedition.midlet.midletstatechangeexception; /** * 进行sprite test的演示程序 */ public class spritesample extends midlet {
display display; spritecanvas canvas;
/** * 构造函数 */ public spritesample(){ display = display.getdisplay(this); canvas = new spritecanvas(); }
/** * 打开程序 */ protected void startapp() throws midletstatechangeexception { display.setcurrent(canvas); } protected void pauseapp() { } protected void destroyapp(boolean arg0) throws midletstatechangeexception { }
} import javax.microedition.lcdui.canvas; import javax.microedition.lcdui.graphics; import javax.microedition.lcdui.image; import com.nec.graphics.nxgraphics; import com.nec.graphics.sprite; import com.nec.graphics.spriteset; /** * sprite test用canvas * 球发生碰撞后消失 */ public class spritecanvas extends canvas{
private final string image_path = "/ball.png";
private image img = null; private sprite ball1 = null; private sprite ball2 = null; private int ball2x = 100; private int ball2y = 100; private spriteset spriteset;
/** * 构造函数 */ public spritecanvas(){
//读取画面 try { img = image.createimage(image_path); } catch (exception e) { e.printstacktrace(); }
//sprite的初始化 spriteset = new spriteset(2); ball1 = spriteset.getsprite(0); ball2 = spriteset.getsprite(1);
if(img != null){ //球1的初始化 ball1.setimage(img); ball1.setlocation(0,0); ball1.setvisible(true);
//球2的初始化 ball2.setimage(img); ball2.setlocation(ball2x,ball2y); ball2.setvisible(true); } }
/** * 描画方法 */ protected void paint(graphics g) { //清除画面 g.setcolor(255,255,255); g.fillrect(0,0,getheight(),getwidth());
//取得nec扩展graphics nxgraphics ng = nxgraphics.getnxgraphics(g); ng.drawspriteset(spriteset); }
/** * 按键处理 */ protected void keypressed(int keycode) {
switch(keycode){ case -1:{ ball2y -= 3; break; } case -2:{ ball2y += 3; break; } case -3:{ ball2x -= 3; break; } case -4:{ ball2x += 3; break; } default:{ break; } }
//使球运动 ball2.setlocation(ball2x,ball2y); ball2.setvisible(true);
//进行球的碰撞判定 spriteset.setcollisionall(); if(spriteset.getcollisionflag(1) == integer.parseint("1",2)){ ball1.setvisible(false); }
//再次描画 repaint(); } } |
实际运行上述演示程序的结果如下所示。

使移动。

发生碰撞后画面上部的球消失。
上述演示程序的碰撞判定如下所示。
//进行球的碰撞判定 spriteset.setcollisionall(); if(spriteset.getcollisionflag(1) == integer.parseint("1",2)){ ball1.setvisible(false); }
|
进行碰撞判定时,必须使用setcollisionof和setcollisionall方法。然后,通过iscollision或者getcollisionflag方法取得结果。
getcollisionflag 方法的返回值是int型。第n项的sprite和,由指定的自变量索引指定的sprite发生碰撞,第n项的bit变为1,而不发生碰撞则为0。也就是说,与第三项的sprite发生碰撞时,由二进数返回“100”的值。第五项和第二项的sprite发生碰撞时,由二进数返回“10010”的值。
使用getcollisionflag方法调查与第n项sprite发生的碰撞时,使用以下计算式。spriteset.getcollisionflag(x) % 2的n次方的值 >= 2的(n-1)次方的值
下面是判断与第三项sprite发生碰撞的例子。
if( spriteset.getcollisionflag(2) % 8 >= 4){ system.out.println(“碰撞!!!!!!”); }else{ system.out.println(“不碰撞”); } |
2.3. 颜色变换 利用imageeffector类,能够改变图片的颜色,而被指定的颜色可以进行最多两种颜色的变换。例如,在选择时/非选择时描画已改变颜色的图标图片,或者描画只有颜色不同的肖像画时,使用该颜色变换功很方便。
imageeffector 类中有以下的方法。
static javax.microedition.lcdui.image changecolors(javax.microedition.lcdui.image image, int[][] colormap, int nelems)
使用changecolors 方法进行颜色变换。在image中,指定变换前的画面,在colormap中指定colormap来改变颜色。在nelems中指定进行变换的颜色的数量。
例如,把某画面图片image的蓝色变为红色时,如下所示书写。
int[][] colormap= {{ 0,0,255}, {255,0,0}}; imageeffector.changecolors(image, colormap, 1); |
颜色变换用的colormap是二次元排列,rgb三要素的值按以下所示进行指定。
1色调的色替换设定
colormap[0][0] = 变换对象rgb色1的r??;
colormap[0][1] = 变换对象rgb色1的g值;
colormap[0][2] = 变换对象rgb色1的b值;
colormap[1][0] = 变换结果rgb色1的r值;
colormap[1][1] = 变换结果rgb色1的g值;
colormap[1][2] = 变换结果rgb色1的b值;
2色调的色替换设定
colormap[2][0] = 变换对象rgb色2的r??;
colormap[2][1] = 变换对象rgb色2的g值;
colormap[2][2] = 变换对象rgb色2的b值;
colormap[3][0] = 变换结果rgb色2的r值;
colormap[3][1] = 变换结果rgb色2的g值;
colormap[3][2] = 变换结果rgb色2的b值;
下面展示利用imageeffector的演示程序。该程序把画面上球的颜色变换后的结果在画面下表示出来。
import javax.microedition.lcdui.display; import javax.microedition.midlet.midlet; import javax.microedition.midlet.midletstatechangeexception; /** * 进行sprite test的演示程序 */ public class imageeffectorsample extends midlet {
display display; imageeffectorcanvas canvas;
/** * 构造函数 */ public imageeffectorsample(){ display = display.getdisplay(this); canvas = new imageeffectorcanvas(); }
/** * 程序的打开方法 */ protected void startapp() throws midletstatechangeexception { display.setcurrent(canvas); } protected void pauseapp() { } protected void destroyapp(boolean arg0) throws midletstatechangeexception { } }
import javax.microedition.lcdui.canvas; import javax.microedition.lcdui.graphics; import javax.microedition.lcdui.image; import com.nec.graphics.imageeffector; import com.nec.graphics.imagemap; import com.nec.graphics.nxgraphics; import com.nec.graphics.sprite; import com.nec.graphics.spriteset; /** * 颜色变换test用canvas */ public class imageeffectorcanvas extends canvas{
private final string image_path = "/ball.png";
private image img = null; private sprite ball1 = null; private sprite ball2 = null; private spriteset spriteset; private imagemap im;
/** * 构造函数 */ public imageeffectorcanvas(){
//读取画面 try { img = image.createimage(image_path); } catch (exception e) { e.printstacktrace(); } //sprite的初始化 spriteset = new spriteset(2); ball1 = spriteset.getsprite(0); ball2 = spriteset.getsprite(1);
if(img != null){ //球1的初始化 ball1.setimage(img); ball1.setlocation(0,0); ball1.setvisible(true);
//进行画面转换 int colormap[][] = {{0,0,0}, {0,0,255}, {255,255,255}, {0,0,0}}; image img2 =imageeffector.changecolors(img,colormap,4); ball2.setimage(img2); ball2.setlocation(100,100); ball2.setvisible(true); } }
/** * 描画方法 */ protected void paint(graphics g) {
//取得nec扩展graphics nxgraphics ng = nxgraphics.getnxgraphics(g); ng.drawspriteset(spriteset); } }
|
运行上述演示程序后的结果如下所示。

2.4. 多重按键
利用nec扩展canvas的nxcanvas类,能够判断同时按下两个按键。利用该多重按键功能,例如,人物在画面上活动时,可以实现斜向移动。(例如,按右键+下键,向右下移动等)。nxcanvas 类中有以下方法。
int getpressedkeys()
我们可以利用getpressedkeys 方法判断被按的按键。按键信息32bit被分为8bit单位,其中包括由canvas类定义的key_num1等键座信息。
也就是说,我们同时按“0”和“1”时,
例) 【0】按键(keycode=48)和【1】按键(keycode=49)同时被按时
00000000 00000000 00110000 00110001
|----未使用 经常0----| 【0】 【1】
getpressedkeys()的返回值变为12337
由于两个按键被特别指定,值必须被分成8bit单位,如下所示,所以可以取得键座的信息。
int key1 = getpressedkeys() % 256; int key2 = (getpressedkeys() ?c key1) / 256 |
下面展示演示程序。在该程序中如果同时按按键,画面下的球的颜色将产生变化。
import javax.microedition.lcdui.display; import javax.microedition.midlet.midlet; import javax.microedition.midlet.midletstatechangeexception; /** * 进行多重按键test的演示程序 */ public class multiplkeysample extends midlet {
display display; multiplkeycanvas canvas;
/** * 构造函数 */ public multiplkeysample(){ display = display.getdisplay(this); canvas = new multiplkeycanvas(); }
protected void startapp() throws midletstatechangeexception { display.setcurrent(canvas); } protected void pauseapp() { } protected void destroyapp(boolean arg0) throws midletstatechangeexception { }
} import javax.microedition.lcdui.graphics; import javax.microedition.lcdui.image; import com.nec.graphics.imageeffector; import com.nec.graphics.nxcanvas; import com.nec.graphics.nxgraphics; import com.nec.graphics.sprite; import com.nec.graphics.spriteset; /** * 多重按键用canvas */ public class multiplkeycanvas extends nxcanvas{
private final string image_path = "/ball.png";
private image img = null; private sprite ball1 = null; private sprite ball2 = null; private spriteset spriteset;
/** * 构造函数 */ public multiplkeycanvas(){
//读取画面 try { img = image.createimage(image_path); } catch (exception e) { e.printstacktrace(); }
spriteset = new spriteset(2); ball1 = spriteset.getsprite(0); ball2 = spriteset.getsprite(1);
if(img != null){
ball1.setimage(img); ball1.setlocation(0,0); ball1.setvisible(true);
ball2.setimage(img); ball2.setlocation(100,100); ball2.setvisible(true); } }
/** * 进行img2的颜色变换 */ public void changecolor(){ //进行画面转换 int colormap[][] = {{0,0,0}, {0,0,255}, {255,255,255}, {0,0,0}}; image img2 =imageeffector.changecolors(img,colormap,4); ball2.setimage(img2); }
/** * 描画方法 */ protected void paint(graphics g) {
//取得nec扩展graphics nxgraphics ng = nxgraphics.getnxgraphics(g);
//描画sprite ng.drawspriteset(spriteset); }
/** * 按键处理 */ protected void keypressed(int keycode) {
if(getpressedkeys() > 255){//如果同时按两个按键 changecolor(); }
repaint(); }
}
|
运行结果如下所示。
3. 制作应用程序
下面介绍如何利用上面解说的扩展api制作应用程序。本讲我们利用sprite来对“泡泡龙”游戏进行改写。同时,通过判断按键是否被同时按下也可以调节小棒的速度。
这里为使source code简单,将与声音相关的功能、使用网络的高分处理省略掉。source code如下所示。
block_src.zip
这里添加的方法有下面两个。
• 对球、小棒、彩球进行sprite化。
• 同时按方向按键和确定按键,改变小棒的速度。
3.1. sprite化
球、小棒、彩球都由sprite表现并进行碰撞判定。因为由sprite来进行碰撞判定,所以就不用单独进行碰撞判定处理的书写了。
3.1.1. 变量的定义
为了进行sprite处理,首先定义例子变数。这里按以下所示进行定义。
//sprite spriteset spriteset = new spriteset(30); sprite ball = spriteset.getsprite(0); /* 在排列的第一位设定球的sprite */ sprite bar = spriteset.getsprite(1); /* 在排列的第二位设定小棒的sprite */ |
spriteset 的分配如下所示。
[0] 球
[1] 小棒
[2]~[29] 彩球
按照上述变量的定义,则sprite的数为30。球1,小棒1,彩球28,合计30。以前程序的彩球数是35,但因为spriteset规定最多不超过32,所以彩球的数量减到了28。
改变常量blocj_v,减少彩球纵向的个数。
private final int block_v = 4; //彩球纵向的个数 |
3.1.2. sprite的初始化
接下来进行sprite的初始化。设定实际的球、小棒、彩球图片和查看坐标。
为进行初始化准备了initilizesprite方法。
/** * 进行sprite的初始化 */ public void initilisespriteset() { //进行球的初始化 ballx = barx; bally = barx - ball_height; ball.setlocation(ballx, bally); ball.setimage(ballimg); ball.setvisible(true); //进行小棒的初始化 bar.setlocation(barx, bary); bar.setimage(barimg); bar.setvisible(true); //进行彩球的初始化 blockcount = block_h * block_v; sprite block = null; int index = 2; for (int i = 0; i < block_h; i++) { for (int j = 0; j < block_v; j++) { block = spriteset.getsprite(index++);/* 从spriteset 中取得sprite */ block.setimage(blockimg); /* 设定画面为sprite */ block.setlocation(i * block_width, (j + 1) * block_height);/* 设定查看坐标*/ block.setvisible(true); /* 设定彩球被显示*/ } } } |
3.1.3. 查看sprite
在画面上查看sprite。利用上述nxgraphics类进行sprite的查看。在blockcanvas类的paint方法里记述着以下内容。
//描画sprite nxgraphics ng = nxgraphics.getnxgraphics(g); ng.drawspriteset(spriteset); |
在上述情况下,以前必需的球、小棒、彩球的查看不需要在paint方法里讲述了。下面介绍paint方法。
/** * 描画方法 */ protected void paint(graphics g) { //清除画面 g.setcolor(255, 255, 255); g.fillrect(0, 0, getwidth(), getheight()); if (state == active) { //游戏进行中 nxgraphics ng = nxgraphics.getnxgraphics(g); ng.drawspriteset(spriteset); } else if (state == clear) { //清除 g.setcolor(0, 0, 0); g.drawstring( "game clear!!!!", getwidth() / 2, getheight() / 2, graphics.hcenter | graphics.baseline); } else if (state == game_over) { //游戏结束 g.setcolor(0, 0, 0); g.drawstring( "game over....", getwidth() / 2, getheight() / 2, graphics.hcenter | graphics.baseline); } } |
3.1.4. 球、小棒的移动和碰撞判定
接着进行球、小棒的移动和碰撞判定。到目前为止,球、小棒的移动是各自利用moveball与movebar方法的,在这里也使用原方法,并对其进行改良。
在使球移动的moveball方法里,添加sprite同类的碰撞判定处理和球坐标反映处理。
首先从碰撞判定的处理开始讲述。与球壁的碰撞还沿用原来的方法,与小棒的碰撞判定采用以下处理方法。
//进行反弹判定 spriteset.setcollisionall(); //碰上小棒后反弹 if (spriteset.getcollisionflag(1) == 1) { ballmovey *= -1; bally = bary - ball_height-5; } |
因为spriteset的索引是“1”,所以小棒利用getcollisionflag(1)进行碰撞判定。若getcollisionflag的返回值是“1”,那么球与小棒就发生了碰撞。相撞时,球被弹起来,球y轴方向的速度被逆转。另外,为了防止小棒和球相碰,要改变球的y坐标。
与彩球的碰撞判定如下所示。
//碰上彩球后反弹 for (int i = 2; i < 30; i++) { if (spriteset.getcollisionflag(i) % 2 == 1) { spriteset.getsprite(i).setlocation(-100, -100); spriteset.getsprite(i).setvisible(false); blockcount--; ballmovey *= -1; //游戏清除检查 if (blockcount == 0) { state = clear; } } } |
彩球的sprite判断是否与球发生了碰撞。若发生了碰撞,彩球被setvisible(false)设为不可视,且发生碰撞的彩球坐标向相反的区域移动。否则,sprite将继续保持“与球碰撞”状态。通过移动sprite,清除碰撞状态。因此,发生碰撞彩球的sprite的坐标即使在画面内移动,若不可视也没有问题,但这里我们为了讲解明白,使之向相反区域的画面外移动。
球坐标反映处理使用moveball方法。如下所示。
/** * 使球运动 */ public void moveball() { ballx += ballmovex; bally += ballmovey; //反弹 //碰壁后反弹 if (ballx < 0) { ballmovex *= -1; ballx = 0; } else if (getwidth() < ballx + ball_height) { ballx = getwidth() - ball_height; ballmovex *= -1; } if (bally < 0) { ballmovey *= -1; bally = 0; } else if (bally > getheight()) { //若球落下 //游戏结束 state = game_over; } //判定反弹 spriteset.setcollisionall(); //碰上小棒后反弹 if (spriteset.getcollisionflag(1) == 1) { ballmovey *= -1; bally = bary - ball_height-5;//与小棒之间留出空间(否则就与小棒相撞了) } //碰上彩球后反弹 for (int i = 2; i < 30; i++) { if (spriteset.getcollisionflag(i) % 2 == 1) { spriteset.getsprite(i).setlocation(-100, -100); spriteset.getsprite(i).setvisible(false); blockcount--; ballmovey *= -1; //游戏清除检查 if (blockcount == 0) { state = clear; } } } //反映球移动 ball.setlocation(ballx, bally); ball.setvisible(true); } |
如上所述完成球的移动。
使小棒移动的movebar方法中,给sprite添加坐标反映处理。下面添加增加处理的movebar方法。
/** * 移动小棒 */ public void movebar() { barx += barmovex; if (barx < 0) { barx = 0; } else if (barx + bar_width > getwidth()) { barx = getwidth() - bar_width; } //反映小棒移动 bar.setlocation(barx, bary); bar.setvisible(true); } |
3.2. 小棒速度的变化
按确定按键和方向按键,设定为增加小棒的速度。给keypressed方法增加判断处理,来判断同时按下。
增加后的方法如下所示。
/** * 按下按键时 */ protected void keypressed(int key) { if (state == active) { if (getgameaction(key) == canvas.right) { barmovex = 6; } else if (getgameaction(key) == canvas.left) { barmovex = -6; } //按键的同时按下 int multiplkey = getpressedkeys(); if (multiplkey > 255) {
if (multiplkey == 64508) { barmovex = 12; } else if (multiplkey == 65019) { barmovex = -12; } } repaint(); } else { //再次起动 this.initilisespriteset(); this.start(); } } |
小棒速度变化时,使其颜色也改变。这里使小棒的颜色从红变黄。颜色变换有准备了方法。
/** * 进行小棒的颜色变换。 */ public void changebarcolor() { int[][] colormap = { { 255, 0, 0 }, {255, 254, 0 },}; bar.setimage(imageeffector.changecolors(barimg, colormap, 2)); bar.setvisible(true); } |
上述方法在keypressed方法里讲述。另外,释放按键之后,要想返回原来的图片,如下所述书写keyrelased方法。
/** * 释放按键时 */ protected void keyreleased(int key) { barmovex = 0; //返回小棒的图片 bar.setimage(barimg); bar.setvisible(true); } |
3.3. 完成
介绍就到这里结束了。
下面是本次所制作应用程序的source code。
block_sprite.zip
下面是实际运行的结果。
4. 总结
本回解说的sprite,对于graphics来说是非常重要的思维方法,请一定复习并加以理解。
共计八讲的java讲座,本讲全部解说完毕。感谢您的关注!