课后练习回顾,疑难重点总结(二)
目录
8.一个类的构造方法的作用是什么?若一个类没有声明构造方法,程序能正确运行吗?为什么?
11.在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是什么?
面向对象习题脉络梳理
1、模拟双色球中奖(Java基础补充)
中奖规则:
"双色球"每注投注号码由6个红色球号码和1个蓝色球号码组成。红色球号码从1--33中选择;蓝色球号码从1--16中选择。奖级和中奖条件如下图所示。
代码实现过程:
- (1)定义用户购买的球和开奖的球的数组,这里调用了用户输入的scanner语句和生成随机数的random语句。
Scanner sc = new Scanner(System.in);
Random rd = new Random();
//定义用户购买的红色球数组和开奖红色球数组
int[] userRed = new int[6];
int[] comRed = new int[6];
//定义用户购买的蓝球和开奖蓝球
int userBlue, comBlue = rd.nextInt(16) + 1;
- (2)用户将从1-33号红球中选择其中6个球进行下注。若超出1-33的范围则输出“输入有误”;若下注到相同的球时,立刻输出“该号码已存在”。反之系统接收红球,并将这6个球进行升序排序,方便后续识别中奖情况。
//用户选择红球
for (int i = 0; i < 6; i++) {
System.out.println("请输入第" + (i + 1) + "个红色球号码");
int inp = sc.nextInt();
if (inp < 1 || inp > 33) {
System.out.println("输入有误");
i--;
continue;
}
//接收输入
userRed[i] = inp;
//j表示已经生成的下标,i表示当前最新的下标
for (int j = 0; j < i; j++) {
if (userRed[i] == userRed[j]) {
System.out.println("该号码已存在");
i--;
}
}
}
//升序排序
Arrays.sort(userRed);
- (3)用户选择蓝球,若超出1-16的范围,则输出“蓝色球号码输入有误”,反之系统接收蓝球。
//接收蓝色球
while (true) {
System.out.println("请输入蓝色球号码");
int inpBlue = sc.nextInt();
if (inpBlue < 1 || inpBlue > 16) {
System.out.println("蓝色球号码输入有误");
} else {
userBlue = inpBlue;
break;
}
}
- (4)以遍历的形式打印用户购买的红球数组的号码,中间用空格隔开,再打印购买的蓝球号码。
//打印
System.out.println("您选择的红色球号码为");
for (int i : userRed) {
System.out.print(i + "\t");
}
System.out.println();
System.out.println("您选择的蓝色球号码为");
System.out.println(userBlue);
- (5)开奖结果要遵循号码不能重复的原则。将开奖的红球数组升序排序,方便和前面用户购买的红球做判断;开奖的蓝球则单一输出即可。
//开奖结果
for (int i = 0; i < 6; i++) {
comRed[i] = rd.nextInt(33) + 1;
//去重复
for (int j = 0; j < i; j++) {
if (comRed[i] == comRed[j]) {
i--;
}
}
}
//排序
Arrays.sort(comRed);
System.out.println("===============");
//打印开奖结果
System.out.println("开奖结果红色球号码为");
for (int i : comRed) {
//程序休眠1s
Thread.sleep(1000);
System.out.print(i + "\t");
}
System.out.println();
System.out.println("开奖结果蓝色球号码为");
System.out.println(comBlue);
- (6)要想判断用户中了几等奖,就必须记录球号正确的数量。这里用count来统计红球正确的数量,以嵌套的方式来比较用户购买和开奖的红球是否一致;蓝球只有一个,可直接判断是否正确。
//判断蓝球是否正确
boolean flag = userBlue == comBlue;
//统计红球正确数量
int count = 0;
//循环嵌套比较两个数组的所有下标
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
if (userRed[i] == comRed[j]) {
count++;
}
}
}
- (7)根据蓝球是否正确,以及红球正确的个数,来打印输出最终的中奖情况。
if (!flag) {
System.out.println("很遗憾未中奖");
}
switch (count) {
case 0:
case 1:
case 2:
if (flag) {
System.out.println("六等奖,奖金5元");
}
break;
case 3:
if (flag) {
System.out.println("五等奖,奖金10元");
}
break;
case 4:
if (flag) {
System.out.println("四等奖,奖金200元");
} else {
System.out.println("五等奖,奖金10元");
}
break;
case 5:
if (flag) {
System.out.println("三等奖,奖金3000元");
} else {
System.out.println("四等奖,奖金200元");
}
break;
case 6:
if (flag) {
System.out.println("一等奖");
} else {
System.out.println("二等奖");
}
break;
}
小结:
1)增强for循环专门用于遍历数组或集合元素的一种循环。语法:for(数据类型 变量名 : 数组名){}
本题中,在写用户购买的红球数组时用到过增强for循环。
System.out.println("您选择的红色球号码为");
for (int i : userRed) {
System.out.print(i + "\t");
}
2)数组工具类Arrays是jdk提供的用于处理数组的工具类。包含了如排序、复制、填充等方法,这些方法都是静态方 法,直接通过Arrays调用。
常用方法 | 作用 |
sort(数组) | 将输入中的元素升序排列。 |
sort(数组,起始位置,结束位置) | 对数组中[起始位置,结束位置)区间的元素升序排序。 |
fill(数组,值) | 使用指定值对数组中的所有元素进行填充。 |
fill(数组,,起始位置,结束位 置,值) | 使用指定值对数组中[起始位置,结束位置)区间的元素进行填充。 |
copyOf(数组,新数组长度) | 复制数组并指定复制后的数组的长度。得到复制后的新数组。 |
asList(一组数据) | 将一组数据转换为List集合。 |
equals(数组1,数组2) | 判断两个数组是否相同,得到判断的布尔值。只有两个数组一模一样 时得到true。 |
2、模拟“电子宠物”(构造方法的应用)
要求:
进入系统 创建宠物(可以手动创建,也可以自动随机创建) 如果手动创建,就输入宠物信息:品种、昵称 。
进入菜单 1.查看宠物信息 打印我叫xxx,是一只xxx,是您的电子宠物;
2.喂食 接收输入的食物名,输出xxx正在吃xxx;
3.玩耍 接收输入的玩具名,输出xxx正在玩耍xxx
宠物类 属性:品种、昵称 方法:输出信息、喂食(String 食物){}、玩耍(String 玩具){}
Main类 main(){ 打印菜单,输入选项 }
代码实现过程:
- (1)宠物类
/*
* 定义电子宠物类
*
* 属性
* 类型
* 昵称
*
* 方法
* 自我介绍
* 吃
* 玩
*
* */
public class Pet {
//定义属性
String type;
String nickName;
/*
* 声明构造方法,用于初始化成员变量
* */
Pet(String type, String nickName) {
this.type = type;
this.nickName = nickName;
}
/*
* 自我介绍的方法
* */
void introduce() {
System.out.println("我是一只" + type + ",我叫" + nickName);
}
/*
* 吃食物的方法
* */
void eat(String food) {
System.out.println(nickName + "正在吃" + food);
}
/*
* 玩耍的方法
* */
void play(String toy) {
System.out.println(nickName + "正在玩" + toy);
}
}
- (2)电子宠物机类(用作执行功能:查看宠物信息,喂食,玩耍)
import java.util.Random;
import java.util.Scanner;
/*
* 定义电子宠物机类
* 属性
* 宠物
* 方法
* 启动
* */
public class Tamagotchi {
//定义属性
Pet pet;
/*
* 构造方法
* 在创建当前类的对象时,就初始化一个宠物对象
* */
Tamagotchi() {
Random rd = new Random();
//类型和昵称数组
String[] typeList = {"小猫", "小狗", "小猪", "鹦鹉", "企鹅"};
String[] nameList = {"喵喵", "阿旺", "阿朱", "小六", "秋秋"};
//随机类型和昵称
int i = rd.nextInt(5);
int j = rd.nextInt(5);
//创建一个宠物对象
/* pet = new Pet();
pet.nickName = nameList[j];
pet.type = typeList[i];*/
pet = new Pet(typeList[i], nameList[j]);
}
/*
* 启动机器
* */
void start() {
Scanner sc = new Scanner(System.in);
System.out.println("欢迎来到你的宠物的小窝");
System.out.println("1.查看宠物信息");
System.out.println("2.喂养");
System.out.println("3.玩耍");
System.out.println("4.退出");
int inp = sc.nextInt();
switch (inp) {
case 1:
pet.introduce();
break;
case 2:
System.out.println("请输入食物");
String food = sc.next();
pet.eat(food);
break;
case 3:
System.out.println("请输入玩具");
pet.play(sc.next());
break;
case 4:
System.exit(0);
break;
}
}
}
- (3)Main类
public class Main {
public static void main(String[] args) {
//创建宠物机对象
Tamagotchi tamagotchi = new Tamagotchi();
//调用启动方法
while (true){
tamagotchi.start();
}
}
}
小结:
构造方法是一个特殊的方法,没有返回值,方法名和类名一致。 每个类在定义时,都有一个默认隐藏的无参数的构造方法,在创建对象时调用。 构造方法通常用于初始化成员变量。
public class Test{
//这就是无参数的构造方法,默认就会存在,不过是隐藏的
public Test(){
}
}
特点:
- 构造方法没有返回值(没有返回值这一部分,不是void),构造方法名必须和类名相同
- 每个类默认有一个隐藏无参数的构造方法,方法体中没有内容,用于创建无参数的对象
- 如果自己写了有参数的构造方法,默认无参数的构造方法就会失效。如果想要同时拥有带参数和不 带参数的构造方法,就需要把它们都写出来
- 构造方法可以限制创建对象时的参数
- 构造方法不能通过“.”操作符访问,只能通过new关键字创建对象时自动调用,所以构造方法通常用于初始化成员变量
3、花木兰替父从军(封装、继承、多态的使用案例)
- (1)女人类
/*
* 多态的应用--花木兰替父从军
* 女人类
* 继承军人类后,重写fight方法
* */
public class Woman extends Soldier {
public Woman(String name) {
super(name);
}
军人类
/*
* 化妆打扮的方法
* */
public void makeUp() {
System.out.println(super.getName() + "梳妆打扮");
}
/*
* 做家务的方法
* */
public void doHousework() {
System.out.println(super.getName() + "烧水做饭");
}
/*
*
* */
@Override
public void fight() {
System.out.println(super.getName() + "替父从军");
}
}
- (2)军人类
/*
* 定义军人类
* */
public class Soldier {
private String name;
public Soldier(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/*
* 定义战斗的方法
* */
public void fight() {
System.out.println(name + "上阵杀敌");
}
}
- (3)战场类
/*
* 定义战场类
* */
public class BattleGround {
/*
* 定义战争的方法,参数为一个军人对象
* */
public void war(Soldier soldier) {
soldier.fight();
}
public static void main(String[] args) {
BattleGround battleGround = new BattleGround();
//原本可以创建一个Soldier对象作为参数
Woman hua = new Woman("花木兰");
//如果创建的子类对象,用子类变量接收,可以调用子类中的方法
hua.makeUp();
hua.doHousework();
//假如不能再创建Soldier对象了
/*Soldier soldier = new Soldier("花爸爸");
battleGround.war(soldier);*/
//无法直接将Woman对象作为Soldier对象使用
//当把Woman继承Soldier类后,就能将Woman类的对象,当做Soldier使用
Soldier soldier=hua;
//如果子类的对象用父类的变量接收,无法访问子类中除父类中有的方法
// soldier.makeUp();无法调用
// soldier.doHousework();//无法调用
soldier.fight();
battleGround.war(soldier);
}
}
小结:
1)面向过程的三大特征:
封装 将类中的属性使用private修饰,这样就能防止非当前类对其访问。
封装的步骤:
- a.给类中的所有属性添加private访问修饰符
- b.给每个属性添加getXXX()方法用于读取属性值
- c.给每个属性添加setXXX()方法用于给属性赋值
- b.给每个属性添加getXXX()方法用于读取属性值
继承 类A extend 类B。类A就是类B的子类,类A的对象就能直接访问类B中非私有成员。 或接口A extends 接口B。
多态 子类的对象指向父类的引用(子类对象使用父类变量接收,即向上转型)。
语句:父类 变量 = new 子类();
2)重写和重载的区别:
重写Override 子类继承父类后,对父类中的非私有方法进行重写,达到拓展或重做的目的
- 必须满足方法名、返回值、参数列表都相同
- 访问权限不能比父类中的方法更严格
- 不能抛出比父类中的方法更大的异常
重载Overload 在一个类中,某个方法在不同的参数下,表现不同的行为。同名不同参。
- 方法名必须相同
- 参数列表必须不同(类型和数量)
- 无返回值无关
3)this和super的区别:
相同点:都可以当做对象或构造方法使用。
不同点:
a、当做对象使用:
- this表示当前类的对象,super表示当前类的父类对象。
- this或super当做对象使用时,只能用在非静态方法中。
b、当做构造方法使用:
- this()表示当前类的无参数构造方法,如果带参数就表示对应参数的构造方法。
- super()表示当前类的父类的无参数构造方法,如果带参数就表示对应参数的构造方法。
- this()或super()只能用在另一个构造方法的首行。
- super()表示当前类的父类的无参数构造方法,如果带参数就表示对应参数的构造方法。
注意:如果父类中有无参数的构造方法,在子类的构造方法中,可以不写super(),系统会自动调用。 如果父类中有带参数的构造方法,没有无参数的构造方法,在子类的构造方法中,必须要写super(),并 且赋予适当的参数。
4、实现简易图书管理系统
要求:
图书类 属性:编号 书名 作者 价格
图书管理员类 属性:用户名 密码 图书数组 方法:添加 查看 修改 删除
代码实现过程:
1)图书类
import java.util.Random;
/*
* 图书类
* 属性
* 编号
* 书名
* 作者
* 价格
* */
public class Book {
private int id;
private String name;
private String author;
private double price;
/*
* 创建图书对象时,只需要提供书名、作者和价格,图书编号自动生成一个6位数
* */
public Book(String name, String author, double price) {
this.id = new Random().nextInt(900000) + 100000;
this.name = name;
this.author = author;
this.price = price;
}
public Book() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
2)图书管理员类
/*
* 图书管理员类
* 属性
* 用户名
* 密码
* 图书数组
* 方法
* 登陆
* 增加
* 查看
* 修改
* 删除
* */
public class BookManager {
private String name;
private String pwd;
//list属性只允许在当前类中使用,所以不提供get/set方法
private Book[] list = new Book[30];
/*
* 添加
* */
public void addBook(Book book) {
//向数组中一个空位置保存参数
for (int i = 0; i < list.length; i++) {
if (list[i] == null) {
list[i] = book;
break;
}
}
}
/*
* 查看所有
* */
public void showAll() {
System.out.println("编号\t书名\t作者\t价格");
for (Book book : list) {
if (book != null) {
System.out.println(book.getId() + "\t" + book.getName() + "\t" + book.getAuthor() + "\t" + book.getPrice());
}
}
}
/*
* 根据编号获取对应的图书对象
* */
public Book findById(int id) {
for (Book book : list) {
if (book != null && book.getId() == id) {
return book;
}
}
return null;
}
/*
* 修改
* */
public void update(int id, double price) {
Book byId = findById(id);
if (byId != null) {
byId.setPrice(price);
} else {
System.out.println("该图书不存在");
}
}
/*
* 删除
* */
public void delete(int id) {
for (int i = 0; i < list.length; i++) {
if (list[i] != null && list[i].getId() == id) {
list[i] = null;
break;
}
}
}
/*
* 只包含name和pwd作为参数的构造方法,用于创建管理员对象时初始化管理员信息及初始化数组
* */
public BookManager(String name, String pwd) {
this.name = name;
this.pwd = pwd;
}
public String getName() {
return name;
}
public String getPwd() {
return pwd;
}
public void setName(String name) {
this.name = name;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
3)Main类
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=====请登陆=====");
System.out.println("请输入用户名");
String name = sc.next();
System.out.println("请输入密码");
String pwd = sc.next();
//创建登陆时的管理员对象
BookManager bookManager = new BookManager(name, pwd);
//调用当前类中登陆的方法
boolean flag = login(bookManager);
if (!flag) {
System.out.println("用户名或密码错误");
return;
}
while (true) {
//进入系统
System.out.println("1.查看所有图书");
System.out.println("2.添加图书");
System.out.println("3.查看指定图书");
System.out.println("4.修改图书");
System.out.println("5.删除图书");
switch (sc.nextInt()) {
case 1:
//查看所有
bookManager.showAll();
break;
case 2:
System.out.println("请输入书名");
String bookName = sc.next();
System.out.println("请输入作者");
String author = sc.next();
System.out.println("请输入价格");
double price = sc.nextDouble();
//调用添加的方法,参数要创建一个图书对象
bookManager.addBook(new Book(bookName, author, price));
break;
case 3:
//接收参数调用查询
System.out.println("请输入图书编号");
int bookId = sc.nextInt();
Book book = bookManager.findById(bookId);
System.out.println(book.getId() + "\t" + book.getName() + "\t" + book.getAuthor() + "\t" + book.getPrice());
break;
case 4:
//接收参数调用修改
System.out.println("请输入图书编号");
int updateId = sc.nextInt();
System.out.println("请输入价格");
double newPrice = sc.nextDouble();
bookManager.update(updateId, newPrice);
break;
case 5:
//接收参数调用删除
System.out.println("请输入图书编号");
int deleteId = sc.nextInt();
bookManager.delete(deleteId);
break;
}
}
}
/*
* 登陆的方法
* 由于想要在main方法中直接调用该方法,所以将该方法也写成static方法
* */
public static boolean login(BookManager bookManager) {
//判断字符串是否相同,要使用 a.equals(b)方法 。最好将已知非空的字符串作为调用者。
if ("admin".equals(bookManager.getName()) && "123123".equals(bookManager.getPwd())) {
return true;
}
return false;
}
}
举一反三:
模拟游戏角色PK
要求:
游戏角色类 属性:姓名 阵营 武器 技能 生命值
玩家类 属性:用于保存游戏角色的数组
方法:添加角色 查看所有 根据编号得到角色 战斗
代码实现过程:
1)游戏角色类
import java.util.Objects;
public class GameRole {
/*
* 游戏角色类
* */
private int id;//定义编号
private String roleName;//定义名字
private String camp;//定义阵营
private String weapon;//定义武器
private String skill;//定义技能
public int hp=1000;//生命
//构造方法
public GameRole(int id, String roleName, String camp, String weapon, String skill) {
this.id = id;
this.roleName = roleName;
this.camp = camp;
this.weapon = weapon;
this.skill = skill;
}
public GameRole() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GameRole gameRole = (GameRole) o;
return id == gameRole.id && roleName.equals(gameRole.roleName) && camp.equals(gameRole.camp) && weapon.equals(gameRole.weapon) && skill.equals(gameRole.skill);
}
@Override
public int hashCode() {
return Objects.hash(id, roleName, camp, weapon, skill);
}
@Override
public String toString() {
return "GameRole{" +
"id=" + id +
", roleName='" + roleName + '\'' +
", camp='" + camp + '\'' +
", weapon='" + weapon + '\'' +
", skill='" + skill + '\'' +
", hp=" + hp +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getCamp() {
return camp;
}
public void setCamp(String camp) {
this.camp = camp;
}
public String getWeapon() {
return weapon;
}
public void setWeapon(String weapon) {
this.weapon = weapon;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
public int getHp() {
return hp;
}
public void setHp(int hp) {
this.hp = hp;
}
}
2)玩家类
import java.util.Random;
public class Player {
/*
* 玩家类
* */
String name;//定义玩家名
//list属性只允许在当前类中使用,所以不提供get/set方法
private GameRole[] list = new GameRole[10];
/*
* 添加
* */
public void addRole(GameRole gameRole){
//向数组中一个空位置保存参数
for (int i = 0; i < list.length; i++) {
if (list[i] == null) {
list[i] =gameRole ;
break;
}
}
}
/*
* 查看所有
* */
public void showAll() {
System.out.println("编号\t名字\t阵营\t武器\t技能\t生命");
for (GameRole gameRole : list) {
if (gameRole != null) {
System.out.println(gameRole.getId()+"\t"+gameRole.getRoleName() + "\t" + gameRole.getCamp() + "\t" + gameRole.getWeapon() + "\t" + gameRole.getSkill()+"\t"+ gameRole.getHp());
}
}
}
/*
* 根据编号获取对应的角色对象
* */
public GameRole findById(int id) {
for (GameRole gameRole : list) {
if (gameRole != null && gameRole.getId() == id) {
return gameRole;
}
}
return null;
}
/*
* 修改
* */
public void update(int id, String name,String camp,String weapon,String skill) {
GameRole byId = findById(id);
if (byId != null) {
byId.setRoleName(name);
byId.setCamp(camp);
byId.setWeapon(weapon);
byId.setSkill(skill);
} else {
System.out.println("该角色不存在");
}
}
/*
* 删除
* */
public void delete(int id) {
for (int i = 0; i < list.length; i++) {
if (list[i] != null && list[i].getId() == id) {
list[i] = null;
break;
}
}
}
/*
* PK
* */
public void battle(GameRole p1,GameRole p2) throws InterruptedException {
System.out.println("来自["+p1.getCamp()+"]阵营的"+p1.getRoleName()+"PK来自["+p2.getCamp()+"]阵营的"+p2.getRoleName());
p1.setHp(1000);
p2.setHp(1000);
while (true){
if(p1.getHp()<=0){
System.out.println(p1.getRoleName()+"已阵亡");
break;
}if(p2.getHp()<=0){
System.out.println(p2.getRoleName()+"已阵亡");
break;
}
//生成4-12的随机数
int randNum=new Random().nextInt(9)+4;
Thread.sleep(500);
if(randNum==12){
int hit1=new Random().nextInt(51)+100;
int hit2=new Random().nextInt(51)+100;
System.out.println(p1.getRoleName()+"使用"+p1.getWeapon()+"对"+p2.getRoleName()+"发动"+p1.getSkill()+"造成"+hit1+"点伤害");
System.out.println(p2.getRoleName()+"使用"+p2.getWeapon()+"对"+p1.getRoleName()+"发动"+p2.getSkill()+"造成"+hit2+"点伤害");
p1.setHp(p1.getHp()-hit1);
p2.setHp(p2.getHp()-hit2);
}else if(randNum%3==0){
int hit1=new Random().nextInt(51)+100;
System.out.println(p1.getRoleName()+"使用"+p1.getWeapon()+"对"+p2.getRoleName()+"发动"+p1.getSkill()+"造成"+hit1+"点伤害");
p2.setHp(p2.getHp()-hit1);
}else if(randNum%4==0){
int hit2=new Random().nextInt(51)+100;
System.out.println(p2.getRoleName()+"使用"+p2.getWeapon()+"对"+p1.getRoleName()+"发动"+p2.getSkill()+"造成"+hit2+"点伤害");
p1.setHp(p1.getHp()-hit2);
}else {
System.out.println(p1.getRoleName()+"受到10点普通伤害");
System.out.println(p2.getRoleName()+"受到10点普通伤害");
p1.setHp(p1.getHp()-10);
p2.setHp(p2.getHp()-10);
}
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3)Main类
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws InterruptedException {
Scanner sc = new Scanner(System.in);
//创建游戏厅对象
System.out.println("欢迎进入角色PK游戏厅");
Player player = new Player();
GameRole g1=new GameRole(1,"八重神子","稻妻","神乐之真意","大秘法 天狐显现");
GameRole g2=new GameRole(2,"钟离","璃月","护摩之杖","天星");
GameRole g3=new GameRole(3,"菲谢尔","蒙德","暗夜华尔兹","至夜幻现");
GameRole g4=new GameRole(4,"纳西妲","须弥","千夜寻梦","心景幻成");
GameRole g5=new GameRole(5,"神里绫华","稻妻","雾切之回光","神里流 霜灭");
player.addRole(g1);
player.addRole(g2);
player.addRole(g3);
player.addRole(g4);
player.addRole(g5);
//创建玩家对象
System.out.println("请输入玩家名:");
String name = sc.next();
System.out.println("欢迎您," + name);
System.out.println("================");
while (true) {
System.out.println();
System.out.println("请选择功能");
System.out.println("1.添加角色");
System.out.println("2.修改角色");
System.out.println("3.删除角色");
System.out.println("4.查看全部角色");
System.out.println("5.角色PK");
System.out.println("6.退出游戏");
System.out.println();
switch (sc.nextInt()) {
default:
System.out.println("输入有误!请重新输入");
break;
case 1://添加角色
System.out.println("请输入角色编号:");
int id = sc.nextInt();
System.out.println("请输入角色名字:");
String roleName = sc.next();
System.out.println("请输入角色阵容:");
String camp = sc.next();
System.out.println("请输入角色武器:");
String sweapon = sc.next();
System.out.println("请输入角色技能:");
String skill = sc.next();
player.addRole(new GameRole(id, roleName, camp, sweapon, skill));
break;
case 2://修改角色
//接收参数调用修改
System.out.println("请输入角色编号:");
int updateId = sc.nextInt();
System.out.println("请重新输入名字:");
String newRoleName = sc.next();
System.out.println("请重新输入阵营:");
String newCamp = sc.next();
System.out.println("请重新输入武器:");
String newWeapon = sc.next();
System.out.println("请重新输入技能:");
String newSkill = sc.next();
player.update(updateId, newRoleName, newCamp, newWeapon, newSkill);
break;
case 3://删除角色
System.out.println("请输入角色编号:");
int deleteId = sc.nextInt();
player.delete(deleteId);
break;
case 4://显示所有
player.showAll();
break;
case 5://角色PK
System.out.println("请输入角色编号");
int id1 = sc.nextInt();
GameRole p1 = player.findById(id1);
System.out.println("请输入角色编号");
int id2 = sc.nextInt();
GameRole p2 = player.findById(id2);
player.battle(p1,p2);
break;
case 6://退出游戏
System.out.println("成功退出游戏");
System.exit(0);
break;
}
}
}
}
运行示例:
小结:
Object类是所有类的父类。任何类都间接地继承了该类,但没有明确地使用extends体现出来。所有类都可以访 问Object类中的方法,或对其进行重写。
- toString()就是Object类中的一个方法,在输出对象时自动调用。默认输出的是"类名@十六进制哈希 码",通常在自定义类中,重写toString(),从而输出该类中的属性。
- equals()也是Object类中的一个方法,用于比较两个对象是否相同。默认使用==比较,即比较内存地 址,通常需要重写该方法,自定义判断两个对象是否相同时所需的参数。
面向对象企业常见面试题总结
1.面向对象的特点
1)封装
使用private关键字对属性进行修饰。再对外提供一组公开的get/set方法用于对该属性读取或赋值。 可以防止除自身类之外的地方对该属性就行访问。 这样做可以保护关键属性,隐藏类内部的实现细节。
步骤:
a.创建类,编写成员变量,给成员变量添加private修饰符
public class Student{
private int stuId;
private String stuName;
private String major;
}
b.给所有成员变量添加setXXX方法,用于给私有的成员变量赋值
public void setStuId(int stuId){
this.stuId = stuId;
}
public void setStuName(String stuName){
this.stuName = stuName;
}
public void setMajor(String major){
this.major = major;
}
c.给所有成员变量添加getXXX方法,用于读取私有的成员变量
public int getStuId(){
return stuId;
}
public String getStuName(){
return stuName;
}
public String getMajor(){
return major;
}
d.这是创建对象后,无法通过.访问属性,只能通过get/set方法
public static void main(String[] args){
Student stu = new Student();
//stu.stuId=111;无法通过.赋值和读取
//只能通过set方法赋值
stu.setStuId(10026312);
//只能通过get方法获取私有属性的值
System.out.println(stu.getStuId());
}
2)继承
- 类A可以通过extends关键字继承类B。
- 语法:class 类A extends 类B{}
- 类A称为子类、派生类、衍生类、subClass
- 类B称为父类、根类、超类、superClass
- 继承后,子类可以访问父类中非私有(没有被private修饰的内容)的属性和方法。
- 不同的子类中如果有相同的代码,都可以把它们提出来保存到父类中,从而减少子类中的代码冗余。如狗类、猫类都有类型、昵称等属性,也有吃、睡等方法,那么就可以定义一个动物类,将这些公共的属性和方法定义在动物类中,让猫类和狗类继承动物类。
3)多态
- 多态就是子类的对象指向父类的引用(子类对象使用父类变量接收,即向上转型)。
- 父类 变量 = new 子类();
public class Father{
}
public class Son extends Father{
}
public class Main{
public static void main(String[] args){
Son son = new Son();
//这就是多态的体现
//子类的对象,可以使用父类的变量保存
Father father = new Son();
}
}
- 多态的应用 当某个方法的参数为父类变量时,可以传递一个子类对象。 这样就能在传递不同子类对象时,执行不同的方法。 如要调用动物发出叫声的方法,参数为猫,输出喵喵叫,参数为狗,输出汪汪叫。 不用多态,需要写多个重载的方法,参数为猫或狗的具体类型。 使用多态,只需一个方法,参数为动物类型,动物类中定义一个叫的方法,让猫和狗继承这个动物类, 重写叫的方法。 这时调用动物发出叫声的方法时,就会根据实际的参数,表示不同的结果。
- 多态的实现条件 在继承关系中,子类需要重写父类中的方法,父类的引用指向子类的对象(向上转型)
2.怎么理解面向对象
面向对象过程(Object Oriented Programming)简称OOP 是当今主流的编程思想,是创建解决问题的对象,赋予对象对应的行为和特征,让这些对象互相配合(调用对象的方法)完成。 这种思想致力于将计算机中的世界,描述的和现实中一致的思想。
- 如洗衣服,创建一个能洗衣服的工具:洗衣机,让洗衣机拥有洗衣粉的行为(方法),调用该行为即可。
- 如组装电脑,A推荐配置单、B去商城购买、C送回家、D组装。
3.面向对象和面向过程的区别
- 面向过程POP:亲力亲为,侧重于分析完成事情的过程。
- 面向对象OOP:所有事情交给相应的对象完成,侧重于如何创建解决问题的对象。
4.接口和抽象类的区别是什么?(重点)
不同点:
a.抽象类是一个类,用abstract class定义:
- 有构造方法,不能创建对象,在创建子类对象时调用构造方法
- 抽象类中可以有抽象方法,也可以有普通方法
- 抽象类被子类继承时,使用extends关键字。子类必须重写父类中的所有抽象方法
- 子类只能继承一个抽象类
b.接口不是一个类,用interface定义:
- 没有构造方法,不能创建对象
- 接口中的属性都是公共的静态常量
- 接口中的方法都是公共的抽象方法
- JDK1.8后,可以在接口中定义default方法和static方法
- 接口被实现类实现时,使用implements关键字。实现类必须重写父接口中的所有抽象方法
- 实现类可以实现多个接口
相同点:
- 接口和抽象类都不能创建对象
- 接口的实现类和抽象类的子类,都需要重写抽象方法
5.成员变量与局部变量的区别?以及生命周期?
- 成员变量是定义在类中的变量,有默认值,不用赋值也能使用。
- 局部变量是定义在方法中的变量,没有默认值,需要赋值后才能使用。
- 成员变量的生命周期:类创建对象,成员变量初始化;类的对象被回收,成员变量销毁。
- 局部变量的生命周期:方法开始调用,局部变量初始化;方法调用结束,局部变量销毁。
6.创建一个对象用什么运算符?对象实体与对象引用有何不同?
- 创建一个对象使用new运算符。new创建的对象实例在堆内存中,而对象引用指向对象实例,对象引用存放在栈内存中。
- 一个对象引用可以指向0个或1个对象实体,而一个对象可以有多个引用来指向它。
7.什么是方法的返回值?返回值在类的方法里的作用是什么?
- 方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果(前提是该方法可能产生结果)
- 返回值的作用:接收出结果,使得它可以用于其他的操作
8.一个类的构造方法的作用是什么?若一个类没有声明构造方法,程序能正确运行吗?为什么?
- 构造方法作用:java类中的一个用来初始化对象的方法,用new+构造方法,创建一个新的对象,并可以给对象中的实例进行赋值。
- 程序可以正确运行。因为当没有指定构造方法时,系统会自动添加无参的构造方法。
9.构造方法有哪些特性?
- 构造方法没有返回值(没有返回值这一部分,不是void),构造方法名必须和类名相同。
- 每个类默认有一个隐藏无参数的构造方法,方法体中没有内容,用于创建无参数的对象。
- 如果自己写了有参数的构造方法,默认无参数的构造方法就会失效。如果想要同时拥有带参数和不 带参数的构造方法,就需要把它们都写出来。
- 构造方法可以限制创建对象时的参数。
- 构造方法不能通过“.”操作符访问,只能通过new关键字创建对象时自动调用,所以构造方法通常用 于初始化成员变量。
10.对象的相等与指向他们的引用相等,二者有什么区别?
对象的相等是指对象所存储的内容是否相等,引用相等是指引用所指向的地址是否相等。
11.在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是什么?
目的:帮助子类做初始化工作。
12.普通类和抽象类有哪些区别?
不同点:
- 抽象类的存在时为了被继承,不能实例化,而普通类存在是为了实例化一个对象
- 抽象类的子类必须重写抽象类中的抽象方法,而普通类可以选择重写父类的方法,也可以直接调用父类的方法
- 抽象类必须用abstract来修饰,普通类则不用
相同点:
- 普通类和抽象类都可以含有普通成员属性和普通方法
- 普通类和抽象类都可以继承别的类或者被别的类继承
- 普通类和抽象类的属性和方法都可以通过子类对象来调用
13.抽象类能用final修饰吗?
- 不能。
- 因为抽象类是要子类继承然后实现内部方法的,但是final修饰的类是不能再被继承和修改的,所以不能用final修饰。
14.其他抽象相关面试题
- 抽象类的特点:除了不能创建对象外,与普通类一样。
- 抽象方法的特点:抽象方法用abstract修饰,不能有方法体,非抽象子类必须要进行重写。
- 抽象类中有构造方法吗? 有,但不是通过new该类时调用,而是在new其子类对象时调用。
- 执行某个类的构造方法时,一定会创建这个类的对象吗? 不一定。如果是普通类,在执行构造方法时,一定会创建对象;如果是抽象类,在执行构造方法时,不会创建自身对象,只会创建其子对象。
15.重载和重写的区别?
- 方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
- 方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
- 方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。