封装和隐藏
为什么需要封装?封装的作用和含义?
- 我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部的结构吗?有必要碰电动机吗?
- 我要开车,…
- 我们程序设计追求“高内聚,低耦合”。
- 高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合 :仅对外暴露少量的方法用于使用。
- 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提 高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
信息的封装和隐藏
Java中通过将数据声明为私有的(private),再提供公共的(public) 方法:getXxx()和setXxx()实现对该属性的操作,以实现下述目的:
- 隐藏一个类中不需要对外提供的实现细节;
- 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑, 限制对属性的不合理操作;
- 便于修改,增强代码的可维护性;
class Animal {
private int legs;// 将属性legs定义为private,只能被Animal类内部访问
public void setLegs(int i) { // 在这里定义方法 eat() 和 move()
if (i != 0 && i != 2 && i != 4) {
System.out.println("Wrong number of legs!");
return; }
legs = i; }
public int getLegs() {
return legs; } }
public class Zoo {
public static void main(String args[]) {
Animal xb = new Animal();
xb.setLegs(4); // xb.setLegs(-1000);
//xb.legs = -1000; // 非法
System.out.println(xb.getLegs());
} }
package com.atguigu.java;
/*
* 面向对象的特征一:封装
* 一、问题引入
* 当我们创建一个类的对象后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。
* 这里赋值操作要受到属性的数据类型和存储范围的制约,除此之外,没有其他制约条件
* 但是,实际问题当中,我们往往需要给属性赋值加入额外的限制条件,这个条件不能在属性声明时体现
* 我们只能通过方法进行限制条件的添加(比如:setLegs),同时避免用户通过"对象.属性"的方式
* ,对对象的属性进行赋值。则需要讲属性声明为私有的(private)
* -->此时,针对属性体现封装性
*
*
* 二、封装性的体现
* 我们将类的属性私有化(private),同时,提供公共(public)的方法来(getXxx)获取
* 和设置(setXxx)此属性的值
*
* 拓展:封装性体现
* 1.如上
* 2.不对外暴露,私有的方法
* 3.单例模式...
*
* 三、封装性的体现,需要权限修饰符来配合
* 1.java规定的四种权限(从小到大排列):private、缺省、protected、public
* 2.4种权限可以用来修饰类以及类的内部结构:属性、方法、构造器、内部类
* 3.具体的,4种权限可以用来修饰类以及类的内部结构:属性、方法、构造器、内部类
* 修饰类的话,只能使用:缺省、public
*
* 总结封装性:Java提供4种权限修饰符来修饰类以及类的内部结构、体现类及类的内部结构在被调用时
* 可见性的大小
*/
public class AnimalTest {
public static void main(String[] args) {
Animal a = new Animal();
a.name = "大黄";
// a.age = 1;
// a.legs = 4;//The field Animal.legs is not visible
a.show();
// a.legs = -4;
a.setLegs(6);
a.setLegs(-6);
a.show();
}
}
class Animal{//类
String name;
private int age;
private int legs;//腿的个数
//对属性设置
public void setLegs(int l){
if(l >= 0 && l % 2 == 0){
legs = l;
}else{
legs = 0;
//抛出异常,暂时没讲
}
}
//对属性设置
public int getLegs(){
return legs;
}
public void eat(){
System.out.println("动物进实");
}
public void show(){
System.out.println("name = " + name + ",age = " + age +",legs = " + legs);
}
//提供关于属性age的get和set方法
public int getaAge(){
return age;
}
public void setAge(int a){
age = a;
}
}
对四种权限修饰的测试
package com.atguigu.java;
public class Order {
//类内部
private int orderPrivate;
//同一个包
int orderDefaule;
//同一个工程
public int orderPublic;
private void mathodprivate(){
orderPrivate = 1;
orderDefaule = 2;
orderPublic = 3;
}
void methodDefault(){
orderPrivate = 1;
orderDefaule = 2;
orderPublic = 3;
}
public void methodPublic(){
orderPrivate = 1;
orderDefaule = 2;
orderPublic = 3;
}
}
package com.atguigu.java;
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
order.orderDefaule = 1;
order.orderPublic = 2;
//出了Order类之后,私有的结构就不可以调用
// order.orderPrivate = 3;//The field Order.orderPrivate is not visible
order.methodDefault();
order.methodPublic();
// order.mathodprivate();//The method mathodprivate() from the type Order is not visible
}
}
package com.atguigu.java1;
import com.atguigu.java.Order;
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
order.orderPublic = 2;
// 出了Order类所属的包以后,私有结构、缺省声明的结构就不可以调用了
// order.orderDefaule = 1;
//出了Order类之后,私有的结构就不可以调用
// order.orderPrivate = 3;//The field Order.orderPrivate is not visible
order.methodPublic();
// 出了Order类所属的包以后,私有结构、缺省声明的结构就不可以调用了
// order.methodDefault();
// order.mathodprivate();//The method mathodprivate() from the type Order is not visible
}
}
练习
package com.atguigu.exer;
/*
* 1.创建程序,在其中定义两个类:Person和PersonTest类。定义如下:
* 用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。 在 PersonTest 类 中实例化 Person 类的对象 b , 调 用 setAge() 和
* getAge()方法,体会Java的封装性。
*
*/
public class Person {
private int age;
public void setAge(int a){
if(a < 0 || a > 130){
System.out.println("传入的数据非法");
return ;
}
age = a;
}
public int getAge(){
return age;
}
}
package com.atguigu.exer;
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
// p1.age = 1;//编译不通过
p1.setAge(12);
}
}
类的成员之三:构造器(或构造方法)
package com.atguigu.java1;
/*
* 类的结构之三:构造器(或构造方法)的使用
* construct
*
* 一、构造器的作用
* 1.创建对象
* 2.初始化对象的信息
*
* 二、说明
* 1.如果没有显示的定义类的构造器的话,系统默认提供一个空参的构造器
* 2.定义构造器的格式:权限修饰符 类名(形参列表){}
* 3.一个类中定义多个构造器,彼此构成重载
* 4.一旦显示定义类的构造器之后,系统不在提供默认的空参构造器
* 5.一个类中,至少有一个构造器
*/
public class PersonTest {
public static void main(String[] args) {
//创建类的对象:new + 构造器
Person p = new Person();//类型 变量名 = new 构造器器
p.eat();
Person p1 = new Person("Tom");
System.out.println(p1.name);
}
}
class Person{
//属性
String name;
int age;
//构造器
public Person(){
System.out.println("Person()....");
}
public Person(String n){
name = n;
}
//方法
public void eat(){
System.out.println("吃饭");
}
}
练习
练习1和练习2
package com.atguigu.exer;
/*
* 1.创建程序,在其中定义两个类:Person和PersonTest类。定义如下:
* 用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。 在 PersonTest 类 中实例化 Person 类的对象 b , 调 用 setAge() 和
* getAge()方法,体会Java的封装性。
*
* 2.练习
* 1. 在前面定义的Person类中添加构造器,利用构造器设置所有人的age属性初始值都为18。
* 2. 修改上题中类和构造器,增加name属性,使得每次创建Person对象的同时初始化对象的age属性值和name属性值。
*
*/
public class Person {
private int age;
private String name;
public Person(){
age = 18;
}
public Person(String n,int a){
name = n;
age = a;
}
public void setAge(int a){
if(a < 0 || a > 130){
System.out.println("传入的数据非法");
return ;
}
age = a;
}
public int getAge(){
return age;
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
}
package com.atguigu.exer;
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
// p1.age = 1;//编译不通过
//p1.setAge(12);
System.out.println("年林" + p1.getAge());
Person p2 = new Person("Jerrmy", 21);
System.out.println("name = " + p2.getAge() + ",age = " + p2.getName());
}
}
练习3
package com.atguigu.exer1;
/*
* 3.编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底
* 边长base和高height,同时声明公共方法访问私有变量。此外,提供类必要的构造器。
* 另一个类中使用这些公共方法,计算三角形的面积。
*/
//任何情况都可用
public class TriAngle {
private double base;//底边长
private double height;//高
public TriAngle(){
}
public TriAngle(double b,double h){
base = b;
height = h;
}
public void setBase(double b){
base = b;
}
public double getBase(){
return base;
}
public void setHeight(double h){
height = h;
}
public double getHeight(){
return height;
}
}
package com.atguigu.exer1;
public class TriAngleTest {
public static void main(String[] args) {
TriAngle t1 = new TriAngle();
t1.setBase(2.0);
t1.setBase(2.4);
// t1.base = 2.5;//The field TriAngle.base is not visible
// t1.height = 4.3;//The field TriAngle.height is not visible
System.out.println("base" + t1.getBase() + ",height" + t1.getHeight());
TriAngle t2 = new TriAngle(5.1,5.6);
System.out.println("base" + t1.getBase() + ",height" + t1.getHeight());
}
}
属性赋值的先后顺序
package com.atguigu.java1;
/*
* 总结:属性赋值的先后顺序
*
* 1.默认初始化值
* 2.显示初始化
* 3.构造器中初始化
*
* 4.通过“对象.方法” 或“对象.属性”的方式,赋值
*
* 以上操作的先后顺序:1--> 2 --> 3 --> 4
*/
public class UserTest {
public static void main(String[] args) {
User u = new User();
System.out.println(u.age);
User u1 = new User(2);//构造器中赋值
u1.setAge(3);//对象.方法
System.out.println(u1.age);
}
}
class User{
String name;//默认初始化
int age = 1;//显示初始化
public User(){
}
public User(int a){
age = a;
}
public void setAge(int a){
age = a;
}
}
JavaBean
JavaBean是一种Java语言写成的可重用组件。
所谓javaBean,是指符合如下标准的Java类:
- 类是公共的
- 有一个无参的公共的构造器
- 有属性,且有对应的get、set方法
- 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以 用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP 页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用
户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
package com.atguigu.java1;
/*
* 1.JavaBean是一种Java语言写成的可重用组件。
* 2.所谓javaBean,是指符合如下标准的Java类:
* - 类是公共的
* - 有一个无参的公共的构造器
* - 有属性,且有对应的get、set方法
* 3.用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以 用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP 页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用
*户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
*/
public class Customer {
private int id;
private String name;
//构造器的权限默认和类的权限相同
public Customer(){
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
九、关键字:this的使用
package com.atguigu.java2;
/*
* this关键字的使用
* 1.this可以用来修饰、调用:属性、方法、构造器
*
* 2.this修饰属性和方法:
* this理解为:当前对象 或当前正在创建的对象
*
* 2.1在类的方法当中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象的属性或方法
* 但是,通常情况下,选择省略"this."。特殊情况下,如果方法的形参和属性同名,我们必须显示使用
* "this.变量"的方式,表明此变量是属性,而非形参
*
* 2.2在类的构造器当中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象的属性或方法
* 但是,通常情况下,选择省略"this."。特殊情况下,如果构造器的形参和属性同名,我们必须显示使用
* "this.变量"的方式,表明此变量是属性,而非形参
*
* 3.this调用构造器
* 3.1我们在类的构造器中,可以显示的使用"this(形参列表)"方式,调用本类中指定的其他构造器
* 3.2构造器中不能通过"this(形参列表)"方式,调用自己
* 3.3如果一个类中有n个构造器,则最多有n-1构造器中使用"this(形参列表)"
* 3.4规定:"this(形参列表)"必须在当前构造器首行
* 3.5构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器
*/
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.setAge(1);
System.out.println(p1.getAge());
p1.eat();
System.out.println();
Person p2 = new Person("Jerrmy",20);
}
}
class Person{
private String name;
private int age;
public Person(){
//this.eat();
String info = "Person初始化时,需要考虑如下1,2,3,4(共40行代码)";
System.out.println(info);
}
//构造器没有返回值
public Person(String name){
this();//调用空参构造器、且必须在当前构造器首行
this.name = name;
//Person初始化时,需要考虑如下1,2,3,4(共40行代码)
}
public Person(int age){
this();
this.age = age;
//Person初始化时,需要考虑如下1,2,3,4(共40行代码)
}
public Person(String name,int age){
this(age);
this.name = name;
//this.age = age;
//Person初始化时,需要考虑如下1,2,3,4(共40行代码)
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
public void eat(){
System.out.println("人吃饭");
this.study();
}
public void study(){
System.out.println("人学习");
}
}
练习11
package com.atguigu.exer2;
public class Boy {
private String name;
private int age;
public Boy() {
}
public Boy(String name,int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void marry(Girl girl){
System.out.println("我想娶" + girl.getName());
}
public void shout(){
if(this.age >= 22){
System.out.println("你可以登记结婚了");
}else{
System.out.println("多谈谈恋爱");
}
}
}
package com.atguigu.exer2;
public class Girl {
private String name;
private int age;
public Girl(){
}
public Girl(String name,int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void marry(Boy boy){
System.out.println("我想嫁给" + boy.getName());
boy.marry(this);//传递的是Girl类型,this表示当前对象
}
public int compare(Girl girl){
/*if(this.age > girl.age){
return 1;
}else if(this.age < girl.age){
return -1;
}else {
return 0;
}*/
return this.age - girl.age;
}
}
package com.atguigu.exer2;
public class BoyGirlTest {
public static void main(String[] args) {
Boy boy = new Boy("罗密欧", 21);
boy.shout();
Girl girl = new Girl("朱丽叶", 18);
girl.marry(boy);
Girl girl1 = new Girl("祝英台", 18);
int compare = girl.compare(girl1);
if(compare > 0){
System.out.println(girl.getName() + "大");
}else if(compare > 0){
System.out.println(girl1.getName() + "大");
}else{
System.out.println("一样大");
}
}
}
实验1
实验2(难、收获大)
1.按照如下的 UML 类图,创建相应的类,提供必要的结构
在提款方法 withdraw()中,需要判断用户余额是否能够满足提款数额的要求,如果不能,
应给出提示。deposit()方法表示存款。
2.按照如下的 UML 类图,创建相应的类,提供必要的结构
按照如下的 UML 类图,创建相应的类,提供必要的结构
addCustomer 方法必须依照参数(姓,名)构造一个新的 Customer 对象,然后把
它放到 customer 数组中。还必须把 numberOfCustomer 属性的值加 1。getNumOfCustomers 方法返回 numberofCustomers 属性值。
getCustomer 方法返回与给出的 index 参数相关的客户。
创建 BankTest 类,进行测试。
Account
package com.atguigu.exer4;
public class Account {
private double balance;
public Account(double init_balance){
this.balance = init_balance;
}
public double getBalance(){
return balance;
}
//存钱操作
public void deposit(double amt){
if(amt > 0){
balance += amt;
}
}
//取钱操作
public void withdraw(double amt){
if(balance >= amt){
balance -= amt;
System.out.println("取钱成功");
}else{
System.out.println("余额不足");
}
}
}
Bank
package com.atguigu.exer4;
public class Bank {
private Customer[] customers;//存放多个数组
private int numerOfCustomer;//记录客户个数
public Bank(){
customers = new Customer[10];
}
//添加客户
public void addCustomer(String f,String l){
Customer cust = new Customer(f,l);//new一个,创建对象
//报空指针异常,数组没有初始化
customers[numerOfCustomer++] = cust;//存放地址
}
//获取指定位置上客户
public Customer getCustomer(int index) {
if(index >= 0 && index <= numerOfCustomer){
return customers[index];
}
return null;
}
public int getNumerOfCustomer() {
return numerOfCustomer;
}
}
Customer
package com.atguigu.exer4;
public class Customer {
private String firstName;
private String lastName;
private Account account;
public Customer(String f, String l){
this.firstName = f;
this.lastName = l;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
BankTest
package com.atguigu.exer4;
public class BankTest {
public static void main(String[] args) {
Bank bank = new Bank();
bank.addCustomer("Jane","Smith");
//匿名对象
bank.getCustomer(0).setAccount(new Account(2000));
bank.getCustomer(0).getAccount().withdraw(500);
double balance = bank.getCustomer(0).getAccount().getBalance();
System.out.println("客户 :" + bank.getCustomer(0).getFirstName() +
"账户的余额为:" + balance);
System.out.println("***************************");
bank.addCustomer("万里", "鹏程");
System.out.println("银行客户个数为 " + bank.getNumerOfCustomer());
}
}