本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2022-06-25
类的基本用法
class Person {
String name;
int age = 0;
boolean isMale;
public void eat() {
System.out.println("吃饭");
}
}
public class PersonTest {
public static void main(String[] args) {
// 创建Person类的实例
Person p1 = new Person();
p1.name = "Anna";
p1.age = 18;
p1.isMale = false;
p1.eat(); // 吃饭
System.out.println(p1.name); // "Anna"
}
}
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。跟方法的修饰符、返回值类型、形参变量名、方法体都没有关系。
public class OverLoadTest {
public void getSum(int i, int j) {
System.out.println(i + j);
}
public void getSum(double i, double j) {
System.out.println(i + j);
}
// 下面两个也算重载
public void getSum(String s, int i) {}
public void getSum(int i, String s) {}
// error 不算重载 返回值不影响
public String getSum(int i, String s) {}
// error 不算重载 权限不影响
private void getSum(int i, String s) {}
}
当重载存在时,在通过对象调用方法时,编译的时候会通过方法名和和参数列表来确定指定的方法。
可变个数形参的方法,类似于JavaScript的剩余参数,也只能是参数列表的最后一个参数,也只能存在一个可变形参。
public class OverLoadTest {
public static void main(String[] args) {
OverLoadTest o = new OverLoadTest();
o.show(12);
o.show("hello");
o.show("hello", "world");
o.show(); // 不传参也能匹配到使用了剩余参数定义的函数
}
public void show(int i) {
System.out.println("show int " + i);
}
public void show(String s) {
System.out.println("show String " + s);
}
public void show(String ... strs) {
if (strs.length > 0) {
for (int i = 0; i < strs.length; i++) {
System.out.println("show String ... strs " + strs[i]);
}
} else {
System.out.println("show String ... strs 参数列表为空");
}
}
}
// show int 12
// show String hello
// show strs hello
// show strs world
// show strs 参数列表为空
可变个数形参的方法与本类中方法名相同,形参不同的方法之间也构成重载,但是需要注意的是,public void show(String ... strs)
与 public void show(String[] strs)
是冲突的,不能共存,因为它们的形参列表是“一样”的。
关于变量的赋值是a = b;
:
形参是指方法定义时,声明的小括号内的参数;实参是方法调用时实际传递给形参的数据(可能是值,也可能是指针)
在方法调用传入实参时,可以这样理解,此时在方法中根据形参列表,声明了多个局部变量,并将实参的值传递给了这些变量。
public class ValueTransfer {
public static void main(String[] args) {
ValueTransfer v = new ValueTransfer();
int a = 10;
int b = 20;
v.swap(a, b);
System.out.println("main方法内访问main方法内的局部变量");
System.out.println("a => " + a + ", b => " + b);
// a => 10, b => + 20
}
public void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
System.out.println("swap方法内访问的形参,是swap方法内的局部变量");
System.out.println("a => " + a + ", b => " + b);
// a => 20, b => + 10
}
}
a => 10, b => + 20
如上述例子,是一个值传递,所以呢,在swap
方法中交换的只是 swap
被调用时内部的局部变量。
总结:如果传递的数据是基本数据类型,此时实参赋值给形参的是实参真实存储的数据值。
public class ValueTransfer2 {
public static void main(String[] args) {
ValueTransfer2 v = new ValueTransfer2();
Data data = new Data();
data.m = 10;
data.n = 20;
v.swap(data);
System.out.println("m => " + data.m + ", n => " + data.n);
// m => 20, n => 10
}
public void swap(Data d) {
int temp = d.m;
d.m = d.n;
d.n = temp;
System.out.println("m => " + d.m + ", n => " + d.n);
// m => 20, n => 10
}
}
class Data {
int m;
int n;
}
上述例子,传递给swap
方法是Data data
这个对象,所有在调用方法时,在swap
也创建了一个局部变量,可以理解为是一个赋值Data d = data;
,此时的这个 d
保存的指针(引用地址),之后在方法体中去修改d.m
和d.n
的时候,是修改的Data data = new Data();
这个对象在内存中保存的相应属性的数据,所以可以影响到main
方法中的Data data
(因为这个变量也是一个指针,它们两个指向的是同一个内存地址)
总结:如果传递的数据是引用数据类型,此时实参赋值给形参的是实参存储数据的地址值。
递归方法是指一个方法体内调用它自身,方法递归包含了一种隐式的循环,它会重复执行某段代码,所有递归方法的方法体中关于结束判断要合理设置,避免死循环。
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏,该暴露的暴露出来,这就是封装性的设计思想,追求高内聚低耦合。
高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅对外暴露少量的方法用于使用。
public class AnimalTest {
public static void main(String[] args) {
Animal a = new Animal();
a.name = "wangcai";
a.setAge(3);
//a.age = -3; // 如果Animal类的age属性没有设置private,则会导致用户可以通过 a.age 直接修改属性,并设置一个不合理的值。
a.show();
a.eat();
}
}
class Animal {
String name;
private int age;
public void setAge(int age) {
if (age > 0) {
this.age = age;
} else {
this.age = 0;
}
}
public int getAge() {
return age;
}
public void eat() {
System.out.println("吃");
}
public void show() {
System.out.println("name:" + name + ",age:" + age);
}
}
当我们创建一个类的对象以后,我们可以通过 对象.属性 的方式,对对象的属性进行赋值。这里的赋值操作要受属性的数据类型和存储范文的制约,除此之外,没有其他的约束条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件,这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的增加,比如上例子中的 setAge
。同时,我们在提供set方法的时候,还需要避免用户再使用 对象.属性 的方法去给属性赋值,则需要将属性声明为私有的(private)。
当我们设置属性为私有的时候,如果只提供set方法,那么使用者将无法读取该属性的值,所以此时应该提供一个get方法给用户,让其可以通过该方法访问到对应的属性,比如上例中的 getAge
。
此时,针对于属性就体现了封装性,体现在我们将类的属性私有化,同时提供公共的set和get方法出去用于设置和获取。
权限从小到大包含,private
、缺省(不修饰)、protected
、public
。
这些权限修饰符用来限制对象对该类成员的访问权限。
修饰符 | 类内部 | 同一个包 | 不同包的子类 | 同一个工程 |
---|---|---|---|---|
private | yes | |||
缺省 | yes | yes | ||
protected | yes | yes | yes | |
public | yes | yes | yes | yes |
需要注意的有:
四种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类。
对于class的权限只可以用public
或者 缺省。
public
可以在任意地方被访问构造器的作用:
创建对象: new Person()
的结构就是 new + 构造器
,当new Person()
的时候,实际执行的是Person的构造器(构造方法)。
初始化对象的信息
需要注意的是:
如果没有显示的定义类的构造器的话,则系统默认为提供一个空参构造器,默认提供的空参构造器的权限与当前类的权限一致。
定义构造器的格式: 权限修饰符 类名(形参列表){}
一个类中可以存在多个构造器,就是对构造器的重载。
一旦我们显示定义了类的构造器之后,系统就不再提供默认的空参构造器。
class Person {
String name;
int age = 0;
// 构造器 如果没有显示的写 就有一个空参的在这 是系统提供的
public Person() {
System.out.println("构造器被执行了");
}
public Person(String _name) {
name = _name;
System.out.println("带有name参数构造器被执行了");
}
}
public class PersonTest {
public static void main(String[] args) {
// 创建Person类的实例
Person p1 = new Person(); // 输出 "构造器被执行了"
Person p2 = new Person("jack"); // 输出 "带有name参数构造器被执行了"
System.out.println(p2.name); // 输出 "jack"
}
}
属性赋值的先后顺序如下:
1、默认初始化对应类型的值,比如上例中第2行的 String name
,就会对name
进行初始化为null
,因为是引用类型。
2、显示初始化,比如上例中的第4行 int age = 0
,就是显示初始化,如果之后没有在构造器中进行赋值通过对象.属性的方法去改变的话,之后访问就是一直是0。
3、构造器中赋值,比如上例中的第22行 Person p2 = new Person("jack")
,就是在构造器中给name
进行了赋值。
4、通过 对象.方法 或者 对象.属性 的方式去赋值,可以多次使用,上面三个只能在“初始化过程”中使用一次。
JavaBean 是一种Java语言写成的可重用组件。
所有的JavaBean,是指符合如下标准的Java类:
使用一种图形的方式表示整个类的结构。
其中,需要注意的是
-
表示private+
表示public#
表示protected~
表示default_
表示staticthis
理解为当前对象或当前正在创建的对象(在构造器中)
在类的方法中,我们可以使用 this.属性
或 this.方法
的方式,调用当前对象属性或方法,但是,通常情况下,我们选择省略 this
。特殊情况下,如果方法的形参和类的属性名相同,我们必须显示使用 this.变量
的方法,表示次变量是属性,而非形参。
public class PersonTest1 {
public static void main(String[] args) {
Person1 p = new Person1("jack", 17);
p.setAge(18); // p调用setAge时,this指向p
System.out.println(p.getAge());
p.getup();
}
}
class Person1 {
private String name;
private int age;
public void setName(String name) {
// 属性名和参数形参相同 所以要显示使用this.变量
this.name = name;
}
public Person1(String name, int age) {
this.name = name; // 在构造器中,this指向正在创建的那个对象
this.age = age;
}
public String getName() {
return name;
}
public void setAge(int a) {
// 属性名和参数形参不同时,可以省略this
age = a;
}
public int getAge() {
return age;
}
public void eat() {
System.out.println("吃饭");
}
public void getup() {
System.out.println("起床");
// 通常调用时,省略this
eat();
//this.eat(); // 与上效果一致
}
}
在一个构造器中调用另一个构造器。
public class PersonTest2 {
public static void main(String[] args) {
Person2 p = new Person2("jack", 18); // 吃饭
System.out.println(p.name); // jack
System.out.println(p.age); // 18
}
}
class Person2 {
String name;
int age;
public Person2() {
this.eat();
}
public Person2(String name) {
this(); // 调用 Person2()
this.name = name;
}
public Person2(String name, int age) { // 业务处调用,先执行这个
this(name); // 调用 Person2(String name)
this.age = age;
// 最终也能成功调用eat,赋值name属性
}
public void eat() {
System.out.println("吃饭");
}
}
我们在类的构造器中,可以显示的使用 this(形参列表)
的方式,调用本类中指定的其他构造器,但是不能使用这种方法调用“自己”(当前构造器)。
同时,使用this(形参列表)
的方法调用其他构造器,必须声明在当前构造器的首行,所以每个构造器内部,最多只能调用一个其他的构造器。
构造器的互相调用,需要注意不能循环调用,每个构造器在一次构造中都只能最多调用一次,一次构造调用了多个构造器也只是创建了一个对象。
1、为了更好的实现项目中类的管理,提供包(package)的概念。
2、使用package声明类或接口所属的包,声明在源文件的首行。
3、包,属于标识符,需要遵循标识符的命名规则、规范(小写、见名知意)。
4、每 “.” 一次,就代表一层文件目录。
5、同一个包下,不能命令同名的接口、类,不同的包下可以。
6、JDK中主要的包介绍
java.lang - 包含一些java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能。
java.net - 包含执行与网络相关的操作的类和接口。
java.io - 包含能提供多种输入/输出功能的类。
java.util - 包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
java.text - 包含了一些java格式化相关的类
java.sql - 包含了java进行JDBC数据库编程的相关类/接口。
java.awt - 包含了构成抽象窗口工具集(abstract/window/toolkits)的多个类,这些被用来构建和管理应用程序的图形用户界面(GUI)。
1、在源文件中显示的使用import结构导入指定包下的类、接口。
2、声明在包的声明和类的声明之间。
3、可以使用*
的方式,导入某个包下的所有结构,import java.util.*
;
4、如果使用的类或接口是在java.lang
定义的,则可以省略import结构。
5、如果在源文件,使用了不同包下的同名的类,则必须至少有一个采用全类名的方式显示。
6、如果使用*
方式可导入某包下面的所有接口,但是如果使用该包下子包的结构,则仍需显示导入。
7、import static
:导入指定类或接口中的静态结构(引入的是属性或方法,而import引入的类或者接口)
Customer.java
public class Customer {
private String name;
private char gender;
private int age;
private String phone;
private String email;
public Customer() {
}
public Customer(String name, char gender, int age, String phone, String email) {
this.name = name;
this.gender = gender;
this.age = age;
this.phone = phone;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
CustomerList.java
public class CustomerList {
private Customer[] customers;
private int total = 0;
/**
* 用来初始化customers数组的构造器
* @param totalCustomer 指定数组的长度
*/
public CustomerList(int totalCustomer) {
customers = new Customer[totalCustomer];
}
/**
* 将指定客户添加到数组中
* @param customer
* @return
*/
public boolean addCustomer(Customer customer) {
if (total >= customers.length) {
return false;
}
customers[total] = customer;
total++;
return true;
}
/**
* 修改指定索引位置的客户信息
* @param index
* @param customer
* @return
*/
public boolean replaceCustomer(int index, Customer customer) {
if (index >= total || index < 0) {
return false;
}
customers[index] = customer;
return true;
}
/**
* 删除指定位置的客户
* @param index
* @return
*/
public boolean deleteCustomer(int index) {
if (index >= total || index < 0) {
return false;
}
for (int i = index; i < total - 1; i++) {
customers[i] = customers[i+1];
}
customers[total-1] = null;
total--;
return true;
}
/**
* 获取所有的客户信息
* @return
*/
public Customer[] getAllCustomers() {
Customer[] custs = new Customer[total];
for (int i = 0; i < total; i++) {
custs[i] = customers[i];
}
return custs;
}
public Customer getCustomer(int index) {
if (index >= total || index < 0) {
return null;
}
return customers[index];
}
public int getTotal() {
return total;
}
}
CMUtility.java
package com.cz.p2.util;
import java.util.*;
public class CMUtility {
private static Scanner scanner = new Scanner(System.in);
/** 读取键盘输入 如果用户键入1-5中的任意字符,则方法返回用户键入的字符。*/
public static char readMenuSelection() {
char c;
for(;;) {
c = readChar();
String[] chars = new String[]{"1", "2", "3", "4", "5"};
if (Arrays.asList(chars).contains(String.valueOf(c))) {
break;
} else {
System.out.print("选择错误,请重新输入:");
}
}
return c;
}
/** 从键盘读取字符,并将其作为方法的返回值 如果用户直接回车,则返回默认值 */
public static char readChar(char ...args) {
boolean hasDefaultValue = args != null;
String str = readKeyBoard(1, hasDefaultValue);
return hasDefaultValue && str.length() == 0 ? args[0] : str.charAt(0);
}
/** 从键盘读取一个长度不超过2位的整数并返回 如果用户直接回车,则返回默认值 默认值通过参数传入 */
public static int readInt(int ...args) {
boolean hasDefaultValue = args != null;
int n;
for(;;) {
String str = readKeyBoard(2, hasDefaultValue);
if (str.equals("") && hasDefaultValue) {
return args[0];
}
try {
n = Integer.parseInt(str);
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/** 从键盘读取不超过limit的字符串,并将其作为方法的返回值 如果用户直接回车,则返回默认值 */
public static String readString(int limit, String ...args) {
boolean hasDefaultValue = args != null;
String str = readKeyBoard(limit, hasDefaultValue);
return hasDefaultValue && str.length() == 0 ? args[0] : str;
}
/** 用于选择,从键盘读取Y/N, 并将其返回 */
public static char readConfirmSelect() {
String select = readString(1, "Y").toUpperCase();
char c = select.charAt(0);
if (c == 'Y' || c == 'N') {
return c;
} else {
System.out.print("输入错误,请重新输入(y/n):");
return readConfirmSelect();
}
}
/**
* 读取键盘输入
*
* @param limit 字符的限制长度
* @param blankReturn 用户回车时是否直接返回
* @return 返回读取的数据
*/
private static String readKeyBoard(int limit, boolean blankReturn) {
String line = "";
while (scanner.hasNextLine()) {
line = scanner.nextLine();
int len = line.length();
if (len == 0) {
if (blankReturn) {
return line;
} else {
continue;
}
} else if (len < 1 || len > limit) {
System.out.print("输入长度(不大于" + limit + ")错误,请重新输入");
}
break;
}
return line;
}
}
CustomerView.java
public class CustomerView {
private CustomerList customerList = new CustomerList(10);
public static void main(String[] args) {
CustomerView view = new CustomerView();
view.enterMainMenu();
}
/**
* 显示界面的方法
*/
public void enterMainMenu() {
boolean isFlag = true;
while(isFlag) {
System.out.println("\n------------客户信息管理软件------------\n");
System.out.println(" 1 添加客户");
System.out.println(" 2 修改客户");
System.out.println(" 3 删除客户");
System.out.println(" 4 客户列表");
System.out.println(" 5 退出\n");
System.out.print(" 请选择(1-5):");
char menu = CMUtility.readMenuSelection();
switch (menu) {
case '1':
addNewCustomer();
break;
case '2':
modifyCustomer();
break;
case '3':
deleteCustomer();
break;
case '4':
listAllCustomers();
break;
case '5':
System.out.print("确认是否退出(Y/N):");
char isExit = CMUtility.readConfirmSelect();
if (isExit == 'Y') {
isFlag = false;
}
}
}
}
private void addNewCustomer() {
System.out.println("\n------------添 加 客 户------------\n");
System.out.print("姓名: ");
String name = CMUtility.readString(10);
System.out.print("性别: ");
char gender = CMUtility.readChar();
System.out.print("年龄: ");
int age = CMUtility.readInt();
System.out.print("电话: ");
String phone = CMUtility.readString(11);
System.out.print("邮箱: ");
String email = CMUtility.readString(20);
Customer c = new Customer(name, gender, age, phone, email);
boolean isSuccess = customerList.addCustomer(c);
if (isSuccess) {
System.out.println("------------添 加 成 功------------");
} else {
System.out.println("------------添 加 失 败------------");
}
}
private void modifyCustomer() {
Customer c;
int number;
System.out.println("\n------------修 改 客 户------------\n");
for(;;) {
System.out.print("请选择待修改客户编号(-1退出):");
number = CMUtility.readInt();
if (number == -1) {
return;
}
c = customerList.getCustomer(number);
if (c == null) {
System.out.println("无法找到指定的客户!");
} else {
break;
}
}
// 找到了
System.out.print("姓名(" + c.getName() + "):");
String name = CMUtility.readString(10, c.getName());
System.out.print("性别(" + c.getGender() + "):");
char sex = CMUtility.readChar(c.getGender());
System.out.print("年龄(" + c.getAge() + "):");
int age = CMUtility.readInt(c.getAge());
System.out.print("电话(" + c.getPhone() + "):");
String phone = CMUtility.readString(11, c.getPhone());
System.out.print("邮箱(" + c.getEmail() + "):");
String email = CMUtility.readString(20, c.getEmail());
Customer newCustomer = new Customer(name, sex, age, phone, email);
boolean isSuccess = customerList.replaceCustomer(number, newCustomer);
if (isSuccess) {
System.out.println("------------修 改 成 功------------");
} else {
System.out.println("------------修 改 失 败------------");
}
}
private void deleteCustomer() {
Customer c;
int number;
System.out.println("\n------------删 除 客 户------------\n");
for(;;) {
System.out.print("请选择待删除客户编号(-1退出):");
number = CMUtility.readInt();
if (number == -1) {
return;
}
c = customerList.getCustomer(number);
if (c == null) {
System.out.println("无法找到指定的客户!");
} else {
break;
}
}
System.out.print("确认是否删除(Y/N):");
char isDelete = CMUtility.readConfirmSelect();
if (isDelete == 'Y') {
boolean isSuccess = customerList.deleteCustomer(number);
if (isSuccess) {
System.out.println("------------删 除 成 功------------");
} else {
System.out.println("------------删 除 失 败------------");
}
}
}
private void listAllCustomers() {
System.out.println("\n------------客 户 列 表------------\n");
int total = customerList.getTotal();
if (total == 0) {
System.out.println("没有客户记录!");
} else {
System.out.println("编号\t\t\t姓名\t\t\t性别\t\t\t年龄\t\t\t电话\t\t\t\t邮箱");
Customer[] customers = customerList.getAllCustomers();
for (int i = 0; i < total; i++) {
Customer c = customers[i];
System.out.println(i + "\t\t\t" + c.getName() + "\t\t\t" + c.getGender() + "\t\t\t"
+ c.getAge() + "\t\t\t" + c.getPhone() + "\t\t\t" + c.getEmail());
}
}
System.out.println("\n------------客 户 列 表------------\n");
}
}