JavaEE漫漫学习路之任务篇之面向对象高级
前言
这次是真正意义的发布第一次博客,也是由于老师有要求,我又很纠结到底要不要去写博客,因为对于我而言,这条路在我毕业后不一定走,但是我现在又是学这个的,想要学好,那些博客,记录自己的学习情况又是必要的一个步骤(要不你去写笔记,用笔写)。俗话说:好记性不如烂笔头,你学习后不久的知识也许很快就会忘,所以这也是写博客的一个原因。即记录了自己的学习进度,又可以在之后的学习中回过头来复习,当然也是为了更好的理解学习的内容,毕竟都是要脸的,你发个博客,要是烂的不行,也觉得丢脸。好了,心路历程,感受先告一段落。接下来看正文。
题目一:用户登录案例
任务概述:假设用户账号为:admin,密码为 123,编写用户登陆案例。 要求:请将登陆定义为 login 方法, 并加粗样式将 login 方法写在 UserService 类中。
解题思路: 我们一看到题目,上面开头就说假设用户账户,还有密码。那我们其实就可以定义两个属性
private String name;//用户名
private String password;//用户密码
当然建议在定义属性的同时,加上无参和全参的构造方法,要不要的先不说,起码要求有,用到了直接调用就是。
public UserService(){}//无参构造方法
public UserService(String name, String password) {//全参构造方法
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
之后的要求是:定义为 login 方法, 并将 login 方法写在 UserService 类中。那我的解决方法是,创建了一个接口User,写了个login方法,之后再UserService类中去重写了一下,直接参考老师代码
User接口
public interface User {
//接口方法
boolean login(String name,String password);
}
这是重写的login方法
@Override//重写接口的方法
public boolean login(String name,String password) {
//字符串比较相等的时候将后输入的放前面,防止空指针异常
if(name.equals(this.name)) {
if(password.equals(this.password)) {
System.out.println("登录成功!");
return true;
}else {
System.out.println("密码错误!");
}
}else {
System.out.println("账号输入有误!");
}
return false;
}
搞到这里,代码要求基本完成,然后就可以测试了
public class UserServiceTest {//测试类
public static void main(String[] args) {
UserService u = new UserService();//创建对象
Scanner input = new Scanner (System.in);//控制台输入
//存放用户登录得账号及密码
String name ;
String password;
//设置账号及密码
u.setName("admin");
u.setPassword("123");
//判断用户登录情况
for (int i = 0;i<3;i++){
System.out.println("你还有" + (3-i) + "次机会");
System.out.println("请输入账户名称:");
name = input.next();
System.out.println("请输入密码:");
password = input.next();
if(u.login(name,password)) {
break;
}
}
}
}
这里参考了这位兄弟的代码:链接:https://blog.csdn.net/weixin_46312449/article/details/112733549
题目二:MyList类
2、试题:自定义一个类, 命名为 MyList,类中包含属性:Object[] element;定义如下几个方法:
- 增加方法 add : 可以向数组属性中依次存储 Object,数
组内容存满时,需实现动态扩容(详解在下面)。 参考: Boolean add(Object
obj)- 删除方法 remove : 可以根据数据或下标,从数组属性
中删除 Object 数据,删除后,数组后续 元素需前移。 参考:void remove(Object
obj) 或 void remove(Integer index)- 查询方法 get : 方法传入下标,返回数组中指定下标的
数据。
参考:Object get(Integer index)- 当前存储数据量 size : 获取当前存储的有效数据长度
参考:size=数组.length
动态扩容详解: 无需真正增加原数组的容量,只用将原内容复
制到新的大数组,然后让原数组名称重新等于大数组即 可。由于原数组数据
在堆中, 失去引用会被 GC 自动回收。(考点:如何实现数组的动态长度)>
说到了垃圾回收,那我们也可以填补一下这个知识的空缺:
- 垃圾回收器(GC),在C/C++等语言中,由程序员负责回收无用内存。
- 而Java语言消除了程序员回收无用内存空间的责任;
- JVM提供了一个系统线程(GC),用于跟踪存储空间的分配情况,检查并释放那些可以被释放的存储空间。垃圾回收器在Java程序运行过程中自动启用,程序员无法精确控制和干预。
言归正传,解题思路:首先定义一个类叫MyList,然后又说要包含一个属性Object[] element;这里就可以看出,是关于数组的,然后在往下看到它的几个方法中要求实现动态扩容,动态扩容很明显,他说要将原有的数组直接复制到新的大数组中,然后重新让原有的数组=新数组
贴图如下:
那其中的int capacity; 其实就是我们每次都要添加的最大容量,而int size;就是最终的大小了
所以我们的属性最后有:
//属性
private Object[] element;//盛放元素的数组
private int capacity;//最大容量
private int size;//实际大小
//构造方法
public MyList2() {
size=0;//实际大小默认就是0
capacity=4;//默认容量--可以自己定义
element=new Object[capacity];//分配数组的空间--数组的空间一定开辟就不能改变大小
}
接着分析说增加方法 add中可以向数组属性中依次存储 Object,数组内容存满时,动态扩容。那我们就需要思考怎么存储,怎么扩容,什么时候进行扩容。于是有了接下来的add方法
代码如下(示例):
//方法
/**
* 添加元素
* @param obj
*/
public void add(Object obj) {
if(size>=capacity){//数组内容是否存满,满了之后需要扩容
//动态扩容
Object[] newArr=new Object[capacity*2];//新数组的大小可以自己决定,比原来大就可以
//将原有数组的元素复制到新的数组中
for (int i = 0; i < element.length; i++) {
newArr[i] = element[i];
}
//让原数组名称重新等于新数组即可
element = newArr;
}
element[size]=obj;//存放元素
size++;//实际大小+1
}
同样的在往下看到了删除方法时,要求可以根据数据或下标两个方面,从数组属性中删除 Object 数据。它说删除后,数组后续元素需前移。
我们先说根据数据删除,我们在删除数据的时候第一判断就是其是否存在,判定存在则直接删除对应的对象,并返回
/**
* 根据指定的对象删除
* @param obj
* @return
*/
public Object remove(Object obj) {
//先判断该对象是否存在
for (int i = 0; i < element.length; i++) {
if(element[i]!=null && obj==element[i]) {
return remove(i);//找到对象的对应下标,remove
}
}
//如果没有
return null;//该数组中没有要删除的对象
}
然后再来说根据下标删除,这个就要求我们去明白是通过什么行为操作去通过下标来删除的,其实与其说是删除不如说是覆盖,因为本来的对象其实也没有丢失,只是被后面的对象给掩盖了。打个比方:说我和你打架,我180,160斤,你160,120斤,我上去就把你给压在了身下,旁边的人还以为我自己趴地上搞行为艺术。那别人没有看见你,但你是不存在了吗,当然不是,你只是在我下面而已,对吧。用一张图表示:
贴图如下:
那通过这个图我们应该就可以理解是怎样通过下标覆盖删除的了,代码如下
/**
* 根据下标删除
* @param index
* @return
*/
public Object remove(int index) {
//如果是最后一个元素
if(index==size-1) {
size--;
return element[index];//返回被删除的数值
}
//数组后续元素需前移
Object obj=element[index];
for(int i=index;i<size;i++) {
element[i] = element[i+1];
}
size--;//删除成功之后实际大小要-1
return obj;//返回被删除的数值
}
最后是查询的方法:比较简单,直接通过get(int index)传入下标,return一下还有getSize获取大小,打印出来就好了
/**
* 查询方法
* @param index
* @return
*/
public Object get(int index) {
return element[index];
}
public int getSize() {
return size;
}
最后是Test类
public class MyListTest2 {
public static void main(String[] args) {
MyList2 list = new MyList2();
//添加元素
for (int i = 0; i < 5; i++) {
list.add("一模一样"+i);
}
String s1="一模一样";//根据下标删除
list.add(s1);
//String s2="一模一样2";//根据指定的对象删除
//删除元素
//Object obj=list.remove(s2);
Object obj=list.remove(3);
System.out.println("删除的元素:"+obj);//根据下标删除
//获取元素
for (int i = 0; i < list.getSize(); i++) {
System.out.println(list.get(i));
}
}
}
题目三:人机猜拳游戏
任务概述: 今天的任务是通过控制台方式实现一个人机对战的猜拳游戏,用户通过输入(1.剪刀 2.石头 3.布),机器随机生成(1.剪刀 2.石头 3.布),胜者积分,n 局以后通过积分的多少判定胜负。
- 定义机器类,以及拳头属性(此属性只有三个值:剪刀,石头,布。这里的值可以使用数值代替)
- 定义生成随机数的方法(让机器生成剪刀,石头,布的值),赋值给第一步的拳头属性
- 定义测试类,获取用户输入的剪头石头布的值,和随机生成的值比较
- 测试中,定义变量保存胜者积分
重点来了各位,人机之争,万万不可不可疏忽。
解题思路:我们看任务概述说,这是一个人类和机器通过控制台猜拳,积分比赛,最终根据比分输赢的游戏。
首先第一个要求说是定义一个机器类,有3个属性,通过数值代替,那我们去想一些,我们是否需要去创建3个属性,分别是石头剪刀,布,然后set方法赋值,还是说我们直接去通过给3个值定义这3个属性呢?都可以兄弟们,但是我的能力有限,我是看到这个题目的时候就想到了之前老师的那个快递E栈(现在没开始去写那个博客,等以后吧)的方法,毕竟都是通过控制台输出的。然后我就首先想到了这个
public static void menu(){
while(true) {
int id = starMenu();
if(id==0) {
return;
}
}
}
然后我就按照这相同的思路一步一步实现到最后
//判断赢家方法
public static String ScoreMenu() {
Scanner input = new Scanner(System.in);
System.out.println("用户的积分:" + p.getScore());
System.out.println("机器的积分:" + m.getScore());
if (p.getScore() > m.getScore()) {
return "人类领先";
} else if (p.getScore() == m.getScore()) {
return "人类和机器打平";
} else {
return "机器赢";
}
}
最后的时候发现p对象为空,出现了一个空指针异常,因为我是按照原本的快递E栈的实现方法写的(那个是数组),然后我很苦恼,去网上找了好久,也没有解决,最后是去出现写个类,不用static静态去创建方法之后,去调用原本的Game才算是完整
注意:以上都是发牢骚,接下来才是真正的解题
思路不变,首先创建三个类,一个人类,一个不是人类(机器),一个是游戏类,分别在人类类与机器类中构造无参和全参方法,当然也创建他们共有的一个属性,都有积分,在人类类中通过创建said方法,写个循环,由于不知道到底进行多少次,所以用while循环,然后嵌套一个switch(这个网上都要,直接参考),选择情况1,2,3,,分别表示剪刀,石头,布
public class People {
private int score;
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public People(){}//无参构造方法
public People(int score) {//全参构造方法
this.score = score;
}
public int said(){
Scanner input = new Scanner(System.in);
System.out.println("游戏开始:");
while (true){
System.out.println("人出拳的方式:1、剪刀,2、石头,3、步");
int num = input.nextInt();
switch (num){
case 1:
System.out.println("人出剪刀");
break;
case 2:
System.out.println("人出石头");
break;
case 3:
System.out.println("人出布");
break;
default:
System.out.println("你是不会玩吗?");
break;
}
return num;
}
}
}
同理:机器类
public class Machine {
private int score;
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public Machine(){}
public Machine(int score){
this.score = score;
}
public int say(){
Scanner input = new Scanner(System.in);//获取控制台输入
while (true){
System.out.println("机器出拳:1、剪刀,2、石头,3、布");
Random r = new Random();
int num = r.nextInt(3);
switch (num){
case 1:
System.out.println("机器出剪刀");
break;
case 2:
System.out.println("机器出石头");
break;
case 3:
System.out.println("机器出布");
default:
System.out.println("机器出故障了,请重新输入");
break;
}
return num;
}
}
}
这里要讲一下,随机数问题,我们可以通过
Random r = new Random();
int num = r.nextInt(3);
这两步来产生随机数,并使num接收
参考链接:https://www.cnblogs.com/phpyangbo/p/java-suijishu.html
这位哥哥正好也是有讲猜拳游戏的,大家也可以参考,学习嘛,就是到处看,到处找过来敲
OK,往下看,接下来通过创建startMenu方法首先实现起始界面。
public int starMenu() {//起始界面
System.out.println("=====欢迎参加人机对战猜拳游戏======");
System.out.println("用户输入:");
System.out.println("请输入您的操作:1-开始游戏,2-查看比分,0-退出");
int id = 0;
while (true){
id = input.nextInt();//接收id
if(id == 1) {
GameMenu();
break;
}else if(id==2) {
ScoreMenu();
break;
}else if(id==0){
System.out.println("谢谢使用");
return 0;
}else {
System.out.println("选择有误,请重新输入!");
}
}
System.out.println("本次游戏已结束!");
return id;
}
这是最终实现的,起始在刚开始,我们肯定要去填充id==1的GameMenu,按照要求,人类先出手,然后我们直接通过number1与number2调用人类类的said方法和机器类中的say方法,通过if else if else 判断输赢情况
public void GameMenu() {//游戏界面
System.out.println("人类优先出拳:");
int number1 = p.said();
int number2 = m.say();
if ((number1 == 1 && number2 == 3) || (number1 == 2 && number2 == 1) || (number1 == 3 && number2 == 2)) {
System.out.println("人类胜利");
p.setScore(p.getScore() + 1);
} else if (number1 == number2) {//平局
System.out.println("二者平局!");
} else {
System.out.println("机器侥幸!");
m.setScore(m.getScore() + 1);
}
}
之后是填充id==2的积分界面,在设计中我是首先将现在的积分情况打印出来,之后通过再一个if else if else 来比较最终结果,结束比赛。
//积分排名
public void ScoreMenu() {//积分界面
Scanner input = new Scanner(System.in);
System.out.println("用户的积分:" + p.getScore());
System.out.println("机器的积分:" + m.getScore());
System.out.println("最终对战结果如下:");
System.out.println("人类 :\t机器");
if (p.getScore() > m.getScore()) {
System.out.println("人类领先");
} else if (p.getScore() == m.getScore()) {
System.out.println("人类和机器打平");
} else {
System.out.println("机器胜利");
}
}
Game类完整代码如下:
public class Game {
public Scanner input = new Scanner(System.in);
public Random random = new Random();
private People p;
private Machine m;
public People getP() {
return p;
}
public void setP(People p) {
this.p = p;
}
public Machine getM() {
return m;
}
public void setM(Machine m) {
this.m = m;
}
public Game() {
this.p= new People();
this.m = new Machine();
}
public Game(People p,Machine m) {
this.p= new People();
this.m = new Machine();
}
public void menu(){
while(true) {
int id = starMenu();
if(id==0) {
return;
}
}
}
public int starMenu() {//起始界面
System.out.println("=====欢迎参加人机对战猜拳游戏======");
System.out.println("用户输入:");
System.out.println("请输入您的操作:1-开始游戏,2-查看比分,0-退出");
int id = 0;
while (true){
id = input.nextInt();//接收id
if(id == 1) {
GameMenu();
break;
}else if(id==2) {
ScoreMenu();
break;
}else if(id==0){
System.out.println("谢谢使用");
return 0;
}else {
System.out.println("选择有误,请重新输入!");
}
}
System.out.println("本次游戏已结束!");
return id;
}
public void GameMenu() {//游戏界面
System.out.println("人类优先出拳:");
int number1 = p.said();
int number2 = m.say();
if ((number1 == 1 && number2 == 3) || (number1 == 2 && number2 == 1) || (number1 == 3 && number2 == 2)) {
System.out.println("人类胜利");
p.setScore(p.getScore() + 1);
} else if (number1 == number2) {//平局
System.out.println("二者平局!");
} else {
System.out.println("机器侥幸!");
m.setScore(m.getScore() + 1);
}
}
//积分排名
public void ScoreMenu() {//积分界面
Scanner input = new Scanner(System.in);
System.out.println("用户的积分:" + p.getScore());
System.out.println("机器的积分:" + m.getScore());
System.out.println("最终对战结果如下:");
System.out.println("人类 :\t机器");
if (p.getScore() > m.getScore()) {
System.out.println("人类领先");
} else if (p.getScore() == m.getScore()) {
System.out.println("人类和机器打平");
} else {
System.out.println("机器胜利");
}
}
}
之后通过Test类,调用menu,输出控制台进行比赛
public class Test {
public static void main(String[] args) {
Game game = new Game();
game.menu();
}
}
接下来是比赛结果:
经过漫长的比赛,最终人类赢得了胜利,让我们为人类的胜利欢呼吧
总结
到了这里,我们的任务也算是告一段落,其实通过这次任务也算是复习了一遍我们在这段时间进行的学习,当然很多的没有复习到,而且在完成任务也不是独立完成的,我承认我是菜鸟,好了,慢慢来吧,且学且看吧,指不定,嘿嘿,我不学了,我换行。啊!!!