抽象与多态
抽象与多态
1 抽象abstract
1.1 抽象类
使用抽象关键字abstract声明的类是抽象类,抽象类不能直接实例化创建对象。
案例:
package demo01;
/*
*Person类的作用是为子类提供代码复用
*/
public class Person{
String name;
int age;
public void whoru(){
System.out.println("我是"+name);
}
}
package demo01;
public class Student extends Person{
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void study(){
System.out.println("学习");
}
}
package demo01;
public class Teacher extends Person{
public Teacher(String name,int age){
this.name=name;
this.age=age;
}
public void teach(){
System.out.println("讲课");
}
}
package demo01;
public class Worker extends Person{
public Worker(String name,int age){
this.name=name;
this.age=age;
}
public void work(){
System.out.println("工作");
}
}
测试案例:
package demo01;
public class Demo01{
public static void main(String[] args){
Student s=new Student("Tom",12);
Teacher t=new Teacher("Andy",28);
Worker w=new Worker("Jerry",28);
s.whoru();
s.study();
t.whoru();
t.teach();
w.whoru();
w.work();
//问题:如果能够直接创建Person对象,其方法运算结果不理想
Person p=new Person();
p.whoru();
//运行结果:
//我是Tom 学习
//我是Andy 讲课
//我是Jerry 工作
//我是null
}
}
面向对象设计时候根据子类泛化得到的半成品父类,应该定义为抽象类。
如何使用抽象类:
- 在类名前面添加abstract关键字以后就是抽象类了
- 抽象类可以作为父类被子类继承,可以定义变量
- 抽象类不能直接创建对象
案例:
package demo02;
/*
*Person类的作用是为子类提供代码复用
*设计为抽象类,只能被继承,不能创建对象
*/
public abstract class Person{
String name;
int age;
public void whoru(){
Systrm.out.println("我是"+name);
}
}
package demo02;
public class Demo01{
public static void main(String[] args){
Student s=new Student("Tom",12);
Teacher t=new Teacher("Andy",28);
Worker w=new Worker("Jerry",28);
s.whoru();
s.study();
t.whoru();
t.teach();
w.whoru();
w.work();
//问题:如果能够直接创建Person对象,其方法运算结果不理想
//Java编译器检查,不允许创建抽象类型的对象
//Person p=new Person();
//p.whoru();
}
}
1,2 抽象方法
使用abstract关键字声明,不包含方法体的方法称为抽象方法。
抽象使用规则:每个子类都有,但是每个子类实现都不同的方法泛化为抽象方法!
语法:
-
使用abstract声明方法,不能有方法体
-
包含抽象方法的类必须声明为抽象类,因为包含抽象方法的类一定是不完整的半成品类
-
子类继承抽象类时必须重写(实现)抽象方法,否则出现编译错误
a.可以将抽象方法看作父类对子类的行为约定,必须被子类重写实现
案例:
package demo03;
public class Teacher extends Person{
public Teacher(String name,int age){
this.name=name;
this.age=age;
}
public void teach(){
System.out.println("讲课");
}
//日程计划
public void schedule(){
System.out.println("吃饭、讲课");
}
}
package demo03;
public class Student extends Person{
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void study(){
System.out.println("学习");
}
//日程计划
public void schedule(){
System.out.println("吃饭、听课");
}
}
package demo03;
public class Worker extends Person{
public Worker(String name,int age){
this.name=name;
this.age=age;
}
public void work(){
System.out.println("学习");
}
//日程计划
public void schedule(){
System.out.println("吃饭、开车");
}
}
package demo02;
/*
*Person类的作用是为子类提供代码复用
*设计为抽象类,只能被继承,不能创建对象
*/
public abstract class Person{
String name;
int age;
public void whoru(){
Systrm.out.println("我是"+name);
}
//日程计划
public abstract void schedule();
}
测试案例:
public class demo02{
public static void main(String[] args){
Student s=new Student("Tom",12);
Teacher t=new Teacher("Andy",28);
Worker w=new Worker("Jerry",28);
s.schedule();
t.schedule();
w.schedule();
Person p=new Teacher("Wang",22);//person引用也可以
p.schedule();
}
}
1.3 使用抽象类重构飞机大战
案例:
package demo04;
import java,awt.Graphics;
import javax.swing.ImageIcon;
/*
* 父类中定义从子类抽取的属性和方法
* 这种抽取方式称为“泛化”
*/
public abstract class FlyingObject {
protected double x;
protected double y;
protected double width;
protected double height;
protected double step;
protected ImageIcon image;
//public FlyingObject(double x, double y, double width, double height) {
//this.x = x;
//this.y = y;
//this.width = width;
//this.height = height;
// }
public abstract void move();
public void paint(Graphics g){
image.paintIcon(null,g,(int)x, (int)y);
}
@Override
public String toString() {
String className=getClass().getName();
return className+" [x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + "]";
}
}
package demo04;
public abstract class Plane extends FlyingObject{
public void move();
y+=step;
}
package demo04;
public class Airplane extends Plane{
public Airplane(double x, double y, double width, double height, double step) {
//利用super()调用父类有参数构造器,复用了父类中构造器算法
//super(x,y,width,height);
this.x=x;
this.y=y;
this.step = step;
image=Images.airplane[0];
width=image.getIconWidth();
height=image.getIconHeight();
}
}
package demo04;
public class Bigplane extends Plane{
public Bigplane(double x, double y, double width, double height, double step) {
//利用super()调用父类有参数构造器,复用了父类中构造器算法
//super(x,y,width,height);
this.x=x;
this.y=y;
this.step = step;
this.image=Images.bigplane[0];
width=image.getIconWidth();
height=image.getIconHeight();
}
}
package demo04;
public class Bee extends Plane{
public Bee(double x, double y, double width, double height, double step){
//super(x,y,width,height);
this.x=x;
this.y=y;
this.step=step;
this.image=Images.bee[0];
width=image.getIconWidth();
height=image.getIconHeight();
}
/**
*重写父类型move方法修改为斜向飞行
*/
public void move(){
//调用父类型方法,复用父类型定义的算法
super.move();//向下飞行 x++;
}
}
package demo04;
import java.awt.Graphics;
import javax.swing.ImageIcon;
public class Sky extends FlyingObject{
protected double yo;
public Sky(double x, double y, double width, double height, double step) {
//super(x,y,width,height);
step =0.8;
image=Images.sky;
x=0;
y=0;
yo=-image.getIconHeight();//照片的高度
height=image.getIconHeight(); //天空的高度(照片)
width=image.getIconWidth();//天空的宽度(照片)
//System.out.println("y="+y+" y0="+yo+" width="+width+" height="+height);
//}
public void move() {
y+=step;
yo+=step;//(两个坐标都在移动)
if(y>=height) {
//System.out.println("第一个照片返回:y="+y);
y=-height;
//System.out.println("y="+y+" y0="+yo+" width="+width+" height="+height);
}
if(yo>=height) {
//System.out.println("第二个照片返回:y0="+yo);
yo=-height;
//System.out.println("y="+y+" y0="+yo+" width="+width+" height="+height);
}
}
public void paint(Graphics g) {//改写父类中的方法
image.paintIcon(null, g, (int)x, (int)y);
image.paintIcon(null, g, (int)x, (int)yo);//对天空做修改,对两张照片进行处理
}
}
package demo04;
public class Bullet extends FlyingObject{
public Bullet(double x, double y, double width, double height, double step) {
//利用super()调用父类有参数构造器,复用了父类中构造器算法
//super(x,y,width,height);
this.x=x;
this.y=y;
this.step = step;
image=Images.bullet;
width=image.getIconWidth();
height=image.getIconHeight();
}
/**
*重写继承与超类的move方法,作用就是修改了超类move行为
*超类是向下移动,修改为向上移动
*/
public void move(){
y-=step;
}
}
package demo04;
public class Hero extends FlyingObject{
public Hero(double x, double y, double height, double width) {
//super(x,y,width,height);
this.x=x;
this.y=y;
this.image=Images.hero[0];
width=image.getIconWidth();
height=image.getIconHeight();
}
/*
* 重写move方法,空方法,目的是不动
* 修改超类中规定的向下飞,改成不动
*/
public void move() {
}
/*
*将鼠标机移动到鼠标位置X,Y
*@param x鼠标位置x
*@param y鼠标位置y
*/
public void move(int x, int y) {
this.x=x;
this.y=y;
}
}
package demo04;
import java.awt.Graphics;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class World extends JPanel{
/*
* 添加飞机大战世界中的物体
*/
private Airplane[] airplanes;
private Bigplane[] bigplanes;
private Bullet[]bullets;
private Sky sky;
private Hero hero;
/*
* 利用构造器初始化世界中每个物体
*/
public World(){
airplanes=new Airplane[2];//创建两个元素的数组
airplanes[0]=new Airplane(10,10,1.5);//宽高去掉了50,40
airplanes[1]=new Airplane(10,100,1.5);
//x,y 宽 高 速度
bigplanes=new Bigplane[2];
bigplanes[0]=new Bigplane(100,20,2);//宽高去掉了100,200
bigplanes[1]=new Bigplane(100,220,2);
bullets =new Bullet[6];
bullets[0]=new Bullet(200,400,4);//宽高去掉了10,10
bullets[1]=new Bullet(200,350,4);
bullets[2]=new Bullet(200,300,4);
bullets[3]=new Bullet(200,250,4);
bullets[4]=new Bullet(200,200,4);
bullets[5]=new Bullet(200,150,4);
sky=new Sky();
hero=new Hero(200,500);
}
public void paint(Graphics g) {
sky.paint(g);
hero.paint(g);
for(int i=0; i<bullets.length; i++) {
//i=0 1 2 3 4 5
bullets[i].paint(g);
}
//调用每个飞机的多态方法,实现多态的绘制
for(int i=0; i<planes.length; i++) {
airplanes[i].paint(g);
}
for(int i=0; i<planes.length; i++) {
bigplanes[i].paint(g);
}
}
public static void main(String[] args) {
JFrame frame=new JFrame();
World world=new World();
frame.add(world);
frame.setSize(400,700);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
//调用action方法启动定时器
world.action();
}
/*
* 添加内部类,实现定时计划任务
* 为何使用内部类实现定时任务
* 1,隐藏定时任务到world类中
* 2,可以访问外部类中的数据,飞机,子弹等
*/
private class PaintTask extends TimerTask{
public void run(){
//执行飞机移动方法;是多态的移动方法,每个飞机都不同
for(int i=0; i<airplanes.length; i++){
airplanes[i].move();
}
for(int i=0; i<bigplanes.length; i++){
bigplanes[i].move();
}
for(int i=0; i<bullets.length; i++){
bullets[i].move();
}
sky.move();
repaint(); //调用重写绘制方法,这个方法会自动执行paint
}
}
public void action(){//启动方法
Timer timer=new Timer();
PaintTask task=new PaintTask();//定时器任务
timer.schedule(task,1000,1000/100);//规定计划每间隔多少时间执行
}
}
2 多态
2.1 什么是多态
多态是面向对象三大基本特征之一。
- 个体多态:父类型定义的变量引用的子类型个体是多种多样的,个体多态是用向上造型实现的
- 行为多态:父类型变量引用子类型实例后,执行方法时候可以得到多种结果,行为多态是利用方法重写实现的
使用多态编程可以使不同类型个体进行统一管理,可以实现不同行为的功能进行统一处理。
2.2 飞行物与多态
开发步骤:
- 重构World类,使用一个FlyingObject数组存储各种飞机
- 重构定时器,执行每个飞行物体的move
- 重构绘制代,执行每个飞行物的paint方法
代码:
package demo05;
import java.awt.Graphics;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class World extends JPanel{
/*
* 添加飞机大战世界中的物体
*/
private FlyingObject[]Planes;//所有的可以被打掉的敌机
private Bullet[]bullets;
private Sky sky;
private Hero hero;
/*
* 利用构造器初始化世界中每个物体
*/
public World(){
//多态数组,数组中可以存储多个类型对象
//好处:一个数组统一管理各种对象
planes=new FlyingObject[6];//创建数组对象
planes[0]=new Airplane(10,10,1.5);
planes[1]=new Airplane(10,100,1.5);
planes[2]=new Bigplane(100,20,2);
planes[3]=new Bigplane(100,220,2);
planes[4]=new Bee(200,200,1.5);
planes[5]=new Bee(200,280,1.5);
bullets =new Bullet[6];
bullets[0]=new Bullet(200,400,4);//宽高去掉了10,10
bullets[1]=new Bullet(200,350,4);
bullets[2]=new Bullet(200,300,4);
bullets[3]=new Bullet(200,250,4);
bullets[4]=new Bullet(200,200,4);
bullets[5]=new Bullet(200,150,4);
sky=new Sky();
hero=new Hero(200,500);
}
public void paint(Graphics g) {
sky.paint(g);
hero.paint(g);
for(int i=0; i<bullets.length; i++) {
//i=0 1 2 3 4 5
bullets[i].paint(g);
}
//调用每个飞机的多态方法,实现多态的绘制
for(int i=0; i<planes.length; i++) {
planes[i].paint(g);
}
}
public static void main(String[] args) {
JFrame frame=new JFrame();
World world=new World();
frame.add(world);
frame.setSize(400,700);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
//调用action方法启动定时器
world.action();
}
/*
* 添加内部类,实现定时计划任务
* 为何使用内部类实现定时任务
* 1.隐藏定时任务到world类中
* 2.可以访问外部类中的数据,飞机,子弹等
*/
private class PaintTask extends TimerTask{
public void run(){//执行飞机移动方法;是多态的移动方法,每个飞机都不同
for(int i=0; i<planes.length; i++){
planes[i].move();
}
for(int i=0; i<bullets.length; i++){
bullets[i].move();
}
sky.move();
repaint(); //调用重写绘制方法,这个方法会自动执行paint
}
}
public void action(){//启动方法
Timer timer=new Timer();
PaintTask task=new PaintTask();//定时器任务
timer.schedule(task,1000,1000/100);//规定计划每间隔多少时间执行
}
}
3 播放动画
3.1 动画原理
动画原理是将连续动画帧按照一定时间间隔播放就能实现动画。
3.2 实现播放动画
实现步骤:
- 在FlyingObject定义图片数组存储图片,一个存储动画,一个存储爆炸动画
- 在构造器中初始图片数组
- 在FlyingObject中增加index变量,作为计数索引
- 添加nextimage方法,实现切换动画帧功能
- 编写案例进行单元测试
案例:父类FlyingObject中声明动画帧图片数组和图片序号index,以及nextimage方法计算下一张图片:
package demo06;
import java,awt.Graphics;
import javax.swing.ImageIcon;
/*
* 父类中定义从子类抽取的属性和方法
* 这种抽取方式称为“泛化”
*/
public abstract class FlyingObject {
protected double x;
protected double y;
protected double width;
protected double height;
protected double step;
protected ImageIcon image;
//当前对象动画帧,如果没有:如子弹、天空,则此属性保持null
protected ImageIcon[] images;
//爆炸效果动画帧,如果没有保持null
protected ImageIcon[] bom;
//动画帧播放计数器,%数组长度得到播放动画帧的位置
protected int index=0;
public abstract void move();
//动画帧播放方法
public void nextImage(){
//没有动画帧时候,不播放动画帧图片
if(images==null){
return;
}
//System.out.println(index +","+(index % images.length));//打桩
image=images[index++/30 % images.length];//除以30等于调慢30倍
}
public void paint(Graphics g){
nextImage();//换动画帧,然后再绘制
image.paintIcon(null,g,(int)x, (int)y);
}
@Override
public String toString() {
String className=getClass().getName();
return className+" [x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + "]";
}
}
子弹和天空没有动画帧,无需初始化动画帧数组。
package demo06;
public class Airplane extends Plane{
public Airplane(double x, double y, double width, double height, double step) {
//利用super()调用父类有参数构造器,复用了父类中构造器算法
//super(x,y,width,height);
this.x=x;
this.y=y;
this.step = step;
image=Images.airplane[0];
width=image.getIconWidth();
height=image.getIconHeight();
bom=Images.bom;
}
}
package demo06;
public class Bee extends Plane{
public Bee(double x, double y, double width, double height, double step){
//super(x,y,width,height);
this.x=x;
this.y=y;
this.step=step;
this.image=Images.bee[0];
width=image.getIconWidth();
height=image.getIconHeight();
bom=Images.bom;
}
/**
*重写父类型move方法修改为斜向飞行
*/
public void move(){
//调用父类型方法,复用父类型定义的算法
super.move();//向下飞行 x++;
}
}
package demo06;
public class Hero extends FlyingObject{
public Hero(double x, double y, double height, double width) {
//super(x,y,width,height);
this.x=x;
this.y=y;
this.image=Images.hero[0];
width=image.getIconWidth();
height=image.getIconHeight();
images=Images.hero;
bom=Images.bom;
}
/*
* 重写move方法,空方法,目的是不动
* 修改超类中规定的向下飞,改成不动
*/
public void move() {
}
/*
*将鼠标机移动到鼠标位置X,Y
*@param x鼠标位置x
*@param y鼠标位置y
*/
public void move(int x, int y) {
this.x=x;
this.y=y;
}
}
package demo06;
public class Bigplane extends Plane{
public Bigplane(double x, double y, double width, double height, double step) {
//利用super()调用父类有参数构造器,复用了父类中构造器算法
//super(x,y,width,height);
this.x=x;
this.y=y;
this.step = step;
this.image=Images.bigplane[0];
width=image.getIconWidth();
height=image.getIconHeight();
bom=Images.bom;
}
}
编织写测试案例测试:
package demo06;
public class NextImageTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
/*
* 测试动画帧播放算法
*/
Airplane plane=new Airplane(10,10,2);
plane.nextImage();
System.out.println(plane.image);
plane.nextImage();
System.out.println(plane.image);
plane.nextImage();
System.out.println(plane.image);
plane.nextImage();
System.out.println(plane.image);
plane.nextImage();
System.out.println(plane.image);
plane.nextImage();
Bigplane p2=new Bigplane(10,10,5);
p2.nextImage();
System.out.println(p2.image);
p2.nextImage();
System.out.println(p2.image);
p2.nextImage();
System.out.println(p2.image);
p2.nextImage();
System.out.println(p2.image);
p2.nextImage();
System.out.println(p2.image);
p2.nextImage();
System.out.println(p2.image);
Bullet b=new Bullet(10,10);
b.nextImage();
System.out.println(b.image);
b.nextImage();
System.out.println(b.image);
b.nextImage();
System.out.println(b.image);
b.nextImage();
System.out.println(b.image);
b.nextImage();
System.out.println(b.image);
b.nextImage();
}
}
4 敌机入场
4.1 敌机入场位置计算
屏幕上方随机入场
案例:小飞机
package demo06;
import java.util.Random;
public class Airplane extends Plane{
public Airplane(){
Random random=new Random();
image=Images.airplane[0];
width=image.getIconWidth();
height=image.getIconHeight();
x=random.nextInt(400-(int)width);//0~400-w
y=-height;
step=random.nextDouble()*5+1;
//初始化小飞机动画帧
images=Images.airplane;
bom=Images.bom;
}
public Airplane(double x, double y, double width, double height, double step) {
//利用super()调用父类有参数构造器,复用了父类中构造器算法
//super(x,y,width,height);
this.x=x;
this.y=y;
this.step = step;
image=Images.airplane[0];
width=image.getIconWidth();
height=image.getIconHeight();
//初始化小飞机动画帧
images=Images.airplane;
bom=Images.bom;
}
}
小飞机测试案例:
package demo06;
public class AirplaneTest {
public static void main(String[] args) {
/*
* 测试小飞机从屏幕上方出场
*/
Airplane plane=new Airplane();
System.out.println(plane);
System.out.println(plane.image);
System.out.println(plane.images);
System.out.println(plane.bom);
System.out.println(plane.step);
}
}
大飞机:
package demo06;
import java.util.Random;
public class Bigplane extends Plane{
public Bigplane() {
Random random=new Random();
image=Images.bigplane[0];
width=image.getIconWidth();
height=image.getIconHeight();
x=random.nextInt(400-(int)width);
y=-height;
step=random.nextDouble()*3+0.7;
images=Images.bigplane;
bom=Images.bom;
}
public Bigplane(double x, double y, double step) {
//super(x,y,width,height);
this.x=x;
this.y=y;//初始化
this.step = step;
this.image=Images.bigplane[0];
width=image.getIconWidth();
height=image.getIconHeight();
images=Images.bigplane;
bom=Images.bom;
}
大飞机测试案例:
package demo06;
public class BigplaneTest {
public static void main(String[] args) {
/*
* 大飞机出场位置测试
*/
Bigplane plane=new Bigplane();
System.out.println(plane);
System.out.println(plane.step);
System.out.println(plane.image);
System.out.println(plane.images);
System.out.println(plane.bom);
}
}
蜜蜂:
package demo06;
import java.util.Random;
public class Bee extends Plane{
public Bee() {
Random random=new Random();
image=Images.bee[0];
width=image.getIconWidth();
height=image.getIconHeight();
x=random.nextInt(400-(int)width);
y=-height;
step=random.nextDouble()*3+0.7;
images=Images.bee;
bom=Images.bom;
}
public Bee(double x, double y, double step) {
//super(x,y,width,height);
this.x=x;
this.y=y;//初始化
this.step = step;
this.image=Images.bee[0];
width=image.getIconWidth();
height=image.getIconHeight();
images=Images.bee;
bom=Images.bom;
}
/**
*重写父类型move方法修改为斜向飞行
*/
public void move(){
//调用父类型方法,复用父类型定义的算法
super.move();//向下飞行 x++;
}
}
蜜蜂测试案例:
package demo06;
public class BeeTest {
public static void main(String[] args) {
/*
* 蜜蜂出场位置测试
*/
Bee plane=new Bee();
System.out.println(plane);
System.out.println(plane.step);
System.out.println(plane.image);
System.out.println(plane.images);
System.out.println(plane.bom);
}
}
4.2 重构构造器
可将以上构造器算法抽取到他们的父类Plane中,子类利用super复用这个构造器算法,减少冗余提高代码复用。
实现步骤:
-
在FlyingObject中创建两个构造器
- 无参数构造器:被子类默认调用,避免子类继承错误
- 有参数构造器:根据位置初始化飞行物的数据,被全部子类调用
-
在Plane增加三个构造器
- 默认构造器:被子类默认调用,避免子类继承错误
- 有参数构造器1:调用父类根据位置初始化数据
- 有参数构造器2:根据图片计算出从屏幕上方出场的位置
-
测试
案例:父类型定义构造器
package demo07;
import java,awt.Graphics;
import javax.swing.ImageIcon;
/*
* 父类中定义从子类抽取的属性和方法
* 这种抽取方式称为“泛化”
*/
public abstract class FlyingObject {
protected double x;
protected double y;
protected double width;
protected double height;
protected double step;
protected ImageIcon image;
//当前对象动画帧,如果没有:如子弹、天空,则此属性保持null
protected ImageIcon[] images;
//爆炸效果动画帧,如果没有保持null
protected ImageIcon[] bom;
//动画帧播放计数器,%数组长度得到播放动画帧的位置
protected int index=0;
//无参数构造器,减少子类的编译错误
public FlyingObject(){
}
//根据位置初始化x,y,image,images,bom
public FlyingObject(double x, double y,
ImageIcon image, ImageIcon[] Images, ImageIcon[] bom) {
//当前图片 全部动画帧 爆炸图片
this.x=x;
this.y=y;
this.image=image;
this.images=Images;
this.bom=bom;
width=image.getIconWidth();
height=image.getIconHeight();
}
public abstract void move();
//动画帧播放方法
public void nextImage(){
//没有动画帧时候,不播放动画帧图片
if(images==null){
return;
}
//System.out.println(index +","+(index % images.length));//打桩
image=images[index++/30 % images.length];//除以30等于调慢30倍
}
public void paint(Graphics g){
nextImage();//换动画帧,然后再绘制
image.paintIcon(null,g,(int)x, (int)y);
}
@Override
public String toString() {
String className=getClass().getName();
return className+" [x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + "]";
}
}
package demo07;
import java.util.Random;
import javax.swing.ImageIcon;
public abstract class Plane extends FlyingObject{
public Plane() {
}
/*
* 根据位置初始化对象数据
*/
public Plane(double x, double y, ImageIcon image, ImageIcon[] Images, ImageIcon[] bom) {
super(x, y, image, Images, bom);
}
/*
* 利用算法实现飞机从屏幕上方出场
*/
public Plane(ImageIcon image, ImageIcon[] Images, ImageIcon[] bom) {
Random random=new Random();
this.image=image;
width=image.getIconWidth();
height=image.getIconHeight();
x=random.nextInt(400-(int)width);
y=-height;
this.images=Images;
this.bom=bom;
}
public void move() {
y +=step;
}
}
子类调用父类构造器
package demo07;
import java.awt.Graphics;
public class Sky extends FlyingObject{
protected double yo;
public Sky(){
super(0,0,Images.sky,null,null);
step=0.8;
yo=-height;
}
public void move() {
y+=step;
yo+=step;//(两个坐标都在移动)
if(y>=height) {
//System.out.println("第一个照片返回:y="+y);
y=-height;
//System.out.println("y="+y+" y0="+yo+" width="+width+" height="+height);
}
if(yo>=height) {
//System.out.println("第二个照片返回:y0="+yo);
yo=-height;
//System.out.println("y="+y+" y0="+yo+" width="+width+" height="+height);
}
}
public void paint(Graphics g) {//改写父类中的方法
image.paintIcon(null, g, (int)x, (int)y);
image.paintIcon(null, g, (int)x, (int)yo);//对天空做修改,对两张照片进行处理
}
}
package demo07;
public class Bullet extends FlyingObject{
public Bullet(double x, double y) {
super(x,y,Images.bullet,null,null);
this.step=4;
}
/**
*重写继承与超类的move方法,作用就是修改了超类move行为
*超类是向下移动,修改为向上移动
*/
public void move(){
y-=step;
}
}
package demo07;
public class Hero extends FlyingObject{
public Hero(double x, double y){
super(x, y, Images.hero[0], Images.hero, Images.bom);
}
/*
* 重写move方法,空方法,目的是不动
* 修改超类中规定的向下飞,改成不动
*/
public void move() {
}
/*
*将鼠标机移动到鼠标位置X,Y
*@param x鼠标位置x
*@param y鼠标位置y
*/
public void move(int x, int y) {
this.x=x;
this.y=y;
}
}
package demo07;
public class Airplane extends Plane{
//飞机从屏幕上方随机位置出场
public Airplane(){
super(Images.ariplane[0], Images.airplane, Images.bom);
step=Math.random()*4+1.5;
}
//从自定位置出场
public Airplane(double x, double y, double step) {
//利用super()调用父类有参数构造器,复用了父类中构造器算法
super(x, y, Images.airplane[0], Images.airplane, Images.bom);
this.step=step;
}
}
package demo07;
public class Bigplane extends Plane{
//飞机从屏幕上方随机位置出场
public Bigplane(){
super(Images.bigplane[0], Images.bigplane, Images.bom);
step=Math.random()*3+0.5;
}
//从自定位置出场
public Bigplane(double x, double y, double step) {
//利用super()调用父类有参数构造器,复用了父类中构造器算法
super(x, y, Images.bigplane[0], Images.bigplane, Images.bom);
this.step=step;
}
}
package demo07;
public class Bee extends Plane{
public Bee() {
super(Images.bee[0], Images.bee, Images.bom);
step=Math.random()*5+2;
}
public Bee(double x, double y, double step) {
super(x, y, Images.bee[0], Images.bee, Images.bom);
this.step=step;
}
/**
*重写父类型move方法修改为斜向飞行
*/
public void move(){
//调用父类型方法,复用父类型定义的算法
super.move();//向下飞行 x++;
}
}
单元测试案例:
package demo07;
public class Demo01{
/*
* 测试构造器
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Sky sky=new Sky();
System.out.println(sky);
System.out.println(sky.image);
Bullet bullet=new Bullet(10,10);
System.out.println(bullet);
System.out.println(bullet.image);
Hero hero=new Hero(200,200);
System.out.println(hero);
System.out.println(hero.image);
System.out.println(hero.images);
System.out.println(hero.bom);
Airplane airplane=new Airplane();
System.out.println(airplane);
System.out.println(airplane.image);
System.out.println(airplane.images);
System.out.println(airplane.bom);
System.out.println(airplane.step);
Bigplane bigplane=new Bigplane();
System.out.println(bigplane);
System.out.println(bigplane.image);
System.out.println(bigplane.images);
System.out.println(bigplane.bom);
System.out.println(bigplane.step);
Bee bee=new Bee();
System.out.println(bee);
System.out.println(bee.image);
System.out.println(bee.images);
System.out.println(bee.bom);
System.out.println(bee.step);
}
}
整合测试:
package demo07;
import java.awt.Graphics;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class World extends JPanel{
/*
* 添加飞机大战世界中的物体
*/
//private Airplane[]airplanes;
//private Bigplane[]bigplanes;
private FlyingObject[]Planes;//所有的可以被打掉的敌机
private Bullet[]bullets;
private Sky sky;
private Hero hero;
/*
* 利用构造器初始化世界中每个物体
*/
public World(){
//多态数组,数组中可以存储多个类型对象
//好处:一个数组统一管理各种对象
planes=new FlyingObject[6];//创建数组对象
planes[0]=new Airplane(10,10,1.5);
planes[1]=new Airplane(10,100,1.5);
planes[2]=new Bigplane(100,20,2);
planes[3]=new Bigplane(100,220,2);
planes[4]=new Bee(200,200,1.5);
planes[5]=new Bee(200,280,1.5);
planes[6]=new Bee();
planes[7]=new Airplane();
planes[8]=new Airplane();
planes[9]=new Bigplane();
bullets =new Bullet[6];
bullets[0]=new Bullet(200,400,4);//宽高去掉了10,10
bullets[1]=new Bullet(200,350,4);
bullets[2]=new Bullet(200,300,4);
bullets[3]=new Bullet(200,250,4);
bullets[4]=new Bullet(200,200,4);
bullets[5]=new Bullet(200,150,4);
sky=new Sky();
hero=new Hero(200,500);
}
public void paint(Graphics g) {
sky.paint(g);
hero.paint(g);
for(int i=0; i<bullets.length; i++) {
//i=0 1 2 3 4 5
bullets[i].paint(g);
}
//调用每个飞机的多态方法,实现多态的绘制
for(int i=0; i<planes.length; i++) {
planes[i].paint(g);
}
}
public static void main(String[] args) {
JFrame frame=new JFrame();
World world=new World();
frame.add(world);
frame.setSize(400,700);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
//调用action方法启动定时器
world.action();
}
/*
* 添加内部类,实现定时计划任务
* 为何使用内部类实现定时任务
* 1.隐藏定时任务到world类中
* 2.可以访问外部类中的数据,飞机,子弹等
*/
private class PaintTask extends TimerTask{
public void run(){
//执行飞机移动方法;是多态的移动方法,每个飞机都不同
for(int i=0; i<planes.length; i++){
planes[i].move();
}
for(int i=0; i<bullets.length; i++){
bullets[i].move();
}
sky.move();
repaint(); //调用重写绘制方法,这个方法会自动执行paint
}
}
public void action(){//启动方法
Timer timer=new Timer();
PaintTask task=new PaintTask();//定时器任务
timer.schedule(task,1000,1000/100);//规定计划每间隔多少时间执行
}
}
4.3 定时出场
实现方案:
- 在定时器任务中创建飞机对象
- 将飞机数组扩容
- 将飞机对象追加到数组中
Word类中:
private int index=0;//计数器
//index=0 1 2 3 4 5 6 7 8 9 ...
// * * *
//index % 4==0
private class PaintTask extends TimerTask{
public void run(){
index++;
if(index % 16==0){
Airplane plane=new Airplane();
//数组扩容
planes=Arrays.conpyOf(planes, planes.length+1);
//将新飞机添加到新数组最后位置
planes[planes.length-1]=plane;
}
//执行飞机移动方法,是多态的移动方法,每个飞机都不同
for(int i=0; i<planes.length;i++){
planes[i].move();
}
for(int i=0; i<bullets.length;i++){
bullets[i].move();
}
sky.move();
repaint(); //调用重写绘制方法,这个方法会自动执行paint
}
}
4.4 随机出场
实现步骤:
- 生成随机数0~9
- 数字是0~范围创建小飞机
- 数字是7~8范围创建大飞机
- 数字是9创建蜜蜂
- 由于算法复杂,可以抽取封装为方法createPlane()
代码:World类
private int index=0;//计数器
//index=0 1 2 3 4 5 6 7 8 9 ...
// * * *
//index % 4==0
//创建一个飞机,进入场地
public void createPlane(){
if(index % 16==0){
Random random=new Random();
int n=random.nextInt(10);//0~9
Plane palne;
if(n<=6){
plane=new Airplane();
}else if(n<=8){
plane=new Bigplane();
}else{
plane=new Bee();
}
//数组扩容
planes=Arrays.conpyOf(planes, planes.length+1);
//将新飞机添加到新数组最后位置
planes[planes.length-1]=plane;
}
}
/*
* 添加内部类,实现定时计划任务
* 为何使用内部类实现定时任务
* 1.隐藏定时任务到world类中
* 2.可以访问外部类中的数据,飞机,子弹等
*/
private class PaintTask extends TimerTask{
public void run(){
index++;
createPlane();
//执行飞机移动方法,是多态的移动方法,每个飞机都不同
for(int i=0; i<planes.length; i++){
planes[i].move();
}
for(int i=0; i<bullets.length; i++){
bullets[i].move();
}
sky.move();
repaint(); //调用重写绘制方法,这个方法会自动执行paint
}
}
4.7 switch...case语句
多路分支语句。可以根据整数,字符串,枚举类型进行分支。
具体语法:
- Java 5开始switch case支持枚举类型
- Java 7开始switch case支持String类型
- break用于结束switch语句
- byte、short、char可以自动转换为int,可以作为分支条件
- case后只能是常量,不能是表达式
案例:
- 输入成绩是百分制
- 评定等级,90~100 A
- 80~89 B
- 60~79 C
- 59以下 D
package demo09;
import java.util.Scanner;
public class SwichDemo {
public static void main(String[] args) {
/*
* switch case演示
*/
Scanner console=new Scanner(System.in);
System.out.println("输入分数");
int score=console.nextInt();
//100-0整除得到;10 9 8 7 6 5 4 3 2 1 0
switch(score/10) {
case 10:
case 9:
System.out.println("A");
break;
case 8:
System.out.println("B");
break;
case 7:
case 6:
System.out.println("c");
break;
default:
System.out.println("D");
}
}
}
4.8 利用switch...case优化创建飞机算法
案例:
package demo07;
import java.awt.Graphics;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class World extends JPanel{
/*
* 添加飞机大战世界中的物体
*/
//private Airplane[]airplanes;
//private Bigplane[]bigplanes;
private FlyingObject[]Planes;//所有的可以被打掉的敌机
private Bullet[]bullets;
private Sky sky;
private Hero hero;
/*
* 利用构造器初始化世界中每个物体
*/
public World(){
//多态数组,数组中可以存储多个类型对象
//好处:一个数组统一管理各种对象
planes=new FlyingObject[6];//创建数组对象
planes[0]=new Airplane(10,10,1.5);
planes[1]=new Airplane(10,100,1.5);
planes[2]=new Bigplane(100,20,2);
planes[3]=new Bigplane(100,220,2);
planes[4]=new Bee(200,200,1.5);
planes[5]=new Bee(200,280,1.5);
planes[6]=new Bee();
planes[7]=new Airplane();
planes[8]=new Airplane();
planes[9]=new Bigplane();
bullets =new Bullet[6];
bullets[0]=new Bullet(200,400,4);//宽高去掉了10,10
bullets[1]=new Bullet(200,350,4);
bullets[2]=new Bullet(200,300,4);
bullets[3]=new Bullet(200,250,4);
bullets[4]=new Bullet(200,200,4);
bullets[5]=new Bullet(200,150,4);
sky=new Sky();
hero=new Hero(200,500);
}
public void paint(Graphics g) {
sky.paint(g);
hero.paint(g);
for(int i=0; i<bullets.length; i++) {
//i=0 1 2 3 4 5
bullets[i].paint(g);
}
//调用每个飞机的多态方法,实现多态的绘制
for(int i=0; i<planes.length; i++) {
planes[i].paint(g);
}
}
public static void main(String[] args) {
JFrame frame=new JFrame();
World world=new World();
frame.add(world);
frame.setSize(400,700);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
//调用action方法启动定时器
world.action();
}
private int index=0;//计数器
//index=0 1 2 3 4 5 6 7 8 9 ...
// * * *
//index % 4==0
//创建一个飞机,进入场地
public void createPlane(){
if(index % 16==0){
Random random=new Random();
int n=random.nextInt(10);//0~9
Plane palne;
switch(n){
case 8:
case 7:
plane=new Bigplane();
break;
case 9:
plane=new Bee();
break;
default:
plane=new Airplane();
}
//数组扩容
planes=Arrays.conpyOf(planes, planes.length+1);
//将新飞机添加到新数组最后位置
planes[planes.length-1]=plane;
}
}
/*
* 添加内部类,实现定时计划任务
* 为何使用内部类实现定时任务
* 1.隐藏定时任务到world类中
* 2.可以访问外部类中的数据,飞机,子弹等
*/
private class PaintTask extends TimerTask{
public void run(){
index++;
//执行飞机移动方法;是多态的移动方法,每个飞机都不同
for(int i=0; i<planes.length; i++){
planes[i].move();
createPlane();
}
for(int i=0; i<bullets.length; i++){
bullets[i].move();
}
sky.move();
repaint(); //调用重写绘制方法,这个方法会自动执行paint
}
}
public void action(){//启动方法
Timer timer=new Timer();
PaintTask task=new PaintTask();//定时器任务
timer.schedule(task,1000,1000/100);//规定计划每间隔多少时间执行
}
}
每天对着镜子里的自己说一句:今天的你也很棒!