答:内部类提供在一个类中实现同一接口的多次机会。
要知道,在一般类中是不能实现同一个方法两次的。因为接口的实现可以超过一个,但类仅仅能继承一个。
注释:如果这个类有多个内部类的话,其每个内部类的实例都能作为参数传递给调用该父类的方法。在每个内部类中可以分别实现同一个接口方法。
示例1:以内部类执行动画效果:让圆圈从画面左上方移动到右下方
import javax.swing.*;
import java.awt.*;
public class SimpleAnimation {
//在主要的GUI中创建两个实例变量用来代表图形的坐标
int x = 70;
int y = 70;
public static void main(String[] args) {
SimpleAnimation gui = new SimpleAnimation();
gui.go();
}
private void go() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel3 drawPanel = new MyDrawPanel3();
frame.getContentPane().add(drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);
//重点:重复130次
for (int i = 0; i < 130; i++) {
x++;
y++;
drawPanel.repaint();
try {
//加上延迟可以放慢,不然一下就会跑完。
Thread.sleep(50);
} catch (Exception ex) {
}
}
}//关闭go方法
class MyDrawPanel3 extends JPanel {
protected void paintComponent(Graphics g) {
g.setColor(Color.green);
g.fillOval(x, y, 40, 40);
}
}//关闭内部类
}//关闭外部类
效果1:有BUG
这跟我们想的有点出入,原因是我们忘记了要擦掉原来的图形
class MyDrawPanel3 extends JPanel {
protected void paintComponent(Graphics g) {
//01把颜色设定为白色
g.setColor(Color.white);
//02然后填满整个方块区域
g.fillRect(0,0,this.getWidth(),this.getHeight());
g.setColor(Color.green);
g.fillOval(x, y, 40, 40);
}
}
效果2:满足要求
示例2:使用java随机产生的图形来跟着节奏起舞
import javax.sound.midi.*;
import javax.swing.*;
import java.awt.*;
//我们必须先监听ControllerEvent,因此实现了这个接口
public class MusicPlayer {
static JFrame f=new JFrame("我的第一个音乐视频");
static MyDrawPanel ml;
public static void main(String[] args) {
MusicPlayer musicPlayer=new MusicPlayer();
musicPlayer.go();
}//关闭main
public void setUpGui(){
ml=new MyDrawPanel();
f.setContentPane(ml);
f.setBounds(30,30,300,300);
f.setVisible(true);
}//关闭方法
private void go() {
setUpGui();
try {
//创建并打开队列
Sequencer sequencer= MidiSystem.getSequencer();
sequencer.open();
//向sequencer注册事件。注册的方法取用监听者与代表想要监听的事件的int数组,我们只需要127事件
sequencer.addControllerEventListener(ml,new int[]{127});
//创建队列并trace
Sequence seq=new Sequence(Sequence.PPQ,4);
Track track=seq.createTrack();
//创建一堆连续的音符事件
int r=0;
for (int i = 5; i <60 ; i+=4) {
r=(int)((Math.random()*50)+1);
//调用makeEvent()来产生信息和事件,然后把它们加到track上
track.add(makeEvent(144,1,r,100,i));
//插入事件编号为127的自定义controllerEvent(176),它不会做任何事情,只是让我们知道有音符
//被播放,因为它的tick跟NOTE ON是同时进行的
track.add(makeEvent(176,1,127,0,i));
track.add(makeEvent(128,1,r,100,i+2));
}//结束循环
sequencer.setSequence(seq);
sequencer.setTempoInBPM(120);
sequencer.start();
}catch (Exception ex){ex.printStackTrace();}//结束循环
}//关闭
private static MidiEvent makeEvent(int comd, int chan, int one, int two, int tick) {
MidiEvent event=null;
try {
ShortMessage a=new ShortMessage();
a.setMessage(comd,chan,one,two);
event=new MidiEvent(a,tick);
}catch (Exception e){
return event;
}
return event;
}//关闭方法
class MyDrawPanel extends JPanel implements ControllerEventListener{
//获知事件时才会为真
boolean msg=false;
//获知事件时设为真并调用重绘程序
public void controlChange(ShortMessage event){
msg=true;
repaint();
}
public void paintComponent(Graphics g) {
//因为也有其他东西会引发重绘,所以要判断是否为controllerEvent所引发的
if (msg){
Graphics2D g2=(Graphics2D)g;
//产生随机的颜色并画出方块
int r=(int)(Math.random()*250);
int gr=(int)(Math.random()*250);
int b=(int)(Math.random()*250);
g.setColor(new Color(r,gr,b));
int ht=(int)((Math.random()*120)+10);
int width=(int)((Math.random()*120)+10);
int x=(int)((Math.random()*40)+10);
int y=(int)((Math.random()*40)+10);
g.fillRect(x,y,width,ht);
msg=false;
}//if结束
}//关闭方法
}//关闭内部类
}//关闭类