封装特性:
封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
优点:隐藏实现细节,提供公共的访问方式;
提高了代码的复用性;
提高了安全性。
封装原则:将不需要对外提供的内容都隐藏起来;
把属性隐藏,提供公共方法对其访问。
封装步骤:1.成员变量私有化;
2.提供对外访问的公共方法setter/getter方法。
注意:this用于当局部变量和成员变量重名时,使用this加以区分,this指代的是成员变量
模拟场景需求:
某校开设:“计算机科学与应用”专业,专业编号J0001,学制4年;
现有3名学生都报名学习了这个专业:
姓名 学号 性别 年龄 嘲风 2016212507 男 25 晨曦 2016212508 女 24 伊人 2016212510 女 24
场景分析:
属性:学生 --> 姓名+性别+年龄+学号; 专业 --> 专业名称+专业编号+专业年限
对象:计算机科学与应用、嘲风、晨曦、伊人
类:学生类(嘲风、晨曦、伊人)、学科专业类(计算机科学与应用)
通过在两个类中实例化四个对象来完成具体场景的实现。
具体步骤:1.创建学生类、学科类;
2.建立类之间的联系; -------------> 即在学生类中表现出他们是学这个专业的。
3.对新增需求的代码维护。
注意:对于私有属性赋值方法有两种
一、是设置无参构造,通过设置setter方法来设置;
二、是设置传参构造,直接通过构造方法赋值。
1.创建学生类与学科类:
public class Student {
//成员属性:学号、姓名、性别、年龄
private String name;
private String idNum;
private String sex;
private int age;
//无参构造
public Student() {}
//多参构造方法,实现对全部属性的赋值
public Student(String name,String idNum,String sex,int age) {
this.setName(name);
this.setIdNum(idNum);
this.setSex(sex);
this.setAge(age);
//this.age = age;这种方式没有对属性的逻辑限定,很容易出错。
}
//私有属性的getter、setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIdNum() {
return idNum;
}
public void setIdNum(String idNum) {
this.idNum = idNum;
}
public String getSex() {
return sex;
}
/**
* 限制性别只能是“男”或者“女”,反之则强制赋值为“男”
* @param sex 传入的年龄
* .equals()方法用于对比字符串的内容,相等则返回true。
* 已知字符串放于.equals方法前面,可以防止空指针异常。
*/
public void setSex(String sex) {
if("男".equals(sex) || "女".equals(sex)) {
this.sex = sex;
}else {
this.sex = "男";
}
}
public int getAge() {
return age;
}
/**
* 给年龄赋值,限定必须在10-80岁之间,反之赋值为18
* @param age 传入的年龄
*/
public void setAge(int age) {
if(age>10 && age<80) {
this.age = age;
}else {
this.age = 18;
}
}
/**
* 自我介绍的方法
* @return 学生的个人信息,包括:姓名、学号、性别、年龄
* 这种字符串的返回方式有利于提高代码的可扩展性,更适合多平台的展示。
*/
public String introduction() {
String str = "学生信息如下:" + "\n姓名:" + this.getName()
+ "\n性别:" + this.getSex() + "\n学号:" + this.getIdNum()
+ "\n年龄:" + this.getAge();
return str;
}
}
public class Major {
private String majorName;
private String idNum;
private int majorYear;
//无参构造方法
public Major() {}
//有参构造方法
public Major(String majorName,String idNum,int majorYear) {
//一般使用setter方法进行属性赋值,因为这样可以利用setter方法内的逻辑判断提高安全系数
this.majorName = majorName;
this.setIdNum(idNum);
this.setMajorYear(majorYear);
}
public String getMajorName() {
return majorName;
}
public void setMajorName(String majorName) {
this.majorName = majorName;
}
public String getIdNum() {
return idNum;
}
public void setIdNum(String idNum) {
this.idNum = idNum;
}
public int getMajorYear() {
return majorYear;
}
//设置专业年限,设置数值必须大于1
public void setMajorYear(int majorYear) {
if(majorYear<=0) {
return;
}
this.majorYear = majorYear;
}
/**
* 专业介绍的方法
* @return 专业的相关信息,包括专业名称、编号、年制
* 此处属性的调用可以使用getter方法,也可以直接使用属性名调用。但是当getter方法中有业务逻辑限制时,则必须使用getter方法;
* 返回字符串类型的对象,在外部输出时选择输出形式,有助于提高代码的复用性;同时也符合面向对象的单一职能原则,只考虑提供功能,而
* 不负责具体的展示功能。
*/
public String info() {
String str = "专业信息如下:" + "\n专业名称:" + majorName + "\n专业编号:" + getIdNum() + "\n专业学制:"
+ getMajorYear();
return str;
}
}
2.建立类之间的联系: --------------------- 即在学生类中表现出他们是学这个专业的。
方案一:对学生类中自我介绍方法进行重载,传入学科名称、学制年限等参数。
注:在进行信息输出的时候,手动在方法中输入学科名称、学制年限等参数信息。
优点:容易理解
缺点:当输入信息过多时,会导致参数列表过长。
/**
* 自我介绍的方法
* @return 学生的个人信息,包括:姓名、学号、性别、年龄
* 这种字符串的返回方式有利于提高代码的可扩展性,更适合多平台的展示。
*/
public String introduction() {
String str = "学生信息如下:" + "\n姓名:" + this.getName()
+ "\n性别:" + this.getSex() + "\n学号:" + this.getIdNum()
+ "\n年龄:" + this.getAge();
return str;
}
/**
* 学生自我介绍的方法
* @param majorName 所学专业名称
* @param majorYear 学制年限
* @return 自我介绍的信息,包括姓名、学号、性别、年龄、所学专业名称、学制年限。
*/
public String introduction(String majorName,int majorYear) {
String str = "学生信息如下:" + "\n姓名:" + this.getName()
+ "\n性别:" + this.getSex() + "\n学号:" + this.getIdNum()
+ "\n年龄:" + this.getAge() + "\n所报专业名称:" + majorName
+ "\n学制年限:" + majorYear;
return str;
}
方案二:对学生类中自我介绍方法进行重载,在方法中添加1个专业对象作为参数,通过其属性获得相关信息。
注:这种方法能够通过对象获得类中的所有对象的属性特征。
优点:更加简单,在方法中只添加1个专业对象作为参数,通过对象的属性获得信息,获取参数也更方便。
缺点:关联性不是很强,只是因为用到了该方法,才需要专业的相关信息。
//对introduction方法进行重载
public String introduction(Major myMajor) {
String str = "学生信息如下:" + "\n姓名:" + this.getName()
+ "\n性别:" + this.getSex() + "\n学号:" + this.getIdNum()
+ "\n年龄:" + this.getAge() + "\n所报专业名称:" + myMajor.getMajorName()
+ "\n学制年限:" + myMajor.getMajorYear() + "\n专业编号:" + myMajor.getIdNum();
return str;
}
方案三:在类中添加专业对象作为成员属性,通过其属性获得相关信息。
分析:作为一个大学生,他必须选择一个专业进行学习。因此可以添加专业信息作为学生类的成员属性存在。此时专业信息的类型即为Major,对于引用数据类型的默认值为null。(私有属性需要设置getter/setter方法)
注意:在调用 专业名称、专业学制 等学科类的属性时,需要先通过getter方法获得学生类的对象属性stuMajor,然后通过对象调用专业类中的属性。
优点:与方案二相比,关联性更强。专业已经成为学生的一个特征了。
/**
* 自我介绍的方法
* @return 学生的个人信息,包括:姓名、学号、性别、年龄、专业名称、专业学制
* 这种字符串的返回方式有利于提高代码的可扩展性,更适合多平台的展示。
*/
public String introduction() {
String str = "学生信息如下:" + "\n姓名:" + this.getName()
+ "\n性别:" + this.getSex() + "\n学号:" + this.getIdNum()
+ "\n年龄:" + this.getAge() + "\n专业名称:" + this.getStuMajor().getMajorName()
+ "\n专业学制:" + this.getStuMajor().getMajorYear();
return str;
}
新增需求:
希望统计计算机科学与应用专业的报名学生人数。
新增需求分析:
1.在专业类中设置一个容器,将报名学生的信息都装进去;
2.遍历容器中学生的人数。
public void addStudent(Student stu) {
/**
* 1.将学生信息保存在数组中;
* 2.将学生个数保存在studentNum中。
*/
//1.将学生信息保存在数组中;
for(int i=0 ; i<this.getMyStudents().length ; i++) {
if(this.getMyStudents()[i] == null) {
this.getMyStudents()[i] = stu;
//2.将学生个数保存在studentNum中
this.studentNum = i+1;
return;
}
}
}
====================================================================
public void addStudent(Student stu) {
int i;
//1.将学生信息保存在数组中;
for(i=0 ; i<this.getMyStudents().length ; i++) {
if(this.getMyStudents()[i] == null) {
this.getMyStudents()[i] = stu;
break;
}
}
//2.将学生个数保存在studentNum中
this.studentNum = i+1;
}