java 12 练习题:抽象类与接口

思考: 构造方法能作为抽象方法吗?

文章目录

    • 实例1:使用抽象类模拟"去商场买衣服"场景
        • 练习1:
        • 练习2:
    • 实例2:通过实现接口 绘制出特殊的平行四边形
    • 实例3: 使用继承输出儿子喜欢做的事

实例1:使用抽象类模拟"去商场买衣服"场景

“去商场买衣服”,这句话描述的是一个抽象的行为∶到底去哪个商场买衣服,是实体店还是网店,买什么样的衣服,是短衫、裙子,还是其他的什么衣服?在"去商场买衣服"这句话中,并没有为"买衣服"这个抽象行为指明一个确定的信息。设计一个商场的抽象类,并在其中定义买东西的抽象方法,具体是什么商场、买什么东西,交给子类去实现即可。代码如下∶

public abstract class Market {public String name; // 商场名称public String goods; // 商品名称public abstract void shop(); // 抽象方法,用来输出信息
}

定义一个TaobaoMarket类,继承自 Market 抽象类,实现其中的shop()抽象方法:

public class TaobaoMarket extends Market {public void shop() {System.out.println(name + "网购" + goods);}
}

定义一个 WallMarket 类,继承自Market 抽象类,实现其中的shop()抽象方法:


public class WallMarket extends Market {public void shop() {System.out.println(name + "实体店购买" + goods);}
}

定义一个 GoShopping类,在该类中分别使用WallMarket类和TaobaoMarket类创建抽象类的对象,并分别给抽象类中的成员变量赋不同的值,调用 shop()方法分别输出结果:

public class GoShopping {public static void main(String[] args) {Market market = new WallMarket(); // 使用派生类对象创建抽象类对象market.name = "沃尔玛";market.goods = "七匹狼西服";market.shop();market = new TaobaoMarket(); // 使用派生类对象创建抽象类对象market.name = "淘宝";market.goods = "韩都衣舍花裙";market.shop();}
}
练习1:

创建 Shape(图形)类,该类中有一个计算面积的方法。圆形和矩形都继承自图形类,输出圆形和矩形的面积。


public class Circle extends Shape {double radius;public Circle(double radius) {this.radius = radius;}@Overridepublic double getArea() {return Math.PI * this.radius * this.radius;}
}public class Rectangle extends Shape {double length;double width;public Rectangle(double length, double width) {this.length = length;this.width = width;}@Overridepublic double getArea() {return this.length * this.width;}
}public abstract class Shape {String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public abstract double getArea();
}public class Test {public static void main(String[] args) {Circle circle = new Circle(1.5);circle.name = "圆形";System.out.println(circle.name + "面积:" + circle.getArea());Rectangle rectangle = new Rectangle(5.5, 2);rectangle.name = "矩形";System.out.println(rectangle.name + "面积:" + rectangle.getArea());}
}
练习2:

创建工厂类,工厂类中有一个抽象的生产方法,创建汽车厂和鞋厂类,重写工厂类中的抽象生产方法,输出汽车厂生产的是汽车,鞋厂生产的是鞋。


public class AutoPlant extends Factory {String productsName;public AutoPlant(String productsName) {this.productsName = productsName;}@Overridepublic String produce() {return this.productsName;}
}public abstract class Factory {String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public abstract String produce();
}public class ShoeFactory extends Factory {String productsName;public ShoeFactory(String productsName) {this.productsName = productsName;}@Overridepublic String produce() {return this.productsName;}
}public class Test {public static void main(String[] args) {AutoPlant autoPlant = new AutoPlant("汽车");autoPlant.setName("汽车厂");System.out.println(autoPlant.getName() + "生产的是" + autoPlant.productsName);ShoeFactory shoeFactory = new ShoeFactory("鞋");shoeFactory.setName("鞋厂");System.out.println(shoeFactory.getName() + "生产的是" + shoeFactory.productsName);}
}

使用抽象类和抽象方法时,需要遵循以下原则

  • 在抽象类中,可以包含抽象方法,也可以不包含抽象方法,但是包含了抽象方法的类必须被定义为抽象类。
  • 抽象类不能直接被实例化,即使抽象类中没有声明抽象方法,也不能被实例化。
  • 抽象类被继承后,子类需要重写抽象类中所有的抽象方法。
  • 如果继承抽象类的子类也被声明为抽象类,则可以不用重写父类中所有的抽象方法。使用抽象类时,可能会出现这样的问题;程序中会有太多冗余的代码,同时父类的局限性很大。例如,上面的例子中,也许某个不需要 shop()方法的子类也必须重写 shop()方法。如果将这个 shop()方法从父类中拿出,放在别的类里,又会出现新间题∶某些类想要实现"买衣服"的场景,意然需要继承两个父类。Java中规定,一个类不能同时继承多个父类,为解决这种问题,接口应运而生。

实例2:通过实现接口 绘制出特殊的平行四边形

特殊的平行四边形有矩形、正方形和菱形。现使用接口的相关知识绘制出特殊的平行四边形。


interface DrawImage { // 定义“画图形”接口public void draw(); // 定义抽象方法“画”
}class Rectangle implements DrawImage { // 矩形类实现了drawTest接口public void draw() { // 矩形类中实现draw()方法System.out.println("画矩形");}
}class Square implements DrawImage { // 正方形类实现了drawTest接口public void draw() { // 正方形类中实现draw()方法System.out.println("画正方形");}
}class Diamond implements DrawImage { // 菱形类实现了drawTest接口public void draw() { // 菱形类中实现draw()方法System.out.println("画菱形");}
}public class SpecialParallelogram { // 定义特殊的平行四边形类public static void main(String[] args) {// 接口也可以进行向上转型操作DrawImage[] images = { new Rectangle(), new Square(), new Diamond() };// 遍历“画图形”接口类型的数组for (int i = 0; i < images.length; i++) {images[i].draw(); // 调用draw()方法}}
}

提醒: 由于接口中的方法都是抽象方法,所以当子类实现接口时,必须实现接口中的所有抽象方法。

实例3: 使用继承输出儿子喜欢做的事

爸爸喜欢做的事有抽烟和钓鱼,妈妈喜欢做的事有看电视和做饭,儿子完全继承了爸爸妈妈的爱好,使用多重继承输出儿子喜欢做的事。首先定义一个DadLikeDo接口,并在接口中定义两个方法 smoke()和 fish():

public interface DadLikeDo { // 定义“爸爸喜欢做的事”接口void smoke(); // 抽烟的方法void fish(); // 钓鱼的方法
}public interface MomLikeDo { // 定义“妈妈喜欢做的事”接口void watchTV(); // 看电视的方法void cook(); // 做饭的方法
}// 继承DadLikeDo接口和MomLikeDo接口
public class SonLikeDo implements DadLikeDo, MomLikeDo {public void watchTV() { // 实现watchTV()方法System.out.println("看电视");}public void cook() { // 实现cook()方法System.out.println("做饭");}public void smoke() { // 实现smoke()方法System.out.println("抽烟");}public void fish() { // 实现fish()方法System.out.println("钓鱼");}public static void main(String[] args) {SonLikeDo son = new SonLikeDo(); // 通过子类创建IFather接口对象System.out.println("儿子喜欢做的事有:");// 子类对象调用DadLikeDo和MomLikeDo两个接口被实现的所有方法son.watchTV();son.cook();son.smoke();son.fish();}
}

思考:
如何区分抽象类和接口?有哪些不同?