文章目录
- Java期末考试准备
- 一、Java的输入
- .next()输入
- .nextLine()输入
- 区别
- 补充
- 二、Java的输出
- 三、类中常写方法
- toString()
- equals()
- 其他
- 四、容器/数组
- 五、继承
- 六、静态属性、方法.
- 七、抽象类
- 八、接口
- 九、初始化模块
- 十、泛型
- 考完结束语
- Java学习历程
注:这篇文章本来是写给同学的,想了想都是用markdown写的,顺手直接发csdn了。文章里有些话用的"你",指的是我同学。文章需要有一定java基础的来看,如果什么也没学的话,可能比较吃力。
Java期末考试准备
注意,别光看,一定要自己再去动手写写,要不然考试的时候自己写还是写不出来。
一、Java的输入
.next()输入
关于.next()输入,有下面这几种方法:
import java.util.*; //导入所有模块,可以尝试一下.
public class Main{public static void main(String[]args){Scanner sc = new Scanner(System.in);String s = sc.next(); //用于获取下一个字符串的.int a = sc.nextInt(); //用于获取下一个整数的double b = sc.nextDouble(); //用于获取下一个double类型的//等等.}
}
这些都是属于.next()输入的,以空格或者回车为间隔。什么意思?比如我想获取下列数字:
1 2 3 4
注意到,这4个数字是以空格为间隔的,所以我们可以使用四次.nextInt()来获取,就像下面这样:
int a = sc.nextInt();
int b = sc.nextInt();
int c = sc.nextInt();
int d = sc.nextInt();
而如果提示输入数据是这样的:
1
2
3
4
我们同样可以使用上面同款输入方式来获取数据.
当然,如果给出的是字符串类型的,我们只需要将.nextInt()换成.next()就行.这些都是属于同一种类型的。
.nextLine()输入
这个是用于读取一行的。
如果输入纯字符串(没用空格的),我们可以使用这种方式获取。比如下面的数据:
ajgoaogeg
eaofewgnge
egnaoenge
直接使用三个.nextLint()赋值给String类型变量就行.
String a = sc.nextLine();
String b = sc.nextLine();
String c = sc.nextLine();
如果有空格的字符串(先不考虑整型),可以一次性获取,并赋值给字符串类型数组:
aa aaaa ffg agge faef fasf
aef feaf efe ffefjo eeof efojfj
注意看下面的操作方式,不用循环就能全部获取.
String [] a = sc.nextLine().split(" ");
String [] b = sc.nextLine().split(" ");
不知道你python写的多不多.split()在python输入中用的比较多.分析一下可以知道.nextLine()返回的String类型,是一个字符串整体.而.split(" “)代表按照空格将字符串切割,返回类型是String数组类型。所以我们可以直接定义一个String类型数组,并接受被split(” ")按照空格切割了的字符串。
如果输入整型怎么办?像下面这样:
1 2 3 4 5
1 9 4 98 2 4
38 23 290 20 40 2
当然我们可以通过循环,一个一个地通过.nextInt()获取并存入整型数组中,也有更简单的方法,就是读取一行,按照字符串读取,并且再强制转化为整形,如下所示:
String []a = sc.nextLine().split(" ");
String []b = sc.nextLine().split(" ");
int []c = new int[a.lenth];//数组定义方式.
int []d = new int[b.length];
for(int i = 0; i < a.length; i++){c[i] = Integer.parseInt(a[i]);//Integer.parseInt是专门将字符串转为整形的。同理,Double.parseDouble也是.
}
for(int i = 0; i < b.length; i++){d[i] = Integer.parseInt(b[i]);
}
另外,不要太死板,有些题目可能会以其他的为间隔,比如用;当做间隔,这样只需要将.split(" “)变为.split(”;")就行了.
区别
上面说了两种输入方式,.next()和.nextLine(),我们先称为方式一和方式二吧。一道题目中,要么只使用方式一,要么只使用方式二。能不混用就不混用。如果不得不混用,那么一定要清楚产生的异常。
举个题目的例子吧,2024自由复习第八题.
输入如下所示:
4
rect
3 1
rect
1 5
cir
1
cir
2
原题目中有个**注意:**处理输入的时候使用混合使用nextInt
与nextLine
需注意行尾回车换行问题。
我一开始看到了,也没太注意,当时输入问题也没仔细分析,大致略过,果然做的时候就出问题了。
分析一下输入数据,第一行是待输入数据种类的个数,如果再输入rect就是代表长方形,需要再获取长宽,如果再输入cir是指圆形,需要获取其半径。
我一开始是这么做的:
Scanner sc = new Scanner(System.in);n = sc.nextInt(); //个数String data ;ArrayList<Shape> l = new ArrayList<>();//相当于vsctor,类型是Shape类型(定义的类)for(int i = 0; i < n; i++){data = sc.nextLine();//这里是读取下一行if(data.equals("rect")){l.add(new Rectangle(sc.nextInt(),sc.nextInt()));//分别再读取两个整数,也就是我们一开始说的next()输入}else{l.add(new Circle(sc.nextInt()));}}
发现存在输入问题。可是并不知道问题在哪。分析后才知道,要么使用nextLine一行一行读取,要么使用next一个一个读取.
所以解决方法也有两个,第一个就是将上面第六行代码,换成下面这个:
data = sc.next();
其实就相当于避免了混用产生的影响。
另一个是混用,但需要.nextLine()吸收多余回车,类似于C++中getchar()吸收回车。
Scanner sc = new Scanner(System.in);n = sc.nextInt(); //个数String data ;ArrayList<Shape> l = new ArrayList<>();//相当于vsctor,类型是Shape类型(定义的类)sc.nextLine();for(int i = 0; i < n; i++){data = sc.nextLine();//这里是读取下一行if(data.equals("rect")){l.add(new Rectangle(sc.nextInt(),sc.nextInt()));//分别再读取两个整数,也就是我们一开始说的next()输入sc.nextLine();}else{l.add(new Circle(sc.nextInt()));sc.nextLine();}}
我加了三个.nextLine,for循环中有俩.对于为什么要在for循环中再添加,因为每次循环都还要nextLine一下,所以还是需要再吸收一下回车。
刚才又想了想,可以再优化一下,只需要一个nextLine就行。如下:
Scanner sc = new Scanner(System.in);n = sc.nextInt(); //个数String data ;ArrayList<Shape> l = new ArrayList<>();//相当于vsctor,类型是Shape类型(定义的类)for(int i = 0; i < n; i++){sc.nextLine();data = sc.nextLine();//这里是读取下一行if(data.equals("rect")){l.add(new Rectangle(sc.nextInt(),sc.nextInt()));//分别再读取两个整数,也就是我们一开始说的next()输入}else{l.add(new Circle(sc.nextInt()));}}
将nextLine放到nextLine前面就行了。
再详细的输入题目练习的时候跟着练就行,我这里就不再说了。
补充
还有就是循环输入问题。如果给定输入个数,使用for循环输入就行,可如果不给定个数,C++中又while(scanf()!=EOF),Java中也有类似的。hasNext().如果是一行的话,就是hasNextLine,整数的话hasNextInt,一样的。具体表示如下:
while(sc.hasNext){a = sc.next();
}
题目例子的话是2024自由复习编程第二题.终止输入跟C++一样,ctrl+Z就行。
二、Java的输出
输出方式有下面几种:
System.out.printf("%d%.2f",a,b) //正则输出,跟C++中表示方法一致。
System.out.println()//输出一行,自动换行,但是缺少格式化控制
System.out.print()//没怎么用过,一般常用的是上面两个.
输出是非常非常灵活的。我们肯定不能只限于上述方式。Java中,String中也有格式控制方式。如下:
String.format("%d%.2f",a,b)//正则String格式化.使用方式跟printf一致,只不过这里不输出,而是调整格式。
String.join("",)//.join()方式,python中有的,不知道你是否熟练,非常好用。
上面两种方式,结合java输出,什么类型都能完美输出了。
前者一般结合在类中toString里,后者则是控制符,用于数组、vector等的输出,不用使用循环,只需要.join()即可。比如:
String[] a;//这是一个数组,
ArrayList<String> b = new ArrayList<>();//这是一个vector。
//我们假设上面有数据,并且想以空格为间隔输出。
String output1 = String.join(" ",a);
String output2 = String.join(" ",b);
System.out.println(output1);
System.out.println(output2);
好处是避免了循环输出中产生多余空格。
如果是整形输出的话,我会将其转化为String类型,然后再.join()输出。上面说了String强转int使用Integer.prase(),int强转String是用String.valueOf().这两个比较常用,最好记住。当然后面还会再总结一下的。
注意,这俩都是String类型的,其他类型的不可以用,但是转化为String类型后就可以用了。
有一个很好的例子,在实验题中,可惜实验题打不开了,也没记录下来。
又找到一个,我们来看看。
//部分输出如下:
[Rectangle [width=3, length=1], Rectangle [width=1, length=5], Circle [radius=1], Circle [radius=2]]
这是2024自由复习第八题。这是其中输出的一部分,由于你没看题,直接分析也不现实,我们先来拆解一下。
//先拆解第一层[],有下面几种
Rectangle [width=3, length=1]
Rectangle [width=1, length=5]
Circle [radius=1], Circle [radius=2]
//上面三个其实就是对应类的toString(),直接返回的,并不困难.
//第一层是[],中间有三个toString(),三个toString()是由", "所分隔.
我的做法.
for(int i = 0; i < l.size(); i++){ a.add(l.get(i).toString());//l是ArrayList类型,相当于vector} //java中的ArrayList无法直接通过下标[i]访问,只能.get(i)获取对象//所以a中存储的就是上面说的toString()String output = String.join(", ",a);//这里使用.join()将a中元素根据", "切割,并组成新String outputoutput = String.format("[%s]",output);//这里又将output格式化一下,添加了[]System.out.println(output);//直接输出output,没有多余动作,干净整洁.
当时做的时候很自然就出来了,熟练之后想怎么输出就怎么输出。
当然,也可以用其他方法输出,不是唯一的 方法,思维也不要受限,如果不熟练,使用.join()输出不了,就直接循环输出就行。
三、类中常写方法
toString()
这个是最常见的,几乎设计到面向对象问题都会重写这个方法,当然也是最简单的。
我们可以直接return 字符串,并且通过+号将多个字符串拼接,但是我还是建议使用String.format().如下所示:
class Person{private String name;private int age;private String sex;public Person(){}public Person(String name, int age, String sex){this.name = name;this.age = age;this.sex = sex;}public String getName(){return name;}public void setName(String n){name = n;}public int getAge(){return age;}public void setAge(int a){age = a;}public String getSex(){return sex;}public void setSex(String s){sex = s;}public String toString(){return String.format("Person [name=%s, age=%d]",name,age);}
由于跟C++中printf一致,所以也没什么上手难度,直接用就行。
注意!!!
如果类中有一个boolean(布尔)类型变量,使用的话是%b,其他的都会报错!!!
如下:
Person{...private boolean sex;...public String toString(){retrun String.format("%b",sex);}
}
equals()
重写这个方法,动作十分十分固定。熟悉后就无敌了。
具体题目:作业6函数题第一个
最好自己动手写写。非常非常经典。
首先传入的对象是Object obj,一定是它,而不是其他的类。之后,需要判断是否是对象本身,是的话返回true。然后再判断传入对象是不是空(null)或者是不是同一个类型,如果不是,返回false。之后强制转化为本类,然后再判断对应属性。
上面说的动作是固定的。如下:
public boolean equals(Object obj){if(this == obj) return true; //实在不理解背过就行else if(obj == null||getClass() != obj.getClass()) return false; //这里也是,不理解背过就行,固定动作Book other = (Book)obj; //这里是强制转化。这个类是Book类,所以将obj强制转化为Book}
**注意!!**上面的内容是固定的,一定要记住。对应题目一定要多写写。我当时差不多重写了三四遍,之后再遇到equals问题没再错过。
完整过程如下:
class Book{private String name;private int value;private String auther;private int id;public Book(String name, int value, String auther, int id){this.name = name;this.value = value;this.auther = auther;this.id = id;}public String toString(){return String.format("name: %s, price: %d, author: %s, edition: %d",name,value,auther,id);}public boolean equals(Object obj){if(this == obj) return true;else if(obj == null||getClass() != obj.getClass()) return false;Book other = (Book)obj;//切割//之后就只需要判断对应属性是否相同就行了。注意,Java中String的判断没有重载==,需要用.equals()!!String temp_name1 = other.name.strip().toLowerCase();//.strip()指去除多余空格.toLowerCase()是转化为小写String temp_name2 = this.name.strip().toLowerCase();//题目中说了不关心大小写、空格,所以才做这两个动作,if (!temp_name1.equals(temp_name2)) return false;//一般情况下不需要这两个动作.String temp_auther1 = other.auther.strip().toLowerCase();String temp_auther2 = this.auther.strip().toLowerCase();if (!temp_auther1.equals(temp_auther2)) return false;return other.id == this.id;}
}
其他
之后就是getter、setter了,面向对象中都涵盖的。其他需要重写的方法似乎也没有了。
四、容器/数组
容器用多了,我几乎也不怎么使用数组了。知到数组定义就行了。
int[] a = new int[n] //如果知道数组大小,直接初始化就行。
int[] a //如果不知道数组大小,先这么定义就行
//需要注意的是,初始化千万别忘了new!
数组排序有Arrays.sort(),直接传入数组就行。当然,题目中一般会给出来。这里也可以自定义排序,比如定义了一个学生类的数组,我可以自定义先按照成绩排序,成绩相同再按照姓名排序。不过数组的自定义排序我不会,我只会容器自定义排序。pta中有个函数是数组自定义排序,如果出了直接放弃。
容器常见的有ArrayList,使用如下:
ArrayList<String> a = new ArrayList<>();//初始化定义.将其视为vector就行
//注意,java的ArrayList中没有vector中的resize,提前开辟空间的方式,不过可以通过其他类来实现这一目的.之后再说.
a.get(i) //获取第i个元素(注意要有值才能获取)
a.set(i,n)//给第i个元素设值
a.add(n)//相当于vector的pushback()//接下来都是使用到Collections类,需要提前导入!
//注意,Collection服务的是容器类,而不是数组!//排序
Collections.sort(a);
//逆序
Collections.reverse(a);
//默认从小到大输出,如果想从大到小输出,如下.当然下面的a是int类型容器
Collections.sort(a, Comparator.reverseOrder());
//如果想按照类中某部分排序,比如学生类成绩,然后再按照姓名排序:
Collections.sort(a,Comparator.comparing(Student::getScore).thenComparing(Student::getName))//上面的特殊排序方式有很多,我的这个方式算是最简单的了.
具体题目似乎在实验里有。当然,排序也可以直接用List接口,但本质上与Collections排序还是一样的,建议按照上面的方式来写就行。
容器还有Map,就是C++中的map.
有一个Map类型好的题目,作业6编程题第一题。我答案直接贴在下面吧。
import java.util.*;public class Main{public static void main(String[] args){Scanner sc = new Scanner(System.in);String input = sc.nextLine();String []data = input.split(" ");Map<String,Integer>map = new HashMap<>();//map的定义,固定化的.for(String ans :data){map.put(ans,map.getOrDefault(ans,0)+1);//这里是赋值.python中有字典,字典的.get()方法跟这里的.getOrDefault()方法几乎一模一样.如果明白.get(),这里就不难理解.我放到外面讲解吧.}ArrayList<Map.Entry<String,Integer>>list = new ArrayList<>(map.entrySet());Collections.sort(list,Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed());for (Map.Entry<String,Integer> m:list){System.out.printf("%s:%d\n",m.getKey(),m.getValue());}sc.close();}
}
上面的代码第一次弄可能看不太懂。首先是map赋值.对于map.put(ans,map.getOrDefault(ans,0)+1)
.put是专们给map赋值的.其中键是ans.如果ans存在,可以直接使用.put(),如果不存在就可以使用.getOrDefault(),含义就是如果这个键存在,则获得这个键对应的值,如果不存在,那么就给它设个默认值。比如map.getOrdefault(ans,0),就是ans不存在的话,就设立新值为0,存在的话就获取其对应的值。那么这个整体,其实就实现了+1的效果。比如我想统计有这本书的人数。一开始肯定没有,所以设立了默认值为0.有了第一个人后,则逐渐+1.
Java中的map,不能像C++一样灵活访问,比如map[i]这样,我们想访问键、值,必须使用其接口.而且由于无法直接访问键和值,所以通过Collections直接排序比较困难。因此需要转化一下。ArrayList<Map.Entry<String,Integer>>list = new ArrayList<>(map.entrySet());
这个含义就是,创建了个list,是容器类型,并且是以map.entrySet()为初始值的。需要注意其类型为Map.Entry<String,Integer>。注意.entrySet()是map的接口,而Map.Entry<String,Integer>是这个接口的类型。有了这个接口,我们就能 访问其键和值了.Collections.sort(list,Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed());
这个排序就跟上面排序一样了,需要注意是类型为Map.Entry<String,Integer>.
还有个集合容器Set具体题目:
2024自由复习编程第一题
五、继承
很幸运,Java不支持多继承(考试中有个题目,说java支持多继承,可以通过什么方式实现。我记得看书上说不支持多继承,你们可以再查阅一下),所以没有C++那种花里胡哨,像什么虚拟继承等等。python的面向对象也支持多继承,但是《python面向对象编程》中也明确说了,当你发现你需要多继承时,一定想复杂了(大致是这个意思吧).
extends //子类继承父类时需要的.
//例如
class Person{}
class Student extends Person{}
具体题目时2024自由复习函数题2
super//这个是用来承接父类的。举个例子:
class Person{private String name;public Person(String name){this.name = name;}public String toString(){return name;}
}
class Student extends Person{private boolean sex;public Student(String name,boolean sex){super(name);//暗自调用父类构造函数this.sex = sex}public String toString(){return String.format("Person[%s,%b]",super.toString(),sex);//调用父类的toString方式.}
}
super非常好用。如果父类属性很多很多,而且构造函数十分复杂,我们可以直接使用super调用父类的构造方法。另外,我们重写了的父类方法,子类中也可以使用super调用,比如上面的toString。在equals判断中也可能用到。我们同样也只需要调用super.equals(obj),就行。
我记得实验有好几个,可惜实验关闭了。
当然,有继承也就有组合。组合问题也是在实验里,没有了。
六、静态属性、方法.
跟C++中的类似。不过我也不清楚你理解的怎么样。本来我也不明白,后来我深入学习python面向对象的时候,突然明白的。python中类中所有方法第一个参数都是self(相当于java和c++中的this,代表当前对象),而其静态方法却不需要传入self。这其实就代表这个方法不论放在类里面还是外面,都是一样的,通过类名可以直接调用(当然,类外就不行),而放在类中其实也是起到封装思想。
具体题目作业四第三题.
七、抽象类
感觉类似多态。我也不确定哈。抽象类中可以定义抽象方法。别的类继承它了之后,可以完善定义的抽象方法。本来pta中有题目的,怎么都找不到了。。
2024自由复习函数题第二题,给定的函数中定义了抽象函数和抽象方法。这个也是一定要会的。
具体可以Ai查询Java抽象类、抽象方法举例,看看它怎么写的。
八、接口
一开始忘了名字了,记得上周做的测试里有,发现测试打不开了,实验中也有,实验也打不开了。。。
整体上方法也比较固定。
public interface Animal {//接口定义void eat(); void sleep();
}
public class Dog implements Animal {//感觉相当于继承了接口。@Overridepublic void eat() {System.out.println("Dog eats meat.");}@Overridepublic void sleep() {System.out.println("Dog sleeps in the kennel.");}
}
就需要记两个关键字就行,interface,使用时是implements.
还有很多东西,比如异常、2024自由复习后面几个题等等,我也不太熟悉。实验题我全都做完了,有很多很多好的题目,很可惜,访问不了了。
九、初始化模块
这个比较简单,有普通初始化模块,也有静态舒适化模块,ai一下看看就行。
十、泛型
这个也是比较有意思的,我们学校这部分补考,但是仍然是很有必要的,我这里就不举例了。
记住,一定要多动手写,不要只看看就以为自己会了。
考完结束语
哎,难度不大,会了上面说的内容就行了。泛型、接口也没考,排序问题也没涉及。跟C++比起来难度低了太多了。当然,这是我们学校这么考的,你们的学校我也不清楚。
最后附我们学校的实验题,只有题目,没有答案,想做的可以练练手。2024自由复习中也有很多好题目,面向对象、继承、组合、接口、泛型、抽象类等等,2024自由复习中都涵盖。可是最后截止之前我还想着是否考虑保存一下,也没保存,现在没权限访问了,只有之前记录的实验大题。
实验题目
最后我想说,怎么考试中strip怎么用不了啊,平时作业能用,考试却用不了。。。
Java学习历程
整体来看,前前后后学了30h左右吧,其中7h是基础学习,看书什么的,后续经过了一周23h的深度学习,基本面是掌握了,学校出的题目大部分自己能单独做出来,不过广度和深度都较浅,只能应付学校出的题目,自己开发还是有些欠缺。注意,我这23h不是看视频学习什么的,而是纯敲代码,做老师给的题目。其中当然也包含了思考、查询解决方法的时间。很幸运有ai,能解决我各种各样的问题(当然不是一开始把题目复制给ai,让它解决,而是自己先解决,实在不行了再问ai,看看解题方法有什么不同)
由于学过C++、Python面向对象,所以Java学习来也不是特别的困难,一些思想总存在重合的地方,极大地提升了学习java的速度。初期时在vscode中运行java会存在乱码问题,而且不知道如何运行。结合ai能解决这些问题,但是回过头去想想还是让人头大,也浪费了不少时间。好在找到了合适的解决方式,从而能顺利学习下去。
第一次学java,没有其他语言基础,可能会存在一个问题,java有这么多类,我是否需要背过它们呢?
我第一次产生这个问题是学C语言的时候,由于还没入门,学到strcmp等等方法的时候,我不知道是否要背过。因为记忆性东西我是十分不愿意去背的,所以也就没记,只知道它们的作用,一般情况下也不会去用。最后C语言上机考试的时候,舍友卡bug,卡出来了一道期末题,我们只能找到答案,不知道实际具体题目。舍友们几乎也都背过了,我也想背,可是确实记不住。我是偏向于理解性记忆,理解领悟了,自然而然地就记住了。后来也明白了,像这种逻辑性问题解决方法,靠强行背过肯定走不长远的,背代码一定不是程序员的终途。
后来学习python的时候,基础知识是没太大问题,可是深入学习各种库的时候,遇到了跟strcmp类似的问题:python有各种各样的库,而库中又有各种各样的类,是要背过吗?这跟那些逻辑性问题解决的代码又有很大的不同,因为这些类的方法是固定的,背过了,一定就有用到。所以带着这样的疑问,我第一次尝试去学习python的manim库。过程十分艰辛,我也不细说了,最后我才领悟了,各种各样的类肯定也不是靠背过的,而是熟能生巧,一次又一次的实践重复中,掌握的。
所以在上面计算机学习过程经历中,领悟了挺多东西。后续学习java的时候,也是各种各样的类、方法,我并没有强行记忆,而是在做题中慢慢领悟其作用,直至掌握。
下面附上我深度学习一周的记录图吧。
这些学习时间都是做题时间,我也没看过java视频。测试了一周学习时间记录,为暑假充分利用时间做准备。最后临近考试就没再记录了。C++不是一点没学,算法都是用C++写的。另外11号之后就没再写过java了,最后16号考试,就光写了这篇文档,自己简单复习了一下,很轻松就做完了。一定要抱有主动学习的思想,而不是被动学习。