Java-Core四对象与类

39次阅读

共计 3326 个字符,预计需要花费 9 分钟才能阅读完成。

四. 对象与类

4.1 面向对象程序设计概述

4.1.4 类之间的关系

  • 分类:依赖(uses a),聚合(has a),继承(is a)
  • 依赖

    • 一个类的方法操纵另一个类的对象
    • 最常见的关系,最明显的关系
    • 设计中应该遵循尽可能减少依赖,依赖越低,耦合越低
  • 聚合

    • 一个类中包含着另一个类

4.2 使用预定义类

4.2.1 对象与对象变量

1. 对象变量

  • 定义:引用变量的部分
  • 注意

    • 一个对象变量不包含对象,仅仅引用一个对象

4.3 用户自定义类

4.3.4 构造器

  • 规则

    • 构造器与类同名
    • 每个类可以有一个及以上的构造器
    • 构造器可以有 0 至多个参数
    • 构造器没有返回值
    • 构造器随着 new 操作符的执行被调用,无法通过构造器重新设置实例域

4.3.5 隐式参数与显式参数

  • 隐式参数:方法名面前的类对象,使用 this 关键字代表
  • 显式参数:传入方法的参数

    <!– 实现 –>

    public void raise(double ByPercent){double raise = this.salary * ByPercent;}
    /* conclusion
    1.ByPercent 为显式参数
    2.this 为隐式参数,代表类对象
    */

4.3.6 封装的优点

1. 域访问器

  • 定义:返回实例域值的机器
  • 组成

    • 私有数据域
    • 公有的域访问器方法
    • 公有的域更改器方法
  • 格式:public 修饰,返回值为实例域值

    <!– 实现 –>

    // 需求:返回薪水值
    public class Worker{private int salary;}
    // 域访问器
    public int getSalary(){return salary;}
  • 优势

    • 支持修改内部实现,不影响其他代码
    • 支持执行错误检查 <!– 比如判断传入数据是否为空 –>
  • 注意

    • 如果需要返回一个可变数据域的拷贝,使用 clone()

      <!– 实现 –>

      class E{
          ...
          public Date getH(){return (Date)hire.clone();}
      }

4.4 静态域和静态方法

4.4.1 静态域

  • 定义:被 static 修饰的域
  • 特点:静态域属于类,不属于对象。也就是所有对象共享一个静态域

4.4.2 静态常量

  • 常用的静态常量

    • Math.PI

      <!– 实现 –>

      // 定义
      public class Math {public static final double PI = 3.123453454354535345;}
      // 使用
      public class TestMath {public static void main(String[] args) {
              int l = 5;
              double circle = l*l*Math.PI;
              System.out.println(circle);
          }
      }
    • System.out

4.4.3 静态方法

  • 定义:不能向对象实施操作的方法(静态方法是没有 this 参数的方法)
  • 使用场景

    • 方法不需要访问对象状态,所需参数都是通过显示参数提供 <!– 比如 Math.pow–>
    • 方法只需要访问类的静态域 <!– 比如返回静态域内容的 get 方法 –>

4.4.4 工厂方法

  • 定义:静态方法模式,支持返回预期的对象
  • 步骤

    • 创建抽象产品类,定义公共的接口 <!– 需要获得工厂中多种对象,返回方法的变量类型能够统一 –>
    • 创建具体产品类
    • 创建工厂类,创建静态方法来返回具体产品类
    • 外部类调用工厂类中的静态方法获得相应的产品对象

      <!– 实现 –>

      // 抽象产品类,方便产生多种产品类型
      abstract class Product {protected abstract void show();
      }
      // 具体产品类 1
      public class Product1 extends Product {@Override public void show() {System.out.println("Product1");
          }
      }
      
      // 具体产品类 2
      public class Product2 extends Product {@Override public void show() {System.out.println("Product2");
          }
      }
      
      // 具体产品类 3
      public class Product3 extends Product {@Override public void show() {System.out.println("Product3");
          }
      }
      // 工厂类,根据传入参数类型返回相应的对象
      public class ProductFatory {public static Product getProduct(String s){switch (s){
                  default:return null;
                  case "a" :return new Product1();
                  case "b" :return new Product2();
                  case "c" :return new Product3();}
          }
      }
      // 测试类
      public class TestFactory {public static void main(String[] args) {ProductFatory.getProduct("a").show();
              ProductFatory.getProduct("b").show();
              ProductFatory.getProduct("c").show();}
      }
      /* output 
      Product1
      Product2
      Product3
      */
  • Pros

    • 创建实例和使用实例解耦
  • Cons

    • 工厂类出现错误时,整个系统受到影响
    • 违背“开放 - 关闭原则”,新增类需要修改工厂逻辑,工厂类将冗杂

4.5 方法参数

  • 规则:java 按值调用,方法得到的是所有参数值的拷贝

    • 无法修改基本数据类型的值。

      <!– 实现 –>

      // 修改值的方法
      public class Method {public void changeNum(int num){num = num * 3;}
      }
      
      // 测试类
      public class TestMethodParam {public static void main(String[] args) {
              int n = 5;
              Method method = new Method();
              System.out.println(n);
              method.changeNum(n);
              System.out.println(n);
          }
      }
      /* output
      5
      5
      */
      
      /* conclusion
      因为 num 被初始化为 n 值的拷贝,因此修改 num 不会影响 n 的值
      */
      
    • 支持修改对象参数的状态

      原因:形参是对 对象引用的拷贝,因此指向的是对象,当发生修改时,会修改对象中的值

    • 不支持让对象参数引用一个新的对象

      原因:形参是对象引用的拷贝,修改引用无法对原引用造成影响

      原理图:

4.6 对象构造

4.6.1 重载

1. 方法的签名

  • 格式:方法名以及参数类型

    <!– 实现 –>

    indexOf(int)
    

4.6.6 调用另一个构造器

  • 格式:在类中的构造器中使用 this 关键字调用另一个构造器

    <!– 实现 –>

    public class TestCons {
        private int age;
        private String name;
    
        private TestCons(int aAge) {this.age = aAge;}
    
        private TestCons(int aAge , String aName) {this(5);
            this.name = aName;
        }
    
        public static void main(String[] args) {TestCons testCons = new TestCons(4,"Toyz");
            System.out.println(testCons.age);
            System.out.println(testCons.name);
        }
    }
    

4.6.7 初始化数据的方法

  • 方法

    1. 在构造器中设置值

      <!– 实现 –>

      private TestCons(int aAge) {this.age = aAge;}
      
    2. 在声明中赋值

      <!– 实现 –>

      private int age = 5;
      
    3. 在初始化块中赋值(不常见,通常可以在构造器中实现)

      <!– 实现 –>

      {int age = 5;}
      
  • 执行顺序

    1. 所有数据域初始化为默认值
    2. 根据在类中的声明顺序,执行初始化语句(上述方法 2)和初始化域(上述方法 3)
    3. 执行构造器(上述方法 1)

4.10 类设计技巧

  • 一定要保证数据私有性
  • 一定要对数据初始化
  • 不要在类中使用过多的基本类型(使用其他类来代替)
  • 不是所有域都需要独立的域访问和修改器
  • 对职责过多的类进行分解(不然会导致耦合过高)
  • 类名和方法名能够体现职责
  • 优先使用不可变的类

正文完
 0