Java 面向对象进阶

第一章:抽象类

抽象类的使用原则如下:

1.1 抽象类(上)

  • (1)抽象方法必须用 public 修饰或者 protected 修饰(因为如果用 private 修饰,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为 public;

  • (2)抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理;

  • (3)抽象类必须有子类,使用 extends 继承,一个子类只能继承一个抽象类;

  • (4)子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法。(如果子类没有实现父类的抽象方法,则必须将子类也定义为为 abstract 类。)

1.2 汽车的轮子

请创建一个抽象类 Vehicle ,添加 NoOfWheels 抽象方法,并在 Vehicle 的子类 Car 和 Motorbike 中重写 NoOfWheels 方法。

Car.java

public class Car extends Vehicle{ public String NoOfWheels() { return "This car has four wheels"; } }

Motorbike.java

public class Motorbike extends Vehicle{ public String NoOfWheels() { return "This Motorbike has two wheels"; } }

Vehicle.java

public abstract class Vehicle { public abstract String NoOfWheels(); }

1.3 制作一杯咖啡

你的朋友学习了如何制作咖啡,现在她邀请你和她一起完成制作一杯咖啡,你非常开心的接受了她的要求。现在她已经创建了一个名为 Coffee 的类,还有两个继承自 Coffee 类的子类,分别为 GroundCoffee 和 BrewingCoffee,在 Main 类中创建了 GroundCoffee 和 BrewingCoffee 的实例。那么你现在需要帮助她完成咖啡的制作:

  • 在 Coffe 类中声明一个 MakeCoffee 方法,使其返回一个字符串值,并在 GroundCoffee 类中通过 System.out.println() 显示 Coffee being ground! 的提示消息
  • 在 BrewingCoffee 类中通过 System.out.println() 显示 Coffee being brewed! 的提示消息

BrewingCoffee.java

class BrewingCoffee extends Coffee { // write your code here public String MakeCoffee(){ System.out.println("Coffee being brewed!"); return "Coffee being brewed!"; } }

Coffee.java

abstract class Coffee { // write your code here public abstract String MakeCoffee(); }

GroundCoffee.java

class GroundCoffee extends Coffee { // write your code here public String MakeCoffee(){ System.out.println("Coffee being ground!"); return "Coffee being ground!"; } }

1.4创建 Person 抽象类

Person.java

public abstract class Person { public abstract String print(); private String className; public Person(String name){ this.className = name; } public String getClassName() { return this.className; } }

Student.java

public class Student extends Person{ @Override public String print(){ return "class extends Person abstract class."; } public Student(String name){ super(name); } }

1.5 抽象工厂模式

抽象工厂模式,是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为 Kit 模式,属于对象创建型模式,是一种创建对象的最佳方式。请您根据 Main 中对 AbstractFactory 工厂的使用,设计一个抽象工厂模式。
factory 包的相关说明:

FactoryProducer(工厂生成器) 用于获取 AbstractFactory 工厂,通过传递类型信息来获取实体类(extension 包下的扩展工厂)的对象
extension 包的说明:
ClothesFactory 创建扩展 AbstractFactory 的服装工厂类
FoodFactory 创建扩展 AbstractFactory 的食物工厂类
VehicleFactory 创建扩展 AbstractFactory 的交通工具工厂类
product 包的相关说明:

ifs 包下是产品的接口
Food :食物产品接口
Clothes :服装产品接口
Vehicle :交通工具产品接口
impl 包下是产品的实现类
答案链接

第二章 接口

2.1 实现 2 个接口的 Student

我们提供了两个接口 Interface1 和 Interface2,现在要写一个 Student 类来实现这两个接口,并通过 print1,print2 分别返回 s1,s2。Main 将会调用这两个方法进行输出。

public class Student implements Interface1,Interface2{ String s1 = "Student implements Interface1"; String s2 = "Student implements Interface2"; public String print1(){ return s1; } public String print2(){ return s2; } }

2.2实现接口

编写一个接口:InterfaceA,只含有一个方法 long method(long n);
编写一个类:ClassA 来实现接口 InterfaceA,实现 long method(long n) 接口方法时,要求计算 1 至 n 的和(0 < n < 9999);
编写另一个类:ClassB 来实现接口 InterfaceA,实现 long method(long n) 接口方法时,要求计算 n 的阶乘(n!)( 0 < n < 16 );
interfaceA:

public interface InterfaceA { long method(long n); }

classA:

public class ClassA implements InterfaceA{ @Override public long method(long n) { return (1 + n) * n / 2; } }

classB:

public class ClassB implements InterfaceA { @Override public long method(long n) { if (n == 1) { return 1; } return n * method(n - 1); } }

2.3 接口

什么时候使用抽象类和接口

  • 如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
  • 如果你想实现多重继承,那么你必须使用接口。由于 Java 不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
  • 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
interface InterfaceA{ void printCapitalLetter(); } interface InterfaceB{ void printLowercaseLetter(); } public class Print implements InterfaceA, InterfaceB { @Override public void printCapitalLetter() { // TODO Auto-generated method stub for(char chr = 'A';chr<='Z';chr++){ if(chr=='Z'){ System.out.println('Z'); break; } System.out.print(chr+" "); } } @Override public void printLowercaseLetter() { for(char chr = 'a';chr<='z';chr++){ if(chr=='z'){ System.out.println('z'); break; } System.out.print(chr+" "); } } }

2.4 打印大小写字母表

你需要定义两个接口 InterfaceA 和 InterfaceB,在接口 A 中定义方法 printCapitalLetter,在接口 B 中定义方法 printLowercaseLetter,然后编写一个类 Print,用来实现接口 InterfaceA 和 InterfaceB,要求 printCapitalLetter() 方法实现输出大写英文字母表的功能,printLowercaseLetter() 方法实现输出小写英文字母表的功能。
请在 Print 类中的 // write your code here 处编写你的代码。

interface InterfaceA { void printCapitalLetter(); } interface InterfaceB { void printLowercaseLetter(); } public class Print implements InterfaceA, InterfaceB { @Override public void printCapitalLetter() { for (char capital = 'A'; capital <= 'Z'; capital++) { if (capital == 'Z') { System.out.println(capital); } else { System.out.print(capital + " "); } } } @Override public void printLowercaseLetter() { for (char lowercase = 'a'; lowercase <= 'z'; lowercase++) { if (lowercase == 'z') { System.out.println(lowercase); } else { System.out.print(lowercase + " "); } } } }

2.5乘车付费提示(解释器模式)

每个乘车系统都会有相应的付费提示,针对不同的人群,会有不同提示。乘客刷卡后会提供的信息包含 3 个部分,"城市, 类别, 乘车卡(可选)"。
expression/InterpreterPattern.java

package expression; import java.util.*; import expression.po.*; public class InterpreterPattern { private String[] citys = {"杭州", "绍兴"}; private String[] local = {"老人", "学生"}; private String[] card = {"市民卡", "交通卡"}; private String[] global = {"孕妇", "儿童", "残疾人", "军人"}; private String s1 = "本次乘车免费~"; private String s2 = "请付费!"; private Expression free; public String freeRide(String passenger) { return free.interpret(passenger)? s1: s2; } // write your code here public InterpreterPattern() { free = new OrExpression(new TerminalExpression(global), new AndExpression(new TerminalExpression(citys), new AndExpression(new TerminalExpression(local), new TerminalExpression(card)) ) ); } }

expression/po/AndExpression.java

package expression.po; import java.util.*; import expression.Expression; public class AndExpression implements Expression{ // write your code here Expression e1; Expression e2; public AndExpression(Expression e1, Expression e2) { this.e1 = e1; this.e2 = e2; } public boolean interpret(String context) { return e1.interpret(context) && e2.interpret(context); } }

expression/po/OrExpression.java

package expression.po; import java.util.*; import expression.Expression; public class OrExpression implements Expression { // write your code here Expression e1; Expression e2; public OrExpression(Expression e1, Expression e2) { this.e1 = e1; this.e2 = e2; } public boolean interpret(String context) { return e1.interpret(context) || e2.interpret(context); } }

expression/po/TerminalExpression.java

package expression.po; import java.util.*; import expression.Expression; public class TerminalExpression implements Expression { // write your code here private String[] data; public TerminalExpression(String[] data) { this.data = data; } public boolean interpret(String context) { for (String s : data) { if (context.contains(s)) { return true; } } return false; } }

第三章:枚举

3.1打印梅兰竹菊代表的品性

请在类名为 Solution 的 textCharacter 方法中 // write your code here 下面编写你的代码。

本题我们在 Main.java 中已经写好了对 Solution 对象的创建和 textCharacter 方法的调用。

  • 在 Solution 类中已经定义好带有枚举类型引用参数的 printCharacter 方法,该方法中通过 switch case 语句实现对梅兰竹菊代表品性的打印。

  • 在 PropertyEnum 文件中定义了枚举类 PropertyEnum,以及列出了所有的枚举值。

要求:请在 Solution 类中 textCharacter 方法下编写代码,实现对枚举值属性的访问。

public class Solution { /** * @methods judge: Enumerate and print out the enumeration values * in the judge method */ public void printCharacter(PropertyEnum s) { switch (s) { case PlumBlossoms: System.out.println( "PlumBlossoms: A noble man who explores the waves and the snow"); break; case Orchid: System.out.println( "Orchid: A sage of the world, the fragrance of the deep valley"); break; case Bamboo: System.out.println("Bamboo: A gentleman of modesty and elegance"); break; case Chrysanthemum: System.out.println("Chrysanthemum: A hermit of the world"); break; } } public void textCharacter() { printCharacter(PropertyEnum.PlumBlossoms); printCharacter(PropertyEnum.Orchid); printCharacter(PropertyEnum.Bamboo); printCharacter(PropertyEnum.Chrysanthemum); } }

3.2一周的休息日(一)

我们提供一个枚举类 WeekDay ,属性 SUN, MON, TUE, WED, THU, FRI, SAT,分别代表 周日,周一,周二,周三,周四,周五,周六,其中 周日 和 周六 是休息日,请实现 isRestDay 函数,传入一个 WeekDay 返回该日期是否是休息日。

public class Solution { public static boolean isRestDay(WeekDay day) { // write your code here if(day == WeekDay.SUN || day == WeekDay.SAT){ return true; } return false; } }

3.3一周的休息日(二)

请您实现一个枚举类 WeekDay ,属性 SUN, MON, TUE, WED, THU, FRI, SAT,分别代表 周日,周一,周二,周三,周四,周五,周六,其中 周日 和 周六 是休息日,且含有一个属性 day,休息日则 day = 'Restday',工作日则 day = 'Workday'。同时需要提供两个函数,getWorkDay() 能够返回所有的工作日,getRestDay() 返回所有的休息日。

public enum WeekDay { SUN("Restday"), MON("Workday"), TUE("Workday"), WED("Workday"), THU("Workday"), FRI("Workday"), SAT("Restday"); private final String day; WeekDay(String day) { this.day = day; } public String getDay() { return day; } public static WeekDay[] getWorkDay() { WeekDay[] weekDays = {WeekDay.MON,WeekDay.TUE,WeekDay.WED,WeekDay.THU,WeekDay.FRI}; return weekDays; } public static WeekDay[] getRestDay() { WeekDay[] weekDays = {WeekDay.SUN,WeekDay.SAT}; return weekDays; } }

第四章:内部类

4.1 成员内部类

本题要求你在 Solution 类中调用内部类 Heart 下的 beat 方法。
请在 Solution.java 文件中的 // write your code here 处,编写合适的代码。

public class Solution { public void methodBody() { System.out.println("Methods for external classes"); // write your code here Heart heart = new Heart(); heart.beat(); } public class Heart { public void beat() { System.out.println("Heartbeat"); } } }

4.2 静态内部类

有一个 Library 类,你需要在该类中编写一个静态内部类 Book,该静态内部类定义了书名 name,作者 author,单价 price,并在 Book 类中编写一个 show 方法,用来输出程序运行结果,请在 Library.java 中的 // write your code here 处编写合适的代码,完成该题目。

class Library { // write your code here public void management() { System.out.println("Managing Books"); } public static class Book{ String name; String author; float price; Book(String name,String author,float price){ this.name=name; this.author=author; this.price=price; } public void show(){ System.out.println("The book title is "+name); System.out.println("The author is "+author); System.out.println("Price is $"+price); } } }

4.3 局部内部类

请在 Solution.java 文件中的 //write your code here 处编写合适的代码,创建一个 Inner 局部内部类,并采用该方式分别获取 a 的值,使得 a1 = 0,a2 = 20。

public class Solution { int a = 0; public void method() { final int a = 20; //write your code here class Inner{ int a2=Solution.this.a; int a1=a; } Inner inner=new Inner(); System.out.println(inner.a1); System.out.println(inner.a2); } }

4.4 匿名内部类

你需要在 Outer.java 文件中编写一个匿名内部类,并在控制台打印 Hello JiuZhang,你可以在 Main.java 文件中查看你的代码是如何被调用的。

interface Inner { void show(); } class Outer { public static Inner method() { //new一个Inner对象,重写接口的show方法 return new Inner(){ public void show(){ System.out.println("Hello JiuZhang"); } }; } }

4.5 使用匿名内部类

请在类名为 Solution 中的 get 方法中的 // write your code here 下面编写你的代码。

我们提供了 Animal 接口与抽象方法 eat,其中 eat 方法需要传入一个字符串类型的参数,在 Solution 中提供了私有字符串属性 name,还包含了带 name 的有参构造函数, 其中 get 方法需要返回一个 Animal 的对象。
要求:实现 Animal 接口并重写 eat 方法,输出打印 name 和 food 的信息。

public class Solution { private String name; public Solution(String name) { this.name = name; } public Animal get() { // 创建匿名内部类对象 return new Animal() { // 重写接口方法 @Override public void eat(String food) { System.out.println(name + " eat " + food); } }; } }

第五章:final

5.1 final关键字

final 关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值。

首先,我们应该了解定义为 final 的方法不能被重写。
将方法定义为 final 类型可以防止任何子类修改该方法,同时定义为 final 的方法执行效率要高于非 final 方法。在修饰权限中曾经提到过 private 修饰符,如果一个父类的某个方法被设置为 private 修饰符,子类将无法访问该方法,自然无法覆盖该方法,所以一个定义为 private 的方法隐式被指定为 final 类型,这样无须将一个定义为 private 的方法再定义为 final 类型。

5.2 bug修复之final关键字

这道题是一个 Bug Fix 训练,但代码中有一个bug,在类 Solution 中,包含五个字符串变量,a,b,c,d,e,请你在某个地方新增关键字,使得 a 与 c 相等,但 a 与 e 不相等,我们会在类 Main 中检验你的代码是否合格,当你正确修改后,输出应如样例所示。

public class Solution { String a = "hello2"; final String b = "hello"; String d = "hello"; // Do not modify the code below String c = b + "2"; String e = d + "2"; }

5.3 接口的变量

请给 Person 接口添加一个名为 ifs 的变量,使程序能够正确运行。

public interface Person { // write your code here String ifs = "Person"; String speak(); }

5.4 检查代码

李四今天做作业写了一段代码,充满了 bug 的气息,最主要的问题全都出在 Student 类上,李四请求你帮他检查并修正代码错误的地方,作业的要求是Student 类的属性必须全是 final 修饰的。

// Please check code here import static java.lang.Math.pow; import static java.lang.Math.sqrt; public class Student { final String name ; final int age; public Student(String name, int age) { this.name = name; this.age = age; } public double math(int a, int b) { if (a > b) { return pow(2, a % 10) - pow(2, b % 10); } else { return sqrt(a) - sqrt(b); } } public String toString() { return name + " : " + age; } }

第六章 static

6.1 bug 修复之 static 关键字

这道题是一个 Bug Fix 训练,代码中有一个 bug,在类 Solution 中,包含两个整型变量 random1 和 random2,我们会在类 Main 中创建两个 Solution 对象 s1 和 s2,最终使得 s1.random1 == s2.random1,s1.random2 != s2.random2,请你在合适的地方新增关键字,确保程序正常运行,当你正确修改后,输出应如样例所示。

import java.util.Random; public class Solution { static int random1 = new Random().nextInt(); int random2 = new Random().nextInt(); }

第七章 instenseof

7.1 全等对象

在日常的开发中,我们可能会需要判断两个对象是否全等。所谓的全等判断标准就是,对象中的所有属性值都是相同的。而实现方式就是重写对象的 equals 方法,来进行比较判断。
请您在 Animal 类中重写 equals 方法,来实现上述功能(判断两个 Animal 是否全等)。

import java.util.*; public class Animal{ private int age; private String name; public Animal() { name = ""; } public Animal(String name, int age) { this.age = age; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else { if (obj instanceof Animal) { Animal animal = (Animal)obj; if (this.getAge() == animal.getAge()) { return this.name.equals(animal.getName()); } } return false; } } }

第八章:代码块

8.1 静态代码块的使用

请在类 Solution 中编写静态代码块,输出打印 Execute static code block when class is loaded,要求当创建两个 Solution 对象时,该语句只被输出一次。

public class Solution { // write your code here static{ System.out.println("Execute static code block when class is loaded"); } }

8.2 初始化类的属性

在日常工作中,我们可能会经常遇见各种 默认值,像用户注册时,性别 sex 会自动勾选默认值 男/女,在创建文件时会有默认文件名称,等等。

今天我们也需要来实现一个这样的功能,给出一个类 People 并包含属性 name 和 sex,请您实现在创建 Person 对象时,为其添加默认 name = Luc 并且 sex = man,同时创建两个构造方法 public People() 与 public People(String name, String sex) ,其中有参构造,可以为属性赋值。同时我们提供了 printMes() 方法来获取 People 的信息。

public class People { public String sex; public String name; public People() { this.sex = "man"; this.name = "Luc"; } public People(String name, String sex) { this.sex = sex; this.name = name; } public String printMes(){ return name +" is a " + sex; } }

程序运行结果

给定一个数字 num 表示 new TestB() 的次数,请您计算执行 num 次 new TestB() 后 TestA.num 的值,并在 Solution 类的 printNum 方法中输出。

public class Solution { public void printNum(int num) { // write your code here for(int i=0;i<num;i++) { TestB test =new TestB(); //实例化对象时自动调用构造方法 } System.out.println(TestB.num); } }

__EOF__

本文作者粥粥alg
本文链接https://www.cnblogs.com/3456939606zwp/p/17900267.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   粥粥alg  阅读(87)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示