软件:idea
我是先建立了一个空白的项目,自己创建的src包和其下面的包。
问题一:建立包之后发现格式为src.com.tjp.bean 没办法建立其他与bean同级的service test utils view 等。只允许继续建立bean的子包。
解决: 这是因为idea自动会折叠空白包。(不同版本的idea可能和我的位置不太一样,但是都在那个齿轮里,第一步都先点击那个齿轮,看看里面有没有提到fold empty等词汇,如果有,又打了对勾,那就取消一下试试嘛,反正大不了记住位置,一会儿再勾回来嘛。)
把压缩空的中间软件包取消勾选,就可以看到可以正常建立空白包的子包了。
项目结构如下图:
- 看以下代码须知:本人是个菜鸟,才学完Java的语法知识和面向对象相关的知识,掌握的也不是很好,下面代码中的注释,都是我根据自己的理解,添加的注释,如果有错的或者不恰当的地方,希望各位大佬可以不吝赐教。谢谢!
- 里面的代码是尚硅谷的代码。因为尚硅谷的代码是用eclipse写的,我本来尝试了一下eclipse代码包转idea项目,但是失败了,不过好在这个项目还不涉及框架和数据库什么的,因此我就仿照尚硅谷的代码结构,建立了包,和类,把他的代码复制粘贴到我的类中,运行起来没有任何问题,反正这次的目的主要是研究,以及熟练掌握一下代码语法。多练,多动手嘛!
- 正常应该先看bean下的customer类,但是我觉得代码太多了,我喜欢从代码少的开始看,你们就随意啦!
//Test类代码:
package src.com.tjp.test;
//先声明本类所在的位置。嘿我在这里!
import src.com.tjp.view.CustomerView;
//导入view包下的CustomerView类,因为下面要创建它的对象,调用它的方法,所以需要把这个类先导入到这个类里面。
public class Test {
//Test类开始
public Test(){
}
//Test无参构造器。
public static void main(String[] args) {
// Test类入口,主函数。
CustomerView view = new CustomerView();
// 创建了CustomerView类的对象view.
view.menu();
// 用创建的对象view,调用CustomerView类的方法menu().
}
}
附图:
//Customer类代码:
package src.com.tjp.bean;
//先写明本类所在的位置.讲个好玩的:你是谁啊?我爸爸是bean,爷爷是tjp,太爷爷是com,太太爷爷是src.我是这一支的人,现在你知道我是谁了吧?
public class Customer {
//本类开始。
private String name;
//一般标准bean都是把属性,定义为私有的,然后其他类想要这个属性的值,就通过set get方法获得。
// 私有化属性name String类型的.
private char gender;
// gender:性别的意思。
private int age;
// 属性,成员变量,实例字段是一个意思.
// 字段是属于类的,它是会用public、private等关键字修饰的。
private String phone;
private String email;
public Customer(){
// 创建一个Customer无参构造器。
}
public Customer(String name, char gender, int age, String phone, String email){
// 创建一个Customer有参构造器,形参是name,gender,age,phone,email.
this.name = name;
// this.name 为构造器外面,本类最开始定义的成员变量,
// 构造器又可以叫做构造方法,构造器可以被看做是一种特殊的方法。构造器用于构造该类的实例,也就是对象。
// 构造器格式:[修饰符] 类名 (形参列表){//n条语句}
// ##构造器与方法的区别:
// 1.构造器的名字必须与定义它的类名完全相同,没有返回类型,甚至连void也没有。
// 2.构造器的调用是在创建一个对象时使用new操作进行的。构造方法的作用是初始化对象。
// 3.不能被static、final、synchronized、abstract和native修饰。构造方法不能被子类继承。
// 4.构造方法可以被重载。没有参数的构造方法称为默认构造方法,与一般的方法一样,构造方法可以进行任何活动,但是经常将他设计为进行各种初始化活动,比如初始化对象的属性。
// 5.每个类可以有一个以上的构造器.
// 6.构造器可以有0个,1个,或多个参数.
// 7.构造器总是伴随着new操作符一起调用.
// 8.构造器与其他方法有一个重要的不同.构造器总是结合new运算符来调用.不能对一个已经存在的对象调用构造器来达到重新设置实例字段的目的.
// 例子:jams.Employee("James Bond",250000,1950,1,1)//ERROR
// 例子: new Employee("Jams Bond",100000,1950,1,1)//CORRECT
// #方法:
// 1.方法包含于类或对象中,方法在程序中被创建,在其他地方被引用.
// 2.命名规则:方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。
// 3.命名规则:下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。一个典型的模式是:test<MethodUnderTest>_<state>,例如 testPop_emptyStack。
// 4.修饰符 返回值类型 方法名(参数类型 参数名){方法体 return 返回值;}没有返回值的时候,用void,而不可以像构造器那样,不去写.
// 5.调用一个方法时候需要提供参数,你必须按照参数列表指定的顺序提供。
// *******************************************
// 成员变量和局部变量的区别:
// 1.在类中位置不同:成员变量:在类中方法外。局部变量:在方法定义中或者方法声明上。
// 2.在内存中的位置不同:成员变量:在堆内存。 局部变量:在栈内存。
// 3.生命周期不同:成员变量:随着对象的创建而存在,随着对象的消失而消失。 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失。
// 4.初始化值不同:成员变量:有默认值初始化。局部变量:没有默认值初始化,必须定义,赋值,然后才能使用。
// 5.注意事项:局部变量名称可以和成员变量名称一样(用this区分),在方法中使用的时候,采用的是就近原则。
// 用this修饰的变量,为成员变量,没有用this修饰的变量,根据就近原则,为局部变量,即构造器里声明的变量,成员变量和局部变量名字可以不同,
// 但是都用的相同的名字,一方面可能是见名知意思,另一方面可能是比较懒,不想起其他名字,防止混乱?仅仅只是我自己的理解,不知对不对。
this.gender = gender;
this.age = age;
this.phone = phone;
this.email = email;
}
// 以下是set get方法.用ALT+Insert快捷键快速生成set, get方法.也可以鼠标右键->点击生成->getter Setter
// 如果按了快捷键发现没有弹窗,你的电脑又恰好是联想小新,可以试试,Fn+Esc.按下去发现Esc键亮起,说明上面一排从F1~F12~Insert, PrtSc都恢复了正常功能.
// 如果你还指望用F3调节音量大小,那我建议你,记得写完代码后,再按Fn+Esc,让Esc的灯光再次熄灭.
// 这回可以再试试刚才的快捷键了,如果还是不行,那就百度一下吧.
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public char getGender(){
return this.gender;
}
public void setGender(char gender){
this.gender = gender;
}
public int getAge(){
return this.age;
}
public void setAge(int age){
this.age = age;
}
public String getPhone(){
return this.phone;
}
public void setPhone(String phone){
this.phone = phone;
}
public String getEmail(){
return this.email;
}
public void setEmail(String email){
this.email = email;
}
// CustomerView类中list方法会调用这个getInfo方法,用于输出.
public String getInfo(){
return this.name + "\t" + this.gender + "\t" + this.age + "\t" + this.email;
}
}
//CustomerService代码:
package src.com.tjp.service;
//声明本类所在的位置。
import src.com.tjp.bean.Customer;
//导入Customer类。
import java.util.Arrays;
//导入Java自带的util包下的Arrays类,如果不导入这个类,下面用arrays的时候,就会报错。
public class CustomerService {
// 本类开始。
private Customer[] all;
// 这个我也不太确定,应该是私有化定义一个Customer类类型的数组,all.
private int total;
// 私有化定义一个int类型的成员变量total
public CustomerService() {
this.all = new Customer[2];
}
// 本类的无参构造器,创造一个Customer类类型的两个长度的数组,并把这个数组地址赋值给ALL数组。(数组是引用类型,应该是地址传递)
public CustomerService(int initSize) {
this.all = new Customer[initSize];
}
// 本类的有一个形参的构造器,initSize是规定几个可以输入的,例如编号,性别,等的最小输入范围,但是为什么这么写,不太清楚,这里不太理解。
public void addCustomer(Customer c) {
// 本类的一个无返回值的公有的addCustomer方法,形参有一个Customer类型的 c.
if (this.total >= this.all.length) {
System.out.println("数组已满");
} else {
this.all[this.total++] = c;
}
}
public Customer[] getAll() {
return (Customer[]) Arrays.copyOf(this.all, this.total);
}
// 返回值类型是Customer[]的方法?应该是这个意思?
public void removeById(int id) {
// 公有的,没有返回值的,一个形参的removeById方法。
// 从CustomerView类中,删除用户方法中,调用此方法,从输入控制台传入要删除的id号。
// 把id-1为了让它和数组下标对应,并查找拥有该数组下标的,是否存在。
// 该死的,用这么多方法。头大。
int index = id - 1;
if (index >= 0 && index < this.total) {
System.arraycopy(this.all, index + 1, this.all, index, this.total - index - 1);
// 原数组, 源数组要复制的起始位置,目的数组,目的数组放置的起始位置,复制的长度。
this.all[--this.total] = null;
// 居然还可以这样写,妙啊。
} else {
System.out.println(id + "对应的客户不存在");
}
}
// 查看输入的id,是否存在对应的客户。
public Customer getById(int id) {
int index = id - 1;
if (index >= 0 && index < this.total) {
return this.all[index];
} else {
System.out.println(id + "客户不存在");
return null;
}
}
// 修改用户,查看需要修改的用户是否存在。
public void replace(int id, Customer newCustomer) {
int index = id - 1;
if (index >= 0 && index < this.total) {
this.all[index] = newCustomer;
} else {
System.out.println(id + "客户不存在");
}
}
}
//CustomerView类的代码:
package src.com.tjp.view;
import src.com.tjp.bean.Customer;
import src.com.tjp.service.CustomerService;
import src.com.tjp.utils.CMUtility;
public class CustomerView {
private CustomerService cs = new CustomerService();
// 这个私有化创建对象的做法值得深思。
public CustomerView(){
}
public void menu(){
while(true) {
System.out.println("----------客户信息管理软件----------");
System.out.println("\t\t\t1. 添加客户");
System.out.println("\t\t\t2. 修改客户");
System.out.println("\t\t\t3. 删除客户");
System.out.println("\t\t\t4. 客户列表");
System.out.println("\t\t\t5. 退 出");
System.out.println("----------请选择(1~5):");
char select = CMUtility.readMenuSelection();
switch(select){
case '1':
this.add();
break;
case '2':
this.update();
break;
case '3':
this.delete();
break;
case '4':
this.list();
break;
case '5':
System.out.println("确认退出嘛?Y/N");
char confirm = CMUtility.readConfirmSelection();
if (confirm == 'Y') {
return;
}
}
}
}
private void list(){
Customer[] all = this.cs.getAll();
System.out.println("-------------客户列表--------------");
System.out.println("编号\t姓名\t性别\t年龄\t电话\t邮箱");
for(int i = 0;i < all.length; ++i) {
System.out.println((i + 1) + "\t" + all[i].getInfo());
}
System.out.println("-------------客户列表完成----------");
}
private void delete(){
System.out.println("-------------删除客户--------------");
System.out.println("请选择待删除客户编号(-1退出):");
int id = CMUtility.readInt();
if (id != -1) {
System.out.println("确认是否删除(Y/N):");
char confirm = CMUtility.readConfirmSelection();
if (confirm != 'N'){
this.cs.removeById(id);
System.out.println("-------------删除完成-----------");
}
}
}
private void update(){
System.out.println("--------------修改客户------------");
System.out.println("请选择待修改客户编号(-1退出):");
int id = CMUtility.readInt();
if(id != -1) {
Customer old = this.cs.getById(id);
System.out.println("姓名(" + old.getName() + "): ");
String name = CMUtility.readString(20, old.getName());
System.out.println("性别(" + old.getGender() + "): ");
char gender = CMUtility.readChar(old.getGender());
System.out.println("年龄(" + old.getAge() + "): ");
int age = CMUtility.readInt(old.getAge());
System.out.println("电话(" + old.getPhone() + "): ");
String phone = CMUtility.readString(11, old.getPhone());
System.out.println("邮箱(" + old.getEmail() + "): ");
String email = CMUtility.readString(32, old.getEmail());
Customer newCustomer = new Customer(name, gender, age, phone, email);
this.cs.replace(id, newCustomer);
System.out.println("--------------修改完成------------");
}
}
private void add(){
System.out.println("--------------添加客户-----------");
System.out.println("姓名: ");
String name = CMUtility.readString(20);
System.out.println("性别: ");
char gender = CMUtility.readChar();
System.out.println("年龄: ");
int age = CMUtility.readInt();
System.out.println("电话: ");
String phone = CMUtility.readString(11);
System.out.println("邮箱: ");
String email = CMUtility.readString(32);
Customer c = new Customer(name, gender, age, phone, email);
this.cs.addCustomer(c);
System.out.println("--------------添加完成-----------");
}
}
//CMUtility类的代码:
package src.com.tjp.utils;
import java.util.Scanner;
public class CMUtility {
private static Scanner scanner;
static {
scanner = new Scanner(System.in);
}
public CMUtility() {
}
public static char readMenuSelection() {
while(true) {
String str = readKeyBoard(1, false);
char c = str.charAt(0);
if (c == '1' || c == '2' || c == '3' || c == '4' || c == '5') {
return c;
}
System.out.print("选择错误,请重新输入:");
}
}
public static char readChar() {
String str = readKeyBoard(1, false);
return str.charAt(0);
}
public static char readChar(char defaultValue) {
String str = readKeyBoard(1, true);
return str.length() == 0 ? defaultValue : str.charAt(0);
}
public static int readInt() {
while(true) {
String str = readKeyBoard(2, false);
try {
int n = Integer.parseInt(str);
return n;
} catch (NumberFormatException var3) {
System.out.print("数字输入错误,请重新输入:");
}
}
}
public static int readInt(int defaultValue) {
while(true) {
String str = readKeyBoard(2, true);
if (str.equals("")) {
return defaultValue;
}
try {
int n = Integer.parseInt(str);
return n;
} catch (NumberFormatException var4) {
System.out.print("数字输入错误,请重新输入:");
}
}
}
public static String readString(int limit) {
return readKeyBoard(limit, false);
}
public static String readString(int limit, String defaultValue) {
String str = readKeyBoard(limit, true);
return str.equals("") ? defaultValue : str;
}
public static char readConfirmSelection() {
while(true) {
String str = readKeyBoard(1, false).toUpperCase();
char c = str.charAt(0);
if (c == 'Y' || c == 'N') {
return c;
}
System.out.print("选择错误,请重新输入:");
}
}
private static String readKeyBoard(int limit, boolean blankReturn) {
String line = "";
while(scanner.hasNextLine()) {
line = scanner.nextLine();
if (line.length() == 0) {
if (blankReturn) {
return line;
}
} else {
if (line.length() >= 1 && line.length() <= limit) {
break;
}
System.out.print("输入长度(不大于" + limit + ")错误,请重新输入:");
}
}
return line;
}
}
#########################################################################
(明天,后天,大后天的任务是把这个项目从头彻底的自己写出来,彻底理解。)
末尾:(和这个项目无关的代码,仅仅为了展示构造器的一些性质,值得深思。还是没读懂Java核心技术卷一第11版中文版P108页的警告)
原书内容:警告:请注意,不要再构造器中定义与实例字段同名的局部变量。例如下面的构造器将不会设置salary。
public Employee(String n,double s,...){
String name = n;//ERROR
double salary = s;//ERROR
}
这个构造器声明了局部变量name和salary。这些变量只能在构造器内部访问。这些变量会遮蔽(shadow)同名的实例字段。有些程序员偶尔会不假思索地写出这类代码,因为他们的手指会不自觉地增加数据类型。这种错误很难检查出来,因此,必须注意在所有的方法中都不要使用与实例字段同名的变量。
他到底是什么意思呢?是在说构造器内的变量,具有局部性,出了这个构造器,这个变量就不被承认?
实例字段不就指的是成员变量吗?
他是在说我下面图片中演示的测试1,2那样?
好奇怪啊,是这个版本的翻译不行吗?有机会找来原著看看,现在不都把名字和实例字段设置成一样的吗?然后用this区分哪个是实例字段,哪个是局部字段嘛?为什么书中说不建议?好奇怪?
- 关于构造器,还不太清楚的可以看以下的文章。(其他人写的,我觉得初学者应该了解构造器的具体用处。下面的都是引用其他人的文章,希望会对你的理解有点帮助。)
https://www.jb51.net/article/266354.htm - 关于数组是值传递还是引用传递的问题: 答案是引用传递,即是赋值的时候,其实是地址传递过去了。
- 关于this.all = new Customer[2];这里不懂的,可以参考这个链接:
https://blog.csdn.net/qq_46423166/article/details/128588295 - 关于Arrays.copyOf(this.all, this.total)
- 关于System.arraycopy的使用方法详解:
https://blog.csdn.net/wenzhi20102321/article/details/78444158 - 学习各种语言的宝藏网站:菜鸟教程,链接如下:
https://www.runoob.com/