封装和隐藏

为什么需要封装?封装的作用和含义?

  • 我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部的结构吗?有必要碰电动机吗?
  • 我要开车,…
  • 我们程序设计追求“高内聚,低耦合”。
  • 高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;
  • 低耦合 :仅对外暴露少量的方法用于使用。
  • 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提 高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。

信息的封装和隐藏

Java中通过将数据声明为私有的(private),再提供公共的(public) 方法:getXxx()和setXxx()实现对该属性的操作,以实现下述目的:

  • 隐藏一个类中不需要对外提供的实现细节;
  • 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑, 限制对属性的不合理操作;
  • 便于修改,增强代码的可维护性;
  1. class Animal {
  2. private int legs;// 将属性legs定义为private,只能被Animal类内部访问
  3. public void setLegs(int i) { // 在这里定义方法 eat() 和 move()
  4. if (i != 0 && i != 2 && i != 4) {
  5. System.out.println("Wrong number of legs!");
  6. return; }
  7. legs = i; }
  8. public int getLegs() {
  9. return legs; } }
  10. public class Zoo {
  11. public static void main(String args[]) {
  12. Animal xb = new Animal();
  13. xb.setLegs(4); // xb.setLegs(-1000);
  14. //xb.legs = -1000; // 非法
  15. System.out.println(xb.getLegs());
  16. } }
  1. package com.atguigu.java;
  2. /*
  3. * 面向对象的特征一:封装
  4. * 一、问题引入
  5. * 当我们创建一个类的对象后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。
  6. * 这里赋值操作要受到属性的数据类型和存储范围的制约,除此之外,没有其他制约条件
  7. * 但是,实际问题当中,我们往往需要给属性赋值加入额外的限制条件,这个条件不能在属性声明时体现
  8. * 我们只能通过方法进行限制条件的添加(比如:setLegs),同时避免用户通过"对象.属性"的方式
  9. * ,对对象的属性进行赋值。则需要讲属性声明为私有的(private)
  10. * -->此时,针对属性体现封装性
  11. *
  12. *
  13. * 二、封装性的体现
  14. * 我们将类的属性私有化(private),同时,提供公共(public)的方法来(getXxx)获取
  15. * 和设置(setXxx)此属性的值
  16. *
  17. * 拓展:封装性体现
  18. * 1.如上
  19. * 2.不对外暴露,私有的方法
  20. * 3.单例模式...
  21. *
  22. * 三、封装性的体现,需要权限修饰符来配合
  23. * 1.java规定的四种权限(从小到大排列):private、缺省、protected、public
  24. * 2.4种权限可以用来修饰类以及类的内部结构:属性、方法、构造器、内部类
  25. * 3.具体的,4种权限可以用来修饰类以及类的内部结构:属性、方法、构造器、内部类
  26. * 修饰类的话,只能使用:缺省、public
  27. *
  28. * 总结封装性:Java提供4种权限修饰符来修饰类以及类的内部结构、体现类及类的内部结构在被调用时
  29. * 可见性的大小
  30. */
  31. public class AnimalTest {
  32. public static void main(String[] args) {
  33. Animal a = new Animal();
  34. a.name = "大黄";
  35. // a.age = 1;
  36. // a.legs = 4;//The field Animal.legs is not visible
  37. a.show();
  38. // a.legs = -4;
  39. a.setLegs(6);
  40. a.setLegs(-6);
  41. a.show();
  42. }
  43. }
  44. class Animal{//类
  45. String name;
  46. private int age;
  47. private int legs;//腿的个数
  48. //对属性设置
  49. public void setLegs(int l){
  50. if(l >= 0 && l % 2 == 0){
  51. legs = l;
  52. }else{
  53. legs = 0;
  54. //抛出异常,暂时没讲
  55. }
  56. }
  57. //对属性设置
  58. public int getLegs(){
  59. return legs;
  60. }
  61. public void eat(){
  62. System.out.println("动物进实");
  63. }
  64. public void show(){
  65. System.out.println("name = " + name + ",age = " + age +",legs = " + legs);
  66. }
  67. //提供关于属性age的get和set方法
  68. public int getaAge(){
  69. return age;
  70. }
  71. public void setAge(int a){
  72. age = a;
  73. }
  74. }

对四种权限修饰的测试

  1. package com.atguigu.java;
  2. public class Order {
  3. //类内部
  4. private int orderPrivate;
  5. //同一个包
  6. int orderDefaule;
  7. //同一个工程
  8. public int orderPublic;
  9. private void mathodprivate(){
  10. orderPrivate = 1;
  11. orderDefaule = 2;
  12. orderPublic = 3;
  13. }
  14. void methodDefault(){
  15. orderPrivate = 1;
  16. orderDefaule = 2;
  17. orderPublic = 3;
  18. }
  19. public void methodPublic(){
  20. orderPrivate = 1;
  21. orderDefaule = 2;
  22. orderPublic = 3;
  23. }
  24. }
  1. package com.atguigu.java;
  2. public class OrderTest {
  3. public static void main(String[] args) {
  4. Order order = new Order();
  5. order.orderDefaule = 1;
  6. order.orderPublic = 2;
  7. //出了Order类之后,私有的结构就不可以调用
  8. // order.orderPrivate = 3;//The field Order.orderPrivate is not visible
  9. order.methodDefault();
  10. order.methodPublic();
  11. // order.mathodprivate();//The method mathodprivate() from the type Order is not visible
  12. }
  13. }
  1. package com.atguigu.java1;
  2. import com.atguigu.java.Order;
  3. public class OrderTest {
  4. public static void main(String[] args) {
  5. Order order = new Order();
  6. order.orderPublic = 2;
  7. // 出了Order类所属的包以后,私有结构、缺省声明的结构就不可以调用了
  8. // order.orderDefaule = 1;
  9. //出了Order类之后,私有的结构就不可以调用
  10. // order.orderPrivate = 3;//The field Order.orderPrivate is not visible
  11. order.methodPublic();
  12. // 出了Order类所属的包以后,私有结构、缺省声明的结构就不可以调用了
  13. // order.methodDefault();
  14. // order.mathodprivate();//The method mathodprivate() from the type Order is not visible
  15. }
  16. }

练习

  1. package com.atguigu.exer;
  2. /*
  3. * 1.创建程序,在其中定义两个类:Person和PersonTest类。定义如下:
  4. * 用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。 在 PersonTest 类 中实例化 Person 类的对象 b , 调 用 setAge() 和
  5. * getAge()方法,体会Java的封装性。
  6. *
  7. */
  8. public class Person {
  9. private int age;
  10. public void setAge(int a){
  11. if(a < 0 || a > 130){
  12. System.out.println("传入的数据非法");
  13. return ;
  14. }
  15. age = a;
  16. }
  17. public int getAge(){
  18. return age;
  19. }
  20. }
  1. package com.atguigu.exer;
  2. public class PersonTest {
  3. public static void main(String[] args) {
  4. Person p1 = new Person();
  5. // p1.age = 1;//编译不通过
  6. p1.setAge(12);
  7. }
  8. }

类的成员之三:构造器(或构造方法)

  1. package com.atguigu.java1;
  2. /*
  3. * 类的结构之三:构造器(或构造方法)的使用
  4. * construct
  5. *
  6. * 一、构造器的作用
  7. * 1.创建对象
  8. * 2.初始化对象的信息
  9. *
  10. * 二、说明
  11. * 1.如果没有显示的定义类的构造器的话,系统默认提供一个空参的构造器
  12. * 2.定义构造器的格式:权限修饰符 类名(形参列表){}
  13. * 3.一个类中定义多个构造器,彼此构成重载
  14. * 4.一旦显示定义类的构造器之后,系统不在提供默认的空参构造器
  15. * 5.一个类中,至少有一个构造器
  16. */
  17. public class PersonTest {
  18. public static void main(String[] args) {
  19. //创建类的对象:new + 构造器
  20. Person p = new Person();//类型 变量名 = new 构造器器
  21. p.eat();
  22. Person p1 = new Person("Tom");
  23. System.out.println(p1.name);
  24. }
  25. }
  26. class Person{
  27. //属性
  28. String name;
  29. int age;
  30. //构造器
  31. public Person(){
  32. System.out.println("Person()....");
  33. }
  34. public Person(String n){
  35. name = n;
  36. }
  37. //方法
  38. public void eat(){
  39. System.out.println("吃饭");
  40. }
  41. }

练习

练习1和练习2

  1. package com.atguigu.exer;
  2. /*
  3. * 1.创建程序,在其中定义两个类:Person和PersonTest类。定义如下:
  4. * 用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。 在 PersonTest 类 中实例化 Person 类的对象 b , 调 用 setAge() 和
  5. * getAge()方法,体会Java的封装性。
  6. *
  7. * 2.练习
  8. * 1. 在前面定义的Person类中添加构造器,利用构造器设置所有人的age属性初始值都为18。
  9. * 2. 修改上题中类和构造器,增加name属性,使得每次创建Person对象的同时初始化对象的age属性值和name属性值。
  10. *
  11. */
  12. public class Person {
  13. private int age;
  14. private String name;
  15. public Person(){
  16. age = 18;
  17. }
  18. public Person(String n,int a){
  19. name = n;
  20. age = a;
  21. }
  22. public void setAge(int a){
  23. if(a < 0 || a > 130){
  24. System.out.println("传入的数据非法");
  25. return ;
  26. }
  27. age = a;
  28. }
  29. public int getAge(){
  30. return age;
  31. }
  32. public void setName(String n){
  33. name = n;
  34. }
  35. public String getName(){
  36. return name;
  37. }
  38. }
  1. package com.atguigu.exer;
  2. public class PersonTest {
  3. public static void main(String[] args) {
  4. Person p1 = new Person();
  5. // p1.age = 1;//编译不通过
  6. //p1.setAge(12);
  7. System.out.println("年林" + p1.getAge());
  8. Person p2 = new Person("Jerrmy", 21);
  9. System.out.println("name = " + p2.getAge() + ",age = " + p2.getName());
  10. }
  11. }

练习3

  1. package com.atguigu.exer1;
  2. /*
  3. * 3.编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底
  4. * 边长base和高height,同时声明公共方法访问私有变量。此外,提供类必要的构造器。
  5. * 另一个类中使用这些公共方法,计算三角形的面积。
  6. */
  7. //任何情况都可用
  8. public class TriAngle {
  9. private double base;//底边长
  10. private double height;//高
  11. public TriAngle(){
  12. }
  13. public TriAngle(double b,double h){
  14. base = b;
  15. height = h;
  16. }
  17. public void setBase(double b){
  18. base = b;
  19. }
  20. public double getBase(){
  21. return base;
  22. }
  23. public void setHeight(double h){
  24. height = h;
  25. }
  26. public double getHeight(){
  27. return height;
  28. }
  29. }
  1. package com.atguigu.exer1;
  2. public class TriAngleTest {
  3. public static void main(String[] args) {
  4. TriAngle t1 = new TriAngle();
  5. t1.setBase(2.0);
  6. t1.setBase(2.4);
  7. // t1.base = 2.5;//The field TriAngle.base is not visible
  8. // t1.height = 4.3;//The field TriAngle.height is not visible
  9. System.out.println("base" + t1.getBase() + ",height" + t1.getHeight());
  10. TriAngle t2 = new TriAngle(5.1,5.6);
  11. System.out.println("base" + t1.getBase() + ",height" + t1.getHeight());
  12. }
  13. }

属性赋值的先后顺序

  1. package com.atguigu.java1;
  2. /*
  3. * 总结:属性赋值的先后顺序
  4. *
  5. * 1.默认初始化值
  6. * 2.显示初始化
  7. * 3.构造器中初始化
  8. *
  9. * 4.通过“对象.方法” 或“对象.属性”的方式,赋值
  10. *
  11. * 以上操作的先后顺序:1--> 2 --> 3 --> 4
  12. */
  13. public class UserTest {
  14. public static void main(String[] args) {
  15. User u = new User();
  16. System.out.println(u.age);
  17. User u1 = new User(2);//构造器中赋值
  18. u1.setAge(3);//对象.方法
  19. System.out.println(u1.age);
  20. }
  21. }
  22. class User{
  23. String name;//默认初始化
  24. int age = 1;//显示初始化
  25. public User(){
  26. }
  27. public User(int a){
  28. age = a;
  29. }
  30. public void setAge(int a){
  31. age = a;
  32. }
  33. }

JavaBean

  • JavaBean是一种Java语言写成的可重用组件。

  • 所谓javaBean,是指符合如下标准的Java类:

    • 类是公共的
    • 有一个无参的公共的构造器
    • 有属性,且有对应的get、set方法
  • 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以 用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP 页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用
    户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
  1. package com.atguigu.java1;
  2. /*
  3. * 1.JavaBean是一种Java语言写成的可重用组件。
  4. * 2.所谓javaBean,是指符合如下标准的Java类:
  5. * - 类是公共的
  6. * - 有一个无参的公共的构造器
  7. * - 有属性,且有对应的get、set方法
  8. * 3.用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以 用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP 页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用
  9. *户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
  10. */
  11. public class Customer {
  12. private int id;
  13. private String name;
  14. //构造器的权限默认和类的权限相同
  15. public Customer(){
  16. }
  17. public int getId(){
  18. return id;
  19. }
  20. public void setId(int id){
  21. this.id = id;
  22. }
  23. public String getName(){
  24. return name;
  25. }
  26. public void setName(String name){
  27. this.name = name;
  28. }
  29. }

九、关键字:this的使用

  1. package com.atguigu.java2;
  2. /*
  3. * this关键字的使用
  4. * 1.this可以用来修饰、调用:属性、方法、构造器
  5. *
  6. * 2.this修饰属性和方法:
  7. * this理解为:当前对象 或当前正在创建的对象
  8. *
  9. * 2.1在类的方法当中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象的属性或方法
  10. * 但是,通常情况下,选择省略"this."。特殊情况下,如果方法的形参和属性同名,我们必须显示使用
  11. * "this.变量"的方式,表明此变量是属性,而非形参
  12. *
  13. * 2.2在类的构造器当中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象的属性或方法
  14. * 但是,通常情况下,选择省略"this."。特殊情况下,如果构造器的形参和属性同名,我们必须显示使用
  15. * "this.变量"的方式,表明此变量是属性,而非形参
  16. *
  17. * 3.this调用构造器
  18. * 3.1我们在类的构造器中,可以显示的使用"this(形参列表)"方式,调用本类中指定的其他构造器
  19. * 3.2构造器中不能通过"this(形参列表)"方式,调用自己
  20. * 3.3如果一个类中有n个构造器,则最多有n-1构造器中使用"this(形参列表)"
  21. * 3.4规定:"this(形参列表)"必须在当前构造器首行
  22. * 3.5构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器
  23. */
  24. public class PersonTest {
  25. public static void main(String[] args) {
  26. Person p1 = new Person();
  27. p1.setAge(1);
  28. System.out.println(p1.getAge());
  29. p1.eat();
  30. System.out.println();
  31. Person p2 = new Person("Jerrmy",20);
  32. }
  33. }
  34. class Person{
  35. private String name;
  36. private int age;
  37. public Person(){
  38. //this.eat();
  39. String info = "Person初始化时,需要考虑如下1,2,3,4(共40行代码)";
  40. System.out.println(info);
  41. }
  42. //构造器没有返回值
  43. public Person(String name){
  44. this();//调用空参构造器、且必须在当前构造器首行
  45. this.name = name;
  46. //Person初始化时,需要考虑如下1,2,3,4(共40行代码)
  47. }
  48. public Person(int age){
  49. this();
  50. this.age = age;
  51. //Person初始化时,需要考虑如下1,2,3,4(共40行代码)
  52. }
  53. public Person(String name,int age){
  54. this(age);
  55. this.name = name;
  56. //this.age = age;
  57. //Person初始化时,需要考虑如下1,2,3,4(共40行代码)
  58. }
  59. public void setName(String name){
  60. this.name = name;
  61. }
  62. public String getName(){
  63. return name;
  64. }
  65. public void setAge(int age){
  66. this.age = age;
  67. }
  68. public int getAge(){
  69. return age;
  70. }
  71. public void eat(){
  72. System.out.println("人吃饭");
  73. this.study();
  74. }
  75. public void study(){
  76. System.out.println("人学习");
  77. }
  78. }

练习11

  1. package com.atguigu.exer2;
  2. public class Boy {
  3. private String name;
  4. private int age;
  5. public Boy() {
  6. }
  7. public Boy(String name,int age){
  8. this.name = name;
  9. this.age = age;
  10. }
  11. public String getName() {
  12. return name;
  13. }
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17. public int getAge() {
  18. return age;
  19. }
  20. public void setAge(int age) {
  21. this.age = age;
  22. }
  23. public void marry(Girl girl){
  24. System.out.println("我想娶" + girl.getName());
  25. }
  26. public void shout(){
  27. if(this.age >= 22){
  28. System.out.println("你可以登记结婚了");
  29. }else{
  30. System.out.println("多谈谈恋爱");
  31. }
  32. }
  33. }
  1. package com.atguigu.exer2;
  2. public class Girl {
  3. private String name;
  4. private int age;
  5. public Girl(){
  6. }
  7. public Girl(String name,int age){
  8. this.name = name;
  9. this.age = age;
  10. }
  11. public String getName() {
  12. return name;
  13. }
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17. public void marry(Boy boy){
  18. System.out.println("我想嫁给" + boy.getName());
  19. boy.marry(this);//传递的是Girl类型,this表示当前对象
  20. }
  21. public int compare(Girl girl){
  22. /*if(this.age > girl.age){
  23. return 1;
  24. }else if(this.age < girl.age){
  25. return -1;
  26. }else {
  27. return 0;
  28. }*/
  29. return this.age - girl.age;
  30. }
  31. }
  1. package com.atguigu.exer2;
  2. public class BoyGirlTest {
  3. public static void main(String[] args) {
  4. Boy boy = new Boy("罗密欧", 21);
  5. boy.shout();
  6. Girl girl = new Girl("朱丽叶", 18);
  7. girl.marry(boy);
  8. Girl girl1 = new Girl("祝英台", 18);
  9. int compare = girl.compare(girl1);
  10. if(compare > 0){
  11. System.out.println(girl.getName() + "大");
  12. }else if(compare > 0){
  13. System.out.println(girl1.getName() + "大");
  14. }else{
  15. System.out.println("一样大");
  16. }
  17. }
  18. }

实验1

实验2(难、收获大)

1.按照如下的 UML 类图,创建相应的类,提供必要的结构

3.(封装、构造器、this) - 图1

在提款方法 withdraw()中,需要判断用户余额是否能够满足提款数额的要求,如果不能,

应给出提示。deposit()方法表示存款。

2.按照如下的 UML 类图,创建相应的类,提供必要的结构

3.(封装、构造器、this) - 图2

  1. 按照如下的 UML 类图,创建相应的类,提供必要的结构
    3.(封装、构造器、this) - 图3

    • addCustomer 方法必须依照参数(姓,名)构造一个新的 Customer 对象,然后把
      它放到 customer 数组中。还必须把 numberOfCustomer 属性的值加 1。

    • getNumOfCustomers 方法返回 numberofCustomers 属性值。

    • getCustomer 方法返回与给出的 index 参数相关的客户。

  2. 创建 BankTest 类,进行测试。
    Account

  1. package com.atguigu.exer4;
  2. public class Account {
  3. private double balance;
  4. public Account(double init_balance){
  5. this.balance = init_balance;
  6. }
  7. public double getBalance(){
  8. return balance;
  9. }
  10. //存钱操作
  11. public void deposit(double amt){
  12. if(amt > 0){
  13. balance += amt;
  14. }
  15. }
  16. //取钱操作
  17. public void withdraw(double amt){
  18. if(balance >= amt){
  19. balance -= amt;
  20. System.out.println("取钱成功");
  21. }else{
  22. System.out.println("余额不足");
  23. }
  24. }
  25. }

Bank

  1. package com.atguigu.exer4;
  2. public class Bank {
  3. private Customer[] customers;//存放多个数组
  4. private int numerOfCustomer;//记录客户个数
  5. public Bank(){
  6. customers = new Customer[10];
  7. }
  8. //添加客户
  9. public void addCustomer(String f,String l){
  10. Customer cust = new Customer(f,l);//new一个,创建对象
  11. //报空指针异常,数组没有初始化
  12. customers[numerOfCustomer++] = cust;//存放地址
  13. }
  14. //获取指定位置上客户
  15. public Customer getCustomer(int index) {
  16. if(index >= 0 && index <= numerOfCustomer){
  17. return customers[index];
  18. }
  19. return null;
  20. }
  21. public int getNumerOfCustomer() {
  22. return numerOfCustomer;
  23. }
  24. }

Customer

  1. package com.atguigu.exer4;
  2. public class Customer {
  3. private String firstName;
  4. private String lastName;
  5. private Account account;
  6. public Customer(String f, String l){
  7. this.firstName = f;
  8. this.lastName = l;
  9. }
  10. public Account getAccount() {
  11. return account;
  12. }
  13. public void setAccount(Account account) {
  14. this.account = account;
  15. }
  16. public String getFirstName() {
  17. return firstName;
  18. }
  19. public String getLastName() {
  20. return lastName;
  21. }
  22. }

BankTest

  1. package com.atguigu.exer4;
  2. public class BankTest {
  3. public static void main(String[] args) {
  4. Bank bank = new Bank();
  5. bank.addCustomer("Jane","Smith");
  6. //匿名对象
  7. bank.getCustomer(0).setAccount(new Account(2000));
  8. bank.getCustomer(0).getAccount().withdraw(500);
  9. double balance = bank.getCustomer(0).getAccount().getBalance();
  10. System.out.println("客户 :" + bank.getCustomer(0).getFirstName() +
  11. "账户的余额为:" + balance);
  12. System.out.println("***************************");
  13. bank.addCustomer("万里", "鹏程");
  14. System.out.println("银行客户个数为 " + bank.getNumerOfCustomer());
  15. }
  16. }