(一)需求和规格说明

问题描述:
这是一款帮助学生背单词的小软件。建立单词库:
第一个功能是学生帮助学生记单词,会显示单词库中单词的拼写、音标、词性、中文翻译,学生可以选择中途退出,再次进入的时候,可以从上次退出的位置继续,也可以重新开始,如果没有上一次的记录,则重头开始。
第二个功能是测试,有四种模式可以选择,一种是隐去单词部分字母,一种是给出中文然后默写单词,一种是给出单词选择对应的中文翻译,一种是给出翻译然后选择对应的单词。
第三个功能是增加单词,可以一个一个单词的增加,也可以读取文件增加。
第四个功能是删除单词,只能一个一个单词的删除。
第五个功能显示单词库中的所有单词。

编程任务:
(1)建立单词库,并可以方便地对单词库进行增加、删除。
(2)随机读取一个单词,随机隐去单词中的一些字母,规则是:长度为2~4空一个字母,5~7空二个字母,8~10空三个字母,11以上空四个字母。用随机数方式确定隐去哪几个位上的字母,并在屏幕上显示带空格单词。
(3)用户填充空格处的字母,程序判断填充是否正确。
(4)当用户结束游戏时,统计正确率,并输出相应的鼓励语句。
(5)随机读取一个单词,给出音标、中文翻译、词性,默写出相应的单词。
(6)随机获得单词库中一个单词的翻译,再随机选择三个单词,将四个单词随机排列,从中选择翻译对应的单词。
(7)随机获得单词库中一个单词,再随机选择三个单词的翻译,将四个单词的翻译随机排列,从中选择正确的翻译。
(8)增加单词,有增加单个单词和读取文件两种方式,读取文件不需输入文件名,只要按照需求建立指定文件并按照固定格式存储即可。
(9)删除单词,只要输入需要删除单词即可,对于该单词的所有信息都会删除。

注:由于单词中空格不容易辨认,故将空格改为下划线。

(二)设计

1.设计思想
在本次大作业中,采用excel表存储数据,通过pandas.read_excel获取excel表中的数据中,存储在一个DataFrame中,后续所有的操作都在这个Data Frame中完成,最后在完成操作后,将内容写回读取的excel表。
一级菜单包含五部分:1.记单词或测试,2.增加单词,3.删除单词,4.显示所有单词,5.退出。在第一部分中,包含除返回外的四个功能,默写单词、填补单词、根据单词选翻译、根据翻译选单词。在增加单词部分,包含增加单个单词和读取文件增加单个单词,如果选择增加单个单词,则单词、音标、词性、翻译全部需要自己输入,如果选择以读取文件的方式增加单词,则需提前准备好相应的文件,运行时仅需选择相应功能即可。删除单词时仅有删除单个单词这一个功能,仅需输入该单词即可,相关的音标、词性和翻译会一次性删除。

2. 设计表示
函数:
数据类型 函数名称 描述
void My_menu() 显示主菜单,一级菜单
void Recite_words() 显示二级菜单1,对应主菜单的第一个选项,可以进行记单词和测试
void recite_words(num) 选择记单词的方式,如果输入为1,则从头开始记单词,如果输入为2,则从上次退出的地方继续记单词,如果没有之前的记录,则判定为从头开始,如果输入为其他数字,则由Recite_words()判定并反馈
void Stop_recite(num) 输入的数字是单词的编号,以此记录本次记单词退出的位置,内容将会写入文本文档中,如果下次需要继续,则直接调用文件中记录的内容
void write_word_from_memory(choice_num) 选择测试的功能后,如果输入为1,则隐去部分字母,需要补全字母,并统计正确率,如果输入为2,则给予提示(音标、词性、翻译),要默写出单词,如果输入为其他数字,则由Recite_words()判定并反馈
void judge_translate_from_word(choice_num) 选择测试的功能后,如果输入为3,则根据单词的翻译,从四个单词的选项中选择正确的单词,并统计正确率,如果输入为4,则根据单词,从四个翻译中选择与该单词对应的翻译,如果输入为其他数字,则由Recite_words()判定并反馈
boolean judge_in_words(string) 判断输入的字符串(单词)是否在单词库中,如果在则返回False,如果不在则返回True
DataFrame Add_words() 显示二级菜单2,对应主菜单的第二个选项,可以进行单词添加,可以选择单个单词或者读取excel文件的方式添加单词
void Show_all_words() 显示单词库中的所有单词,对应主菜单的第四个选项
DataFrame Delete_words() 显示二级菜单3,对应主菜单的第三个选项,可以进行单词删除,输入单词后,在单词库中寻找,没有找到则返回原来的dataframe,如果找到则返回删除单词后的dataframe

3. 核心算法
核心算法主要是在记单词和测试、添加单词和删除单词三个部分。
1、在记单词和测试部分:
在记单词部分,如果是从新开始,则直接设置在Dataframe中开始的位置为0,如果是从上一次继续,则读取文件中记录的数字,如果读取到了,则将遍历Dataframe的开始位置设置为读取到的数字,如果没有读取到,则同样设置开始位置为0,从头遍历。在没有遍历完Dataframe的情况下,会持续遍历Dataframe的数据,打印出其中所有的数据,在循环中,如果选择停止,则会记录停止的位置到相应的文件中,然后退出,如果选择继续,则会打印输出下一个单词的信息,如果输入不符合规范,则打印提示,需要重新输入。
在测试部分,如果选择隐去单词部分字母,先建立一个空列表(列表1),在列表长度小于dataframe的行数时,处于循环中,在循环内,先生成一个规定范围的随机数,规定范围是dataframe行号范围,如果随机数在之前生成的列表(列表1)中,则重新生成,如果不在,则将该随机数添加到列表(列表1)中,添加之后,首先获得随机数对应dataframe处的单词,获得单词的长度,根据规则获得需要隐去字母的数量,然后生成随机数,获得相应数量的的随机数,放置到新的列表(列表2)中,对新的列表(列表2)中的数据排序,根据列表(列表2)数据将单词中指定位置的字母替换成下划线并打印出,根据输入字母判断是否正确,统计并计算正确率,根据正确率输出鼓励的话。
如果选择默写单词,在将随机数添加到列表(列表1)中后,直接打印出dataframe该位置单词的词性、音标、中文翻译,然后根据输入的单词判断是否正确,计算正确率,输出鼓励的话。
如果选择根据翻译选单词,开始流程与前面相同,在将随机数添加到列表(列表1)中后,获得dataframe中该随机数处的单词和中文翻译,将单词添加到一个空列表(列表3)中,再从dataframe中随机选择单词,如果单词不在列表(列表3)中,则添加到其中,如果在,则重新选择,直到列表(列表3)中有4个单词,再次生成一个随机数,范围为(0,3),按照前面的方法,通过空列表(列表4)判定是否将列表中(列表3)对应位置单词输出出去,输出所有单词后,输出中文翻译,输入与之对应的单词,计算正确率并输出。
如果选择根据单词选翻译,核心算法与上述(根据翻译选单词)相同,仅选择获取的数据不同。
2、在添加单词部分:
如果选择添加单个单词,可直接设定dataframe中的值,依据现有dataframe的行数,再添加一行,如果选择读取文件添加单词,先生成该文件的dataframe,然后遍历,如果该文件的dataframe中的单词在原dataframe中没有,则直接用loc[]函数设定,如果原dataframe中有,则跳过,最后将修改过的dataframe重新写入原文件中。
3、在删除单词部分:
仅能一个一个单词的删除,先设定标志,如果在dataframe中没有找到要删除的单词,则输出提示并结束,如果找到该单词,则用drop()函数直接删除对应行,然后修改dataframe中后续单词的编号,然后将修改后的dataframe写入源文件中。

import random
import pandas as pd#单词以编号,单词,读音,词性,中文翻译几部分组成
words = pd.read_excel("Words_Library.xlsx")
indexs = words['Number'].notnull()
words = words[indexs]def Stop_recite(num):#停止背单词,并记录停止时的单词编号file = open('Record.txt','r+')file.truncate()string = str(num)file.write(string)file.close()print("停止完成")def recite_words(num):#二级菜单功能1if num == 1:number = 0else:print("您将从退出的位置继续。")file = open('Record.txt','r')string = file.read()if string == '':print("没有记录,请从新开始")number = 0else:number = int(string)print("输入next显示下一个单词,输入stop停止")    print("单词的读音、词性和中文翻译:")while number < len(words['Number']):print(words['Word'][number],words['Phonetics'][number],words['Word_class'][number],words['Translate'][number])recite_flag = input()if recite_flag == 'stop':Stop_recite(words['Number'][number]-1)returnwhile recite_flag != 'next':print("输入错误,请重新输入")recite_flag = input()number = number+1print("词库结束。")def write_word_from_memory(choice_num):judge = []right_number = 0false_number = 0while(len(judge)<len(words['Number'])):ch = random.randint(0,len(words['Number'])-1)if ch not in judge:judge.append(ch)if choice_num == 1:string = words['Word'][ch]word_len = len(string)if word_len>10:hide = 4else:hide = int((word_len-2)/3)+1position = []num = 0while num<hide:letter = random.randint(0,word_len-1)if letter not in position:#获得要替换成下划线字母的位置,保证不取重复position.append(letter)num = num+1true_letter = []new_position = sorted(position)#print(new_position)ago_word = ''split_word = []for i in range(len(string)):split_word.append(string[i])for i in new_position:true_letter.append(split_word[i])split_word[i] = '_'for i in split_word:ago_word = ago_word+str(i)#print(true_letter)print("请填充空缺字母:"+ago_word)#字母间由空格分开print(words['Phonetics'][ch]+'\n'+words['Word_class'][ch]+'\n'+words['Translate'][ch])your_answer = input()your_letter = your_answer.split()if your_letter == true_letter:right_number = right_number+1else:false_number = false_number+1print("正确的答案是:"+words['Word'][ch])else:#choice_num == 2print(words['Phonetics'][ch]+'\n'+words['Word_class'][ch]+'\n'+words['Translate'][ch]) your_input = input("请输入单词")            if your_input == words['Word'][ch]:right_number = right_number+1else:false_number = false_number+1print("正确的答案是:"+words['Word'][ch])sum_num = false_number+right_numberaccuracy = right_number/sum_numprint("正确率为:"+str('{:.2%}'.format(accuracy)))if accuracy >= 0.9:print("你的正确率很高,请继续保持")elif accuracy<0.9 and accuracy>=0.6:print("你的成绩合格了,但仍有不足")else:#accuracy<0.6print("你没有取得合格的成绩,请努力学习")def judge_translate_from_word(choice_num):word_num = 0right_number = 0false_number = 0judge = []while word_num<len(words['Number']):ch = random.randint(0,len(words['Number'])-1)if ch not in judge:judge.append(ch)num = 0if choice_num == 3:string = words['Translate'][ch]word_list = []word_list.append(words['Word'][ch])while num<3:word_ch = random.randint(0,len(words['Number'])-1)if words['Word'][word_ch] not in word_list:num = num+1word_list.append(words['Word'][word_ch])print(string)        num = 0choice_list = []while num<4:choice = random.randint(0,3)if choice not in choice_list:choice_list.append(choice)num = num+1print(word_list[choice])true_word = input("请输入匹配的单词")if true_word == words['Word'][ch]:right_number = right_number+1else:false_number = false_number+1else:string = words['Word'][ch]translate_list = []translate_list.append(words['Translate'][ch])while num<3:translate_ch = random.randint(0,len(words['Number'])-1)if words['Translate'][translate_ch] not in translate_list:num = num+1translate_list.append(words['Translate'][translate_ch])print(string)        num = 1choice_dict = {}while num<5:choice = random.randint(0,3)if translate_list[choice] not in choice_dict.values():choice_dict[num] = translate_list[choice]print(str(num)+'、'+translate_list[choice])num = num+1#print(choice_dict)true_word = input("请输入正确答案的选项")if choice_dict[int(true_word)] == words['Translate'][ch]:right_number = right_number+1else:false_number = false_number+1word_num = word_num+1    sum_num = false_number+right_numberaccuracy = right_number/sum_numprint("正确率为:"+str('{:.2%}'.format(accuracy)))def Recite_words():#二级菜单print("请选择功能")options = ((1,'记单词'),(2,'测试'),(3,'返回'))while(1):for option in options:print(option[0],option[1])flag = input("选择功能:")if flag == '1':while(1):next_options = ((1,'从新开始'),(2,'从退出的位置继续'),(3,'返回'))for option in next_options:print(option[0],option[1])next_flag = input('请选择方式:')if next_flag == '1'or next_flag == '2':recite_words(int(next_flag))elif next_flag == '3':print("返回完成")break  else:print('输入错误,请重新输入')elif flag == '2':#单词测试third_options = ((1,'隐藏部分字母'),(2,'默写单词'),(3,'判断单词的翻译'),(4,'根据单词选择词义'),(5,'返回'))for option in third_options:print(option[0],option[1])third_flag = input('请选择方式:')if third_flag == '1' or third_flag == '2':write_word_from_memory(int(third_flag))elif third_flag == '3' or third_flag == '4':judge_translate_from_word(int(third_flag))elif third_flag == '5':print("返回完成")breakelse:print('输入错误,请重新输入')elif flag == '3':print("返回完成")returnelse:print('输入错误,请重新输入')def judge_in_words(string):list1 = []for i in range(len(words['Number'])):list1.append(words['Word'][i])if string not in list1:return Falseelse:return Truedef Add_words():print("选项菜单:")options = ((1,'添加单个单词'),(2,'以文件的方式添加单词'),(3,'返回'))while(1):for option in options:print(option[0],option[1])flag = input("选择功能:")number = len(words['Number'])+1if flag == '1':words.loc[len(words['Number'])] = [number,input("请输入单词:"),input("音标:"),input("词性:"),input("翻译:")]words.to_excel("Words_Library.xlsx",index = False)#将改变后的单词库重新写入excel表中elif flag == '2':many_words = pd.read_excel("many_words.xlsx")for i in range(len(many_words['Number'])):if judge_in_words(many_words['Word'][i]) == False:word_position = number-1words.loc[word_position] = [number,many_words['Word'][i],many_words['Phonetics'][i],many_words['Word_class'][i],many_words['Translate'][i]]number = number+1words.to_excel("Words_Library.xlsx",index = False)elif flag == '3':print("返回完成")return words.reset_index(drop = True)else:print('输入错误,请重新输入')def Show_all_words():new_words = words.reset_index(drop = True)for i in range(len(new_words['Number'])):print(new_words['Number'][i],new_words['Word'][i],new_words['Phonetics'][i],new_words['Word_class'][i],new_words['Translate'][i])def Delete_words():print("选项菜单:")options = ((1,'删除单个单词'),(2,'返回'))while(1):for option in options:print(option[0],option[1])flag = input("选择功能:")if flag == '1':breakelif flag == '2':print("返回完成")returnelse:print('输入错误,请重新输入')this_number = -1old_len = len(words['Number'])string = input("请输入要删除的单词:")for i in range(old_len):if string == words['Word'][i]:this_number = ibreakif this_number == -1:print("没有找到该单词")return wordswords.drop(index = this_number,inplace = True)this_number = this_number+1for i in range(this_number,old_len):#修改后续单词编号words.loc[i] = [i,words['Word'][i],words['Phonetics'][i],words['Word_class'][i],words['Translate'][i]]words.to_excel("Words_Library.xlsx",index = False)return words.reset_index(drop = True)def My_menu():print("选项菜单:")options = ((1,'记单词或测试'),(2,'增加单词'),(3,'删除单词'),(4,'显示所有单词'),(5,'退出')) while(1):for option in options:print(option[0],option[1])flag = input("选择功能:")#print(flag)if flag == '1':Recite_words()elif flag == '2':words = Add_words()elif flag == '3':words = Delete_words()elif flag == '4':Show_all_words()elif flag == '5':print("退出完成")breakelse:print("输入错误,请重新输入")      print("欢迎下次使用")
My_menu()

进一步改进:
1、大作业一开始准备以可视化界面的方式完成,但因为对于可视化界面的方法不熟,从时间方面考虑,最终没有采用该方法,而是选择在IDLE上显示。如果使用可视化界面,可以直接关联按钮和鼠标点击,大大节省输入的要求,如:在记单词中不用输入‘next’和‘stop’,直接建立两个按钮替代即可,在选择题的过程中,直接点按钮即可,不必输入,更符合选择题的做题习惯。
同时,可以使界面更简洁,不会有大量过去的信息留存在显示中,过多信息的留存,不符合一款记单词软件的要求(单词库的信息在测试时仍保留,不能很好地测试出学生的水平)。
2、在测试中3、4部分的选择题(4个单词中选与翻译匹配的,4个翻译中选与单词匹配的),仅完成了最基本的功能,对于输入的有要求,如:根据翻译选单词,必须输入完整的单词(如果选择没错,但拼写错误,会导致错误),没有对应的选项,在根据单词选翻译,因为中文翻译过长,所有选择了输入选项(数字)的方式完成,两种模式的输入方式没有统一。
我的想法有两个:第一种,直接与可视化相结合,不必考虑输入的规范,直接以按钮代替。第二种方式:修改成统一的输入要求,因为中文翻译过长,所以只能考虑输入选项(数字1234或字母ABCD),但我个人更倾向于第一种,所以在完成程序的编写,除了因为测试进行修改,没有统一格式。
3、记单词模式中,无论是在记单词的过程中退出,还是选择从退出的地方继续,都进行了读文件的操作,但是前提要求是文件必须存在,这就使得必须在使用程序前先建立好相应的文件,避免出现错误。
可以考虑python的os库,使用其中的方法,如果判定文件不存在,则直接建立文件,避免出错的可能性。
4、在以读取文件的方式添加单词时,可以使用append函数,但是经过测试,没有添加成功,最后采用遍历读取的文件,再将内容逐行写入dataframe中,然后再将dataframe的内容写入excel的方法,可以考虑采用append的方法,节省空间。还有,因为不需要输入(读取的文件名已设定好),所以在使用程序前,需要建立好对应文件(考虑输入文件名的方式修改,避免只能读取一个文件,减少程序外的操作)。
5、在添加单个单词的部分,对于输入内容没有限定,致使无论什么样的内容输入都可以通过,应该考虑添加判定内容,避免错误内容危害单词库。同时还有,对于添加内容没有判定同样的内容有没有在单词库中,应该添加判定:如果已经有该单词在库中,则添加失败。(英语中有动词做名词的用法,为了词性的区分,可以添加同样的单词,但对于输入内容的限定就成了问题)
6、单词库中缺少修改单词内容的功能,英语中有名词用作动词的用法,也有动词作为名词的用法,如果单词库中的中文翻译和词性不够全的话,只能通过删除后再添加的操作,应该再在一级菜单中添加一个修改单词的功能。(一个单词作为动词和名词的含义并不相同,还要考虑词性和翻译的对应功能,考虑直接修改数据形式,将词性一栏和翻译一栏融合,再添加修改单词功能,要修改整个程序中的各个地方,近乎重写程序了)
7、因为在程序中使用dataframe的方式存储读取的文件内容,为了消除warning和错误,使用了loc函数添加单词(直接设定dataframe的某一行为添加的内容),但又致使dataframe的标签修改,(如添加单词或删除单词后,直接显示单词库,会报错),所以需要reset_index重新确立dataframe中数据的标签,因为是在测试的过程中修改,可能有代码的冗余,需要重新审视自己的代码消除冗余。
8、程序中只有删除单个单词的方法,没有删除一个词库的方法,我的预想是直接输入一个文件名,将文件中所有的单词删除(真正背英语单词的时候,要考虑词汇范围,过多的词汇会影响最后的学习成果),而一个一个单词的删除,仅仅是对应增加单个单词(我认为这两项功能并不实用)。

python语言与系统设计 大作业——背单词的小软件相关推荐

  1. 合工大Python语言与系统设计大作业:微博评论文本情感分析

    大作业:爬取微博评论文本并且分析文本的情感极性:pos or neg 外挂图片失败,请自行发挥想象!!! 文章目录 大作业:爬取微博评论文本并且分析文本的情感极性:pos or neg 设计背景 系统 ...

  2. 【大学生课程】《Python数据分析》课程大作业要求

    <Python数据分析>课程大作业要求 大作业要求 评分标准 考核目标 数据分析基本步骤 实际操作 一.掌握Pandas的读写操作 读写数据操作: 读取文本文件 正确使用预处理技术过滤数据 ...

  3. Python008: Python大作业之移动的小火车动画(一)

    Python大作业 1. 要求 使用Python语言,使用的库不限 如下图1的火车轨道 如下图2的火车(2节车厢) 小火车可以在轨道上动态的运行 小火车的大小可调.轨道的大小可调 2. 用到的第三方库 ...

  4. 微信小程序期末大作业 记单词小程序 适合初学者学习使用

    微信小程序期末大作业 记单词小程序 小程序如下图所示:(下载链接在文末) 点我下载资源 https://download.csdn.net/download/weixin_43474701/59677 ...

  5. Python011: Python大作业之移动的小火车动画(四)代码实现

    书接上文:Python010: Python大作业之移动的小火车动画(三)结果显示 0.注意: ​ 该项目使用的库和资源说明如下: pygame 2.0.1 (SDL 2.0.14, Python 3 ...

  6. 0039c语言作业答案2020,西南大学2019年网络与继续教育[0039]《C语言程序设计》大作业试题(资料).doc...

    西南大学2019年网络与继续教育[0039]<C语言程序设计>大作业试题(资料).doc 文档编号:764150 文档页数:4 上传时间: 2019-10-12 文档级别: 文档类型:do ...

  7. 作业3(大作业):python数据分析与应用大作业,对用户用电量数据进行数据处理,包括数据转置、异常数据识别和处理、统计基本统计量(包括峰度、偏度)、按日/周(求和)差分、5%分位数等

    Python数据分析与应用大作业 使用学习过的知识(Numpy数值分析基础.Matplotlib数据可视化基础.Pandas统计分析基础),对data.csv用户用户用电量数据进行相关处理,其中数据中 ...

  8. [附源码]计算机毕业设计Python+uniapp基于安卓的英语背单词app21a6v(程序+lw+APP+远程部署)

    [附源码]计算机毕业设计Python+uniapp基于安卓的英语背单词app21a6v(程序+lw+APP+远程部署) 该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程 项目运行环境配置 ...

  9. 可以测试成果的背单词软件,实测背单词最好的软件排名,选了4款最管用的单词软件送给你!...

    目前市面上单词软件千千万,哪一款才是我的菜?这个时候通过查看背单词最好的软件排名情况,能让我们快速找到适合自己的背单词软件.每个人基础不一样,比如有的人英语是零基础的,有的人英语是达到四级水平,他们两 ...

最新文章

  1. 博客园首页博问闪存新随笔联系订阅管理 随笔- 252 文章- 0 评论- 45 HashPasswordForStoringInConfigFile中的Md5算法并非常用的Md5算法...
  2. php 安装 phpunit,phpunit的安装
  3. 卡牌大师怎么玩_用卡牌大师如何上分
  4. 三诺+n20g+微型计算机,原来是他?揭秘三诺永恒系列开山鼻祖
  5. 【小记】输入框前后左右去空格的正则方法
  6. 图像处理基本概念——卷积,滤波,平滑
  7. 宁夏大学新华学院08计算机马宁,公 示
  8. Vue模板 script部分
  9. 学渣的c#复习手记 类 一
  10. COM 组件设计与应用7 - 编译、注册、调用
  11. 大数据 流式计算 apache storm 学习笔记 01 ---汪文君
  12. 发送ajax将浏览器卡死,jQuery Ajax同步参数致使浏览器假死怎么办
  13. 例题(15.6) 细菌实验分组
  14. 故障转移集群搭建高可用文件共享服务器
  15. 配置activiti控制台打印SQL
  16. ROS IDE —— RoboWare Studio
  17. Arduino_mega2560+DynamixelShield控制MX-64R舵机
  18. 查看及修改微软Edge浏览器用户数据保存位置(包括详细历史记录(页面停留时间,页面访问次数,最后访问时间,下载历史等),Cookie,书签等)
  19. P2V迁移(Centos7整机业务迁移到ESXI7.0)
  20. 奥塔在线:Centos7下Nginx的安装

热门文章

  1. 【CFW】浏览器[自动]选择是否走代理,桌面软件不走代理
  2. 图解常用的几种深度学习评价指标
  3. linux 系统运维日常巡检脚本参考
  4. 机器学习平台系列(六) - 再探 Jupyter Lab:在 CentOS 下制作 Docker 镜像
  5. linux教程 diff,Linux下Diff命令使用方法
  6. 计算机毕业设计JAVA我爱短视频管理系统mybatis+源码+调试部署+系统+数据库+lw
  7. Python--NBA数据分析初探(下)
  8. Obsidian Pandoc导出带图片的word docx
  9. 03pe修改计算机名称,[U盘PE教程]03PE注册表修改与优化总结
  10. setLayout(null)在java中什么意思