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

原题目中有个**注意:**处理输入的时候使用混合使用nextIntnextLine需注意行尾回车换行问题。

我一开始看到了,也没太注意,当时输入问题也没仔细分析,大致略过,果然做的时候就出问题了。

分析一下输入数据,第一行是待输入数据种类的个数,如果再输入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 output
        output = 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 {//感觉相当于继承了接口。
    @Override
    public void eat() {
        System.out.println("Dog eats meat.");
    }

    @Override
    public 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号考试,就光写了这篇文档,自己简单复习了一下,很轻松就做完了。一定要抱有主动学习的思想,而不是被动学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值