用Java实现ATM银行系统(超详细)

这篇具有很好参考价值的文章主要介绍了用Java实现ATM银行系统(超详细)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

用Java实现ATM银行系统

用Java实现ATM银行系统(超详细)

一、功能概要

1.登陆账户

2.注册账户

3.查询账户

4.取款

5.存款

6.转账

7.修改密码

8.注销账户
 

 二、准备工作----创建账户类,创建集合对象

系统准备内容分析:

每个用户的账户信息都是一个对象,需要提供账户类。
需要准备一个容器,用于存储系统全部账户对象信息。

 ①.一般标准JavaBean的步骤是:

        (1)成员变量私有封装

        (2)构建有参数构造器和重写无参数构造器

        (3)创建getter、setter方法

注:由于ATM系统中的类信息是封装到后面建立的集合类型当中去的,且该信息数据的录入是依靠用户自行注册账户,所以不需要构建有参数构造器,直接使用默认的无参数构造器即可。

package hm_17_ATMBank;

public class Account {
    // 1.成员遍历使用私有封装
    private String UserName;    // 用户名称
    private String Password;    // 用户密码
    private double RemainMoney; // 用户余额
    private double withdrawal;  // 用户单次取现额度
    private String CardId;      // 用户账号

    // 2. getter、setter方法

    public String getUserName() {
        return UserName;
    }

    public void setUserName(String userName) {
        UserName = userName;
    }

    public String getPassword() {
        return Password;
    }

    public void setPassword(String password) {
        Password = password;
    }

    public double getRemainMoney() {
        return RemainMoney;
    }

    public void setRemainMoney(double remainMoney) {
        RemainMoney = remainMoney;
    }

    public double getWithdrawal() {
        return withdrawal;
    }

    public void setWithdrawal(double withdrawal) {
        this.withdrawal = withdrawal;
    }

    public String getCardId() {
        return CardId;
    }

    public void setCardId(String cardId) {
        CardId = cardId;
    }
}

 ② 创建集合数据类型

注意:该集合类型的泛型为刚刚创建的Account类

import java.util.ArrayList;

public class ATM_Main {
    public static void main(String[] args) {
        // 创建集合类
        ArrayList<Account> Accounts = new ArrayList<>();
    }
}

③ 进入页面,选择登录或注册功能

 Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("========欢迎您进入ATM银行系统========");
            System.out.println("1.登录账户");
            System.out.println("2.注册开户");
            System.out.println("请输入命令1、2对应的操作:");
            int command = sc.nextInt();

            switch (command){
                case 1:
                    // 登录账户功能
                    break;
                case 2:
                    // 注册账户功能
                    break;
                default:
                    System.out.println("输入数据有误!请重新输入:");
            }
        }

用Java实现ATM银行系统(超详细)

三、登录和注册功能

1.登录和注册功能

登录和注册是该系统的最基本的功能,也是建立在其他功能之上的功能

用Java实现ATM银行系统(超详细)

 (1)注册功能

目的:

        将用户注册的数据加入到集合当中

步骤:

用Java实现ATM银行系统(超详细)

代码如下:

        该功能最难的就是实现与其他账户的卡号不相同的问题,我这里单独写了方法,方法套方法,因为在后续的转账功能中还需使用!

        注释已经写的很详细了

    private static void register(ArrayList<Account> accounts, Scanner sc) {
        // 创建用户对象,用于后期接收数据(每次调用该方法都会重写创造一个新的用户对象)
        Account account = new Account();

        System.out.println("========ATM银行系统办卡页面========");
        System.out.println("请输入您的姓名:");
        String UserName = sc.next();
        // 将数据加入到类中
        account.setUserName(UserName);
        while (true) {
            System.out.println("请输入您的密码:");
            String Password = sc.next();
            System.out.println("请您再次确认密码:");
            String okPassword = sc.next();
            // 判断两个密码是否相同
            if (Password.equals(okPassword)){
                System.out.println("请设置当日取现额度:");
                double Withdrawal = sc.nextDouble();
                // 加入到集合类型
                account.setWithdrawal(Withdrawal);

                // 随机生成八位数字的账号,且不能与其他账号相同
                // 单独写一个方法
                String CardId = getCardId(accounts,sc);
                // 加入到类中
                account.setCardId(CardId);
                // 将创建的类注入到集合中
                accounts.add(account);
                System.out.println(account.getUserName() + "贵宾,您的账户已开卡成功,您的卡号是:" + account.getCardId());
                // 退出死循环
                break;
            }else{
                System.out.println("两次密码不相同,请重新设置密码:");
            }
        }
    }

    /**
     * 实现随机生成八位账户,且不能与其他账户相同
     * @param accounts 存储数据的集合类型
     * @param sc 扫描器
     */
    private static String getCardId(ArrayList<Account> accounts, Scanner sc) {
        Random r = new Random();
        String CardId;
        // 随机生成随机数8次
        // 0-9
        while (true) {
            CardId = "";
            for (int i = 0; i < 8; i++){
                CardId += r.nextInt(10);
            }
            // 查看是否与集合类型中存储的其他账户相同
            // 单独封装成方法
            boolean flag = getCardIdByAccounts(accounts,CardId);
            // 判断
            if( !flag){
                // 退出死循环
                break;
            }
        }
        return CardId;
    }

    /**
     * 实现 在集合存储的数据中寻找有没有相同的账户
     * @param accounts 存储数据的集合类型
     */
    private static boolean getCardIdByAccounts(ArrayList<Account> accounts, String CardId) {
        boolean flag = false;
        // 变量集合
        for (int i = 0; i < accounts.size(); i++){
            Account a = accounts.get(i);
            if (a.getCardId().equals(CardId)){
                // 如果有相同类型flag就为true
                flag = true;
            }
        }
        // 有相同类型的卡号则返回true,没有相同的则返回false
        return flag;
    }

  文章来源地址https://www.toymoban.com/news/detail-444381.html


总结

package hm_18_ATM;


import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

// ATM入口
public class ATMSystem {
    public static void main(String[] args) {
        // 1. 定义账户类
        // 2.定义一个集合容器,用来装账户的数据
        ArrayList<Account> accounts = new ArrayList<>();
        Scanner sc =new Scanner(System.in);
        a:while (true) {
            // 3.展示系统的首页
            System.out.println("===============欢迎您进入到ATM系统===============");
            System.out.println("1.登录账户");
            System.out.println("2.注册账户");
            System.out.println("0.退出ATM系统");

            int command = sc.nextInt();

            switch(command){
                case 0:
                    // 退出循环
                    break a;
                case 1:
                    // 登录账户
                    login(accounts,sc);
                    break;
                case 2:
                    // 注册账户
                    register(accounts,sc);
                    break;
                default:
                    System.out.println("您输入的操作不存在~~");
            }
        }
    }


    /**
     * 实现登录账户的功能
     * @param accounts 存储账户数据的集合,需要于账户和密码比对
     * @param sc 扫描器
     */
    private static void login(ArrayList<Account> accounts, Scanner sc) {
        System.out.println("===============系统登录===============");
        // 1.判断集合中是否存有数据,如果没有数据则返回主页面
        if (accounts.size() == 0){
            System.out.println("系统中没有存入任何数据,请注册账号后再试~");
            // 直接返回
            return;  // 卫语言风格,解决方法的执行
        }

        System.out.println("请您输入卡号:");
        String CardId;

        while (true) {
            // 2.正式进入登录操作
            CardId = sc.next();

            // 3.判断卡号是否存在,根据卡号去账户集合中查询对象
            // 直接调用前面写的方法即可
            boolean flag = getCountsByCardId(accounts, CardId);
            // 如果有相同的flag == true
            if (flag){
                // 如果在集合中有改卡号,则直接退出死循环
                break;
            }else{
                System.out.println("输入卡号有误!请重新输入:");
            }
        }
        int b = 0;
        c:while (true) {
            // 输入密码
            System.out.println("请您输入密码:");
            String passWord = sc.next();
            // 4.判断密码是否正确
            // 根据卡号找到账号的数据

            for (int i = 0; i < accounts.size(); i++){
                Account a = accounts.get(i);
                // 根据账号匹配数据
                if (a.getCardId().equals(CardId)){
                    // 再判断密码是否匹配
                    if (a.getPassWord().equals(passWord)){
                        System.out.println("密码正确!");
                        // 都匹配的话则进入选择功能页面
                        // 选择功能功能单独封装
                        chooseFunction(a,accounts,sc);
                        break c;
                    }else{
                        if ((3-b) == 0){
                            System.out.println("请您再仔细想想再试~");
                            // 直接退出
                            return; // 卫方法
                        }
                        System.out.println("您还有" + (3-b) + "次机会");
                        b += 1;
                        System.out.println("密码错误!请重新输入密码:");
                    }
                }
            }
        }
    }

    /**
     * 选择功能
     * @param a Account对象,用于接收集合中的数据,a = account.get(i)
     * @param sc 扫描器
     */
    private static void chooseFunction(Account a,ArrayList<Account> accounts, Scanner sc) {
        functionPage(a,accounts,sc);
    }

    /**
     * 功能页面功能
     * @param a Account对象,接收集合中的数据 a = account.get(i)
     */
    private static void functionPage(Account a, ArrayList<Account> accounts, Scanner sc) {

        a:while (true) {
            System.out.println("=========尊敬的" + a.getUserName() + "先生/女士,欢迎您进入ATM银行操作系统========");
            System.out.println("1.查询:");
            System.out.println("2.存款:");
            System.out.println("3.取款:");
            System.out.println("4.转账:");
            System.out.println("5.修改密码:");
            System.out.println("6.退出:");
            System.out.println("7.注销当前账户:");
            System.out.println("您选择的操作:");
            int command = sc.nextInt();

            switch(command){
                case 1:
                    userDetailPage(a,sc);
                    break;
                case 2:
                    deposit(a,sc);
                    break;
                case 3:
                    getMoney(a,sc);
                    break;
                case 4:
                    transfer(a,accounts,sc);
                    break;
                case 5:
                    modify(a,sc);
                    break a;
                case 6:
                    exit();
                    break a;
                case 7:
                    soldAccount(a,accounts,sc);
                    break a;
                default:
                    System.out.println("请输入有效数据!");
            }
        }
    }

    /**
     * 实现删除账户的功能
     * @param a Account的对象
     * @param accounts 集合,存储数据
     * @param sc 扫描器
     */
    private static void soldAccount(Account a, ArrayList<Account> accounts, Scanner sc) {
        System.out.println("您确定要注销账户吗?");
        System.out.println("1.确定");
        System.out.println("2.取消");
        int number = sc.nextInt();
        switch(number){
            case 1:
                accounts.remove(a);
                System.out.println("已删除");
            case 2:
                break;
            default:
                System.out.println("请输入正确内容!");
        }
    }

    /**
     * 实现修改密码功能
     * @param a Account的对象
     * @param sc 扫描器
     */
    private static void modify(Account a, Scanner sc) {
        b:while (true) {
            System.out.println("========欢迎来到ATM银行修改密码页面========");
            System.out.println("请您输入当前账户的密码");
            String passWord = sc.next();
            // 判断密码是否正确
            while (true) {
                if (passWord.equals(a.getPassWord())){
                    System.out.println("请您输入新的密码:");
                    String passWordNew = sc.next();
                    // 确认密码
                    System.out.println("请您确认新的密码:");
                    String passWordNewOk = sc.next();
                    if (passWordNew.equals(passWordNewOk)){
                        // 将集合中存储的密码更换成新的密码(set)
                        a.setPassWord(passWordNewOk);
                        System.out.println("密码修改成功,请您重新登录!");
                        // 退出死循环
                        break b;
                    }else{
                        System.out.println("两次密码不一致,请重新输入密码:");
                    }
                }else{
                    System.out.println("当前密码不正确!请重新输入:");
                    break;
                }
            }
        }
    }

    /**
     * 实现退出回到主页面的功能
     */
    private static void exit() {
        System.out.println("正在退出...");
    }

    /**
     * 实现转账功能
     * @param a Account对象,接收集合中的数据
     * @param accounts  整个集合
     * @param sc 扫描器
     */
    private static void transfer(Account a, ArrayList<Account> accounts, Scanner sc) {
        System.out.println("========欢迎您进入ATM银行用户转账页面========");
        u:while (true) {
            // 判断集合中的账户是否少于两个
            if (accounts.size() < 2){
                System.out.println("当前系统,账户不足2个,无法转账!");
                System.out.println("按任意键返回页面");
                String num = sc.next();
                if(num != null){
                    break;
                }
            }else{
                // 判断自己账户是否还有余额
                if (a.getMoney() < 0){
                    System.out.println("您自己都没钱,就别转了~~");
                    // 跳出循环
                    break;
                }else{
                    // 有余额
                    System.out.println("请您输入转账的账户卡号:");
                    String cardId = sc.next();
                    // 以卡号寻找账户信息
                    // 直接调用方法
                    boolean flag = getCountsByCardId(accounts, cardId);
                    // flag==true说明集合中有相同的
                    if (flag) {
                        // 确认姓氏
                        for (int i = 0; i < accounts.size(); i++) {
                            Account m = accounts.get(i);
                            if (m.getCardId().equals(cardId)){
                                String name = m.getUserName();
                                // 生成姓氏
                                String firstName = name.substring(0,1);
                                // 姓名长度
                                int length = name.length();
                                String print = name.substring(1,length);
                                System.out.println("您当前要为*" + print + "转账!");
                                System.out.println("请您输入姓氏确认:");
                                String firstNameOk = sc.next();
                                // 如果姓氏相同
                                if (firstNameOk.equals(firstName)){
                                    System.out.println("请输入转账的金额!");
                                    double money = sc.nextDouble();
                                    if (money > a.getMoney()){
                                        System.out.println("大哥!您没这么多钱呀!赶紧去搬砖挣钱!");
                                    }else if(money > a.getWithdrawal()){
                                        System.out.println("单次转账额度不足!");
                                    }else{
                                        // 自己的余额减少,别人的余额增加
                                        a.setMoney(a.getMoney()-money);
                                        m.setMoney(m.getMoney()+money);
                                        System.out.println("转账成功!");
                                        // 退出死循环
                                        break u;
                                    }
                                }else{
                                    // 如果输入的姓氏不相同
                                    System.out.println("输入错误!请重新再试!");
                                }
                            }
                        }

                    }else {
                        System.out.println("不存在该账户,请重新确认!");
                    }
                }
            }
        }
    }

    /**
     * 实现取款功能
     * @param a Account对象,接收集合中的数据 a = account.get(i)
     * @param sc 扫描器
     */
    private static void getMoney(Account a, Scanner sc) {
        // 查看集合中是否有余额
        if (a.getMoney() == 0.0){
            System.out.println("大哥,你都没钱,还取啥款~~");
        }else{
            System.out.println("请输入取款的金额:");
            double money = sc.nextInt();
            // 判断取款金额是否比余额多而且判断是否小于一次的取现额度
            if (money <= a.getWithdrawal() && money <= a.getMoney()){
                // 减少余额(原来的余额-要取的)
                a.setMoney(a.getMoney() - money);
                System.out.println("您已经取款成功!");
            } else if (money > a.getWithdrawal()) {
                System.out.println("您当前超出了当次限额!");
            } else if (money > a.getMoney()) {
                System.out.println("大哥,你没钱啊!快去挣钱吧!");
            }
        }
    }

    /**
     * 实现存款功能
     * @param a Account对象,接收集合中的数据 a = account.get(i)
     * @param sc 扫描器
     */
    private static void deposit(Account a, Scanner sc) {
        while (true) {
            System.out.println("========欢迎您进入ATM银行用户存款页面========");
            System.out.println("请您输入要存款的金额:");
            double money = sc.nextDouble();

            if (money > 0) {
                // 如果存款金额正确需要在集合数据中加入存款
                // 如果直接a.setMoney(money) 会替换已有的金额,如果想要相加需要a.setMoney(a.getMoney()+money)
                a.setMoney(a.getMoney() + money);
                System.out.println("存款成功!欢迎您再次使用!");
                // 退出死循环
                break;
            }else{
                System.out.println("输入金额数据错误!请重新输入:");
            }
        }
    }

    /**
     * 用户详情页面
     * @param a  Account对象,接收集合中的数据 a = account.get(i)
     */
    private static void userDetailPage(Account a, Scanner sc) {
        while (true) {
            System.out.println("========欢迎您进入ATM用户详情页面========");
            System.out.println("您的账户页面信息如下:");
            System.out.println("卡号:" + a.getCardId());
            System.out.println("用户名:" + a.getUserName());
            System.out.println("余额:" + a.getMoney());
            System.out.println("当次取现额度:" + a.getWithdrawal());
            System.out.println("按0返回到功能页面");
            int n = sc.nextInt();
            if (n == 0){
                // 退出死循环
                break;
            }else{
                System.out.println("输入有误!请重新再试~");
            }
        }
    }

    /**
     * 用户开户功能的实现
     * @param accounts 存储账户数据的集合
     */
    private static void register(ArrayList<Account> accounts, Scanner sc) {
        // 1.创建用户对象,用于后期接收数据(每次调用该方法都会重写创造一个新的用户对象)
        Account account = new Account();

        System.out.println("===============系统开户===============");

        // 2.录入这个账户的信息加入到对象中去
        System.out.println("请您输入账户:");
        String UserName = sc.next();
        account.setUserName(UserName);

        while (true) {
            System.out.println("请您输入密码:");
            String PassWord = sc.next();
            System.out.println("请您再次输入密码:");
            String OkPassWord = sc.next();

            // 判断两个密码是否相同
            if(PassWord.equals(OkPassWord)){
                // 如果两密码相同则注入到对象中去
                account.setPassWord(OkPassWord);
                // 退出死循环
                break;
            }else{
                System.out.println("对不起,您两次输入的密码不一致,请重新设置密码");
            }
        }


        while (true) {
            System.out.println("请输入账户当次限额");
            double withDrawl = sc.nextDouble();
            if (withDrawl < 0){
                System.out.println("输入数据有误~,请重新输入");
            }else {
                // 注入到对象中其
                account.setWithdrawal(withDrawl);
                // 退出循环
                break;
            }
        }

        // 为账户生成一个随机8位账号且不于其他用户重复(独立功能/独立方法)
        String CardId = getCardId(accounts);
        // 注入到对象中去
        account.setCardId(CardId);

        // 3.将对象添加到集合中去
        accounts.add(account);
        System.out.println("恭喜您" + UserName + "先生/女士" + "您开户成功,您的卡号为:" + CardId + ",请您妥善保管.");
    }

    /**
     * 随机生成8位账号
     * @param accounts 集合,查看是否有重复的账号
     * @return 返回CardId
     */
    private static String getCardId(ArrayList<Account> accounts) {
        Random r = new Random();
        String CardId;
        while (true) {
            CardId = "";
            for (int i = 0; i < 8; i++) {
                CardId += r.nextInt(10);
            }
            // 判断是否有重复的账号(单独封装成方法)
            boolean a = getCountsByCardId(accounts, CardId);
            if (!a){
                // 如果没有相同的
                // 则直接退出死循环
                break;
            }
        }
        return CardId;
    }

    /**
     * 判断是否有相同的账号
     * @param accounts 需要查看数据的集合
     */
    private static boolean getCountsByCardId(ArrayList<Account> accounts, String CardId) {
        boolean flag = false;
        // 遍历集合
        for (int i = 0; i < accounts.size(); i++){
            Account acc = accounts.get(i);
            if (CardId.equals(acc.getCardId())){
                // 如果有相同的则将标识符变为true
                flag = true;
                break;
            }
        }
        // 没有相同的直接返回false
        return flag;
    }

}

到了这里,关于用Java实现ATM银行系统(超详细)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【java】【基础8】入门结业-ATM系统实战

      目录 一、ATM项目技术  二、能达成的能力  三、开始编码 3.1 系统架构搭建、欢迎页设计  3.1.1 Account 3.1.2 ATM  3.1.3 Test 3.2 开户功能实现 3.2.1 修改AccountgetUserName()  3.2.2 ATM 开户操作  3.2.3 ATM为新用户生成一个随机卡号​编辑 3.3 登录功能实现 3.4 操作页展示、查询账户、退出

    2024年02月16日
    浏览(40)
  • java每日一题——ATM系统编写(答案及编程思路)

    基础语句学完,也可以编写一些像样的程序了,现在要做的是多加练习,巩固下知识点,打好基础,daydayup! 题目:模仿银行ATM系统,可以创建用户,存钱,转账,修改密码注销账户等操作 思路:利用面向对象编程:1, 定义一个账户类 Account,至少需要包含(卡号、姓名、性

    2024年01月20日
    浏览(38)
  • 基于Javaweb实现ATM机系统开发实战(十)取款功能实现

    老规矩,先看前端页面:  创建同名servlet: 接口: 实现类: 数据层: 这里我们为了方便实现交易记录的查询,先创建一个实体类:

    2024年02月15日
    浏览(42)
  • 基于Javaweb实现ATM机系统开发实战(八)实时查询余额功能实现

    老规矩,先看前端页面,把前端页面上没有的表达式都删掉:  创建servlet接受和处理请求: 接口: 实现类: 数据层: 测试一下就发现余额查询成功啦~  

    2024年02月16日
    浏览(57)
  • 基于Javaweb实现ATM机系统开发实战(四)用户修改删除功能实现

    我们点一下修改,发现页面进行了跳转,跳转到了/toUpdate,并传递了用户的卡号。  我们可以先查看一下用户列表展示界面的前端代码:userlist.jsp,可以看到前端代码中做了跳转的动作,我们需要在后端中完成相应的servlet完成这个动作。  首先,创建UserToUpdateServlet,对用户

    2024年02月13日
    浏览(36)
  • 基于Javaweb实现ATM机系统开发实战(十一)存储交易记录

    首先创建一个业务接口: 再完成业务接口的实现类: 在创建数据层的持久化类: 在存款中调用接口来保存交易记录: 取款中也是一样的: 然后我们重启一下系统,存个钱测试一下; 发现交易记录已经成功保存啦~  代码已上传~

    2024年02月16日
    浏览(42)
  • 基于Javaweb实现ATM机系统开发实战(十四)交易记录分页实现

    还是老规矩,先看前端页面查看需要传递哪些参数,并且把逻辑有问题的部分进行修改~ 创建一个PageBean对象,封装这些数据: 之前我们把查询交易明细的代码都写到Userservice中了,其实应该写到RunMessageService中,对应的数据层和实现类也是同样的操作~ 然后对交易记录的Serv

    2024年02月16日
    浏览(36)
  • 操作系统银行家算法(JAVA/Python/C#/JavaScript/C/C++)代码实现

    银行家算法是一种资源分配和死锁避免算法,它通过模拟所有资源的预定最大可能数量的分配来测试安全性,然后进行“s状态”检查以测试可能的活动,然后决定是否应该允许继续分配。 Banker’s algorithm 之所以叫“银行家算法”,是因为它在银行系统中被用来检查贷款是否

    2024年02月06日
    浏览(69)
  • 银行家算法——C++实现 [ 开源代码 + 详细解析 ]

    ✅ (原创,纯手敲,开源免费,2021的最后一篇) Banker Algorithm 🏦 ◆ 说明 :上述算法的核心实现采用了 “DFS + 回溯” 的方法,详见后文的源代码。另外,如果把 C++ 代码里面的 “ p_num=1; ” 注释掉,得到的是另一个结果。我虽然输入是“0”,但代码里后面我直接把 p_num 赋值

    2023年04月26日
    浏览(71)
  • JAVA项目--银行管理系统

    1、项目描述 银行管理系统:实现登录、注册,登录后的用户可以进行存款、取款、转账、查询余额操作 2、分析 创建银行类Bank:用于存储银行卡信息,并创建银行系统的主窗体 创建银行卡类BankCard:初始化银行卡信息 创建用户操作类User:进行存款、取款、转账、查询余额

    2024年02月11日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包