面向对象(三)

103 阅读9分钟
1、封装性
  • 为什么需要封装?封装的作用和含义?

    • 程序设计追求【高内聚,低耦合】
      • 高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;
      • 低耦合 :仅对外暴露少量的方法用于使用。
    • 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
  • 封装与隐藏

    • 当我们创建一个类的对象以后,可以通过【对象.属性】的方式,对对象的属性进行赋值。这里,赋值操作要受属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,只能通过方法进行限制条件的添加。比如【setLegs()】,同时需要避免用户再使用【对象.属性】的方式对属性进行赋值。则需要将属性声明为私有的【private】,此时,针对于属性就体现了封装性。

    • 封装性的一些体现

      • 将类的属性Xxx私有化【private】,同时提供公共的【public】方法来获取【getXxx】和设置【setXxx】此属性的值。
      • 不对外暴露的私有方法
      • 单例模式
      • 等等......
    public class AnimalTest {
        public static void main(String[] args) {
            Animal A = new Animal();
            A.setLegs(4);
            System.out.println(A.getLegs());
        }
    }
    class Animal{
        private int legs;
    
        //对属性的设置
        public void setLegs(int legs){
            if (legs > 0){
                this.legs = legs;
            }else {
                this.legs = 0;
            }
        }
    
        //对属性的获取
        public int getLegs(){
            return this.legs;
        }
    
        public String getInfo(){
            return "腿的条数为:" + this.legs;
        }
    }
    

2、权限修饰符
  • 4种权限
修饰符 类内部 同一个包不同类 不同包的子类 不同包的普通类
private Yes
(缺省) Yes Yes
protected Yes Yes Yes
public Yes Yes Yes Yes
  • 说明

    • 对于class的权限修饰只可以用public和default(缺省);
    • 4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类;
  • private、(缺省)、public权限的测试

    • 同一个类内部

      package com.wj2;
      
      public class Order{
          private int orderPrivate;
          int orderDefault;
          public int orderPublic;
      
          private void methodPrivate(){
              orderPrivate = 1;
              orderDefault = 2;
              orderPublic = 3;
          }
          void methodDefault(){
              orderPrivate = 1;
              orderDefault = 2;
              orderPublic = 3;
          }
          public void methodPublic(){
              orderPrivate = 1;
              orderDefault = 2;
              orderPublic = 3;
          }
      }
      
    • 同一个包不同类

      package com.wj2;
      
      public class OrderTest {
          public static void main(String[] args) {
              Order order = new Order();
      
              order.orderDefault = 1;
              order.orderPublic = 2;
      //        出了Order类后私有结构就不能调用了
      //       order.orderPrivate = 3;
      
              order.methodDefault();
              order.methodPublic();
      //        出了Order类后私有结构就不能调用了
      //        order.methodPrivate();
          }
      }
      public class Order{
          private int orderPrivate;
          int orderDefault;
          public int orderPublic;
      
          private void methodPrivate(){
              orderPrivate = 1;
              orderDefault = 2;
              orderPublic = 3;
          }
          void methodDefault(){
              orderPrivate = 1;
              orderDefault = 2;
              orderPublic = 3;
          }
          public void methodPublic(){
              orderPrivate = 1;
              orderDefault = 2;
              orderPublic = 3;
          }
      }
      
    • 不同包的普通类

      package com.wj1;//不同包
      
      import com.wj2.Order;
      
      public class OrderTest {
          public static void main(String[] args) {
              Order order = new Order();
      
              order.orderPublic = 1;
      //        出了Order类所处的包之后,私有的结构和缺省声明的结构都不能调用了
      //        order.orderDefault = 2;
      //        order.orderPrivate = 3;
      
              order.methodPublic();
      //        出了Order类所处的包之后,私有的结构和缺省声明的结构都不能调用了
      //        order.methodDefault();
      //        order.methodPrivate();
          }
      }
      
  • 总结封装性

    Java提供4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性大小


3、构造器
  • 构造器的作用:1. 创建对象;2. 给对象进行初始化;

    • 说明

      • 如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器;

      • 定义构造器的格式:【权限修饰符 类名 (形参列表){}】;

      • 一个类中定义的多个构造器构成重载;

      • 一旦显式的定义构造器后,系统就不再提供默认的空参构造器了;

      • 一个类中,至少会有一个构造器;

        public class PersonTest {
            //创建对象:new + 构造器
            Person p = new Person();
        	Person p2 = new Person("tom");
        }
        class Person{
            //属性
            String name;
            int age;
        
            //构造器,构成重载
            public Person(){
                System.out.println("Person()...");
            }
            public Person(String name){
                this.name = name;
            }
        
        
            //方法
            public void eat(){
                System.out.println("人吃饭");
            }
            public void study(){
                System.out.println("人学习");
            }
        }
        

4、总结属性赋值的过程
  • 赋值的位置:

    1. 默认初始化;
    2. 显式初始化;
    3. 构造器中初始化;
    4. 通过【对象.属性】或【对象.方法】的方式赋值;
  • 赋值的先后顺序:1-2-3-4

    public class UserTest {
        public static void main(String[] args) {
            User u = new User(3);
            System.out.println(u.age);//3
            u.setAge(4);
            System.out.println(u.age);//4
        }
    }
    class User{
        String name;
        int age = 1;
    
        public User(int age){
            this.age = age;
        }
    
        public void setAge(int age){
            this.age = age;
        }
    }
    

5、JavaBean的使用
  • JavaBean是一种Java语言写成的可重用组件;

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

    • 类是公共的;
    • 有一个无参的公共的构造器;
    • 有属性,且有对应的get、set方法;
  • 说明:

    用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP 页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。

  • 例子:

    public class JavaBean {
        private String name; // 属性一般定义为private
        private int age;
        public JavaBean() {
            
        }
    	public int getAge() {
    		return this.age;
    	}
    	public void setAge(int age) {
    		this.age = age;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    }
    

6、UML类图


7、this关键字
  • this关键字的使用
    1. this可以用来修饰、调用:属性、方法和构造器;
    2. this修饰该属性和方法:
      • this理解为:当前对象或当前正在创建的对象;
      • 在类的方法或者构造器中,可以使用【this.属性】或【this.方法】的方式,来调用当前对象的属性或方法;
      • 通常情况下可以省略【this】,但是当方法的形参和类的属性同名时,则必须显式的使用【this.变量】的方式,以此来表明该变量是属性,而不是形参;
    3. this调用构造器
      • 在类的构造器中,可以显式的用【this(形参列表)】的方式来调用本类中其他构造器;
      • 构造器中不能通过【this(形参列表)】的方式调用自己;
      • 如果一个类中有n个构造器,那么最多只能有n-1个构造器使用了【this(形参列表)】的方式;
      • 【this(形参列表)】必须声明在当前构造器的首行;
      • 构造器内部,最多只能声明一个【this(形参列表)】,来调用其他的构造器;

8、综合练习1

public class Account_Customer_Test {
    public static void main(String[] args) {
        Customer cust = new Customer("Jane" , "Smith");
        Account acct = new Account(1000,2000,0.0123);
        cust.setAccount(acct);

        cust.getAccount().deposit(100);
        cust.getAccount().withdraw(960);
        cust.getAccount().withdraw(2000);

        System.out.println("Customer [" + cust.getLastName() + cust.getFirstName() +
                "] has a account:id is " + acct.getId() + ",annualInterestRate is " +
                acct.getAnnualInterestRate()*100 + "%,balance is " + acct.getBalance());
    }
}
class Account{
    private int id;//账号
    private double balance;//余额
    private double annualInterestRate;//年利率

    public Account (int id, double balance, double annualInterestRate ){
        this.id = id;
        this.balance = balance;
        this.annualInterestRate = annualInterestRate;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public double getAnnualInterestRate() {
        return annualInterestRate;
    }

    public void setAnnualInterestRate(double annualInterestRate) {
        this.annualInterestRate = annualInterestRate;
    }

    //在提款方法 withdraw 中,需要判断用户余额是否能够满足提款数额的要求,如果不
    //能,应给出提示。
    //取钱
    public void withdraw (double amount){
        if (balance < amount){
            System.out.println("余额不足,取款失败");
            return;
        }
        balance -= amount;
        System.out.println("成功取出" + amount + "钱");
    }
    //存钱
    public void deposit (double amount){
        if (amount > 0){
            balance += amount;
            System.out.println("成功存入" + amount + "钱");
        }
    }

}
class Customer{
    private String firstName;
    private String lastName;
    private Account account;

    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    public Account getAccount() {
        return account;
    }
}

9、综合练习2

public class BankTest {
    public static void main(String[] args) {
        //造一个银行
        Bank bank = new Bank();
        //添加一个客户
        bank.addCustomer("Jane" , "Smith");
        //为该客户办一个账户,余额为2000
        bank.getCustomer(0).setAccount(new Account(2000));
        //取出500元
        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("四" , "李");
        //获取当前客户个数
        int number = bank.getNumOfCustomers();
        System.out.println("当前客户个数为:"+number);
    }
}
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){
            amt += balance;
            System.out.println("存钱成功");
        }
    }

    //取钱
    public void withdraw (double amt){
        if (balance >= amt){
            balance -= amt;
            System.out.println("取钱成功");
        }else{
            System.out.println("余额不足");
        }
    }
}
class Customer{
    private String firstName;
    private String lastName;
    private Account account;

    public Customer(String f, String l) {
        this.firstName = f;
        this.lastName = l;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    public Account getAccount() {
        return account;
    }
}
class Bank{
    private Customer[] customers ;//可以存放多个客户的数组
    private int numberOfCustomer ;//记录客户的个数

    public Bank() {
        //初始化数组
        customers = new Customer[10];
    }

    //添加客户
    public void addCustomer(String f , String l){
        Customer cust = new Customer(f,l);
//        customers[numberOfCustomer] = cust;
//        numberOfCustomer++;
//        或者这么写
        customers[numberOfCustomer++] = cust;
    }

    //获取客户的个数
    public int getNumOfCustomers(){
        return this.numberOfCustomer;
    }

    //获取指定位置上的客户
        public Customer getCustomer(int index){
            if (index >= 0 && index < numberOfCustomer){
                return customers[index];
            }
            return  null;
    }
}

10、package关键字
  1. 为了更好地实现项目中类的管理,提供包的概念;
  2. 使用Package声明类或接口所属的包,声明在源文件的首行;
  3. 包,属于标识符,遵循标识符的命名规则、规范,【见名知意】;
  4. 包对应于文件系统的目录,package语句中,用 【.】来指明包(目录)的层次,包通常用小写单词标识。通常使用所在公司域名的倒置:【com.atguigu.xxx】;
  5. 同一个包下不能命名同名的接口、类;不同包下就可以;
  • 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)。 B/S C/S

11、MVC设计模式


12、import关键字
  1. 在源文件中使用import显式的导入指定包下的类、接口,import语句告诉编译器到哪里去寻找类;
  2. 声明在包的声明和类的声明之间;
  3. 如果需要导入多个类或接口,那么就并列显式多个import语句即可;
  4. 举例:可以使用java.util.*的方式,一次性导入util包下所有的类或接口;
  5. 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句;
  6. 如果在代码中使用不同包下的同名的类。那么至少有一个类就需要使用类的全类名的方式指明调用的是哪个类;
  7. 如果已经导入java.a包下的类。那么如果需要使用a包的子包下的类的话,仍然需要导入;
  8. import static组合的使用:调用指定类或接口下的静态的属性或方法;