Java第四周学习:第83—— 113章(黑马程序员Java入门教程)

本周学习内容目录

一.ATM系统项目的实现

1.启动ATM系统,展示欢迎页面

public void start() {
        while (true) {
            System.out.println("===欢迎您进入ATM银行系统===");
            System.out.println("1.用户登录");
            System.out.println("2.用户开户");
            System.out.println("请选择你的操作 :");
            int command = scanner.nextInt();
            switch (command) {
                case 1:
                    // 用户登录
                    login();
                    break;
                case 2:
                    // 用户开户
                    createAccount();
                    break;
                default:
                    System.out.println("没有此命令,请重试");
            }
        }
    }

2. 完成用户开户操作

1.创建一个账户对象,用于封装对象的开户信息

2.需要用户输入自己的开户信息,赋值给账户对象

3.把这个用户对象,存入到对象集合中去

/** 完成用户开户操作 */
    private void createAccount(){
        System.out.println("==系统开户操作==");
        // 1.创建一个账户对象,用于封装用户的开户信息
        Account account = new Account();

        // 2.需要用户输入自己的开户信息,赋值给账户对象
        System.out.println("请您输入你的账户名称 ");
        String name = scanner.next();
        account.setUserName(name);

        while (true) {
            System.out.println("请您输入您的性别 :");
            char sex = scanner.next().charAt(0);
            if (sex == '男' || sex == '女'){
                account.setSex(sex);
                break;
            }else {
                System.out.println("你输入的性别有误 !");
            }
        }

        while (true) {
            System.out.println("请你输入你的账户密码 ");
            String passWord = scanner.next();
            System.out.println("请您确认你的密码 :");
            String passWord2 = scanner.next();
            // 判断两次密码是否一样
            if (passWord2.equals(passWord)){
                account.setPassWord(passWord2);
                break;
            }else {
                System.out.println("两次密码不一致,请重试");
            }
        }
        System.out.println("输入每次的取现额度 :");
        double limit = scanner.nextDouble();
        account.setLimit(limit);

        // 重点:我们需要为这个账户生成一个卡号(有系统自动生成,8位数字表示:不能与其他账户的卡号重复)
        String newCardId = createCardId();
        account.setCardId(newCardId);

        // 3.把这个用户对象,存入到账户集合中去
        accounts.add(account);
        System.out.println("恭喜你" + account.getUserName() + "开户成功。你的卡号是:" + account.getCardId());
    }

4.需要为这个账号生成一个卡号(由系统自动生成,8位数字表示,且不能与其他卡号重复)(先随机一个8位数的卡号,在根据卡号查询对象返回进行判断此卡号是否重复)

// 返回一个随机8位数的卡号,且不能与其他卡号重复
    private String createCardId(){
        // 1.定义一个String类型的变量记住一个8位数的卡号
        while (true) {
            String cardId = "";
            // 2.定义循环,循环8次,每次产生的随机数都给cardId连起来
            Random r = new Random();
            for (int i = 0; i < 8; i++) {
                int data = r.nextInt(10);
                cardId += data;
            }
            // 3.判断卡号是否重复
            Account account = getAccountByCardId(cardId);
            if (account == null){
                // 说明cardId没有找到账号对象,因此没有与其他账号的卡号重复,可以返回它成为一个新卡号
                return cardId;
            }
        }
    }

    // 根据卡号查询账户对象返回
    private Account getAccountByCardId(String cardId){
        // 遍历全部的账户对象
        for (int i = 0; i < accounts.size(); i++) {
            Account account = accounts.get(i);
            // 判断这个账户对象acc中的卡号是否是我们要找的卡号
            if (account.getCardId().equals(cardId)){
                return account;
            }
        }
        return null;
    }

3.完成用户的登录操作

1.先判断系统中是否存在账户对象,如果存在,才能登录,如果不存在,我们直接结束登录操作

2.进行登录操作,输入账户的卡号

3.判断账户卡号是否存在

4.卡号存在,则输入登录密码

5.判断密码是否正确,正确的话,则登录成功

/** 完成用户的登录操作 */
    private void login() {
        System.out.println("==系统登录==");
        // 1.判断系统中是否存在账户对象,存在才能登录,如果不存在,我们直接结束登录操作
        if (accounts.size() == 0) {
            System.out.println("当前系统中无任何账户。请先开户");
            return;
        }

        // 2.系统中存在用户对象,可以开始进行登录操作
        System.out.println("请您输入您的卡号 :");
        String cardId = scanner.next();
        // 3.判断卡号是否存在
        Account account = getAccountByCardId(cardId);
        if (account == null) {
            // 卡号不存在
            System.out.println("您输入的卡号不存在,请重试");
        } else {
            // 卡号存在
            while (true) {
                System.out.println("请您输入你的登录密码;");
                String passWord = scanner.next();
                // 判断密码是否正确
                if (account.getPassWord().equals(passWord)) {
                    loginAccount = account;
                    // 密码正确,登录成功
                    System.out.println("恭喜您" + account.getUserName() + "登录成功,您的卡号是:" + account.getCardId());
                    // 展示登录后的操作界面了
                    showUserCommand();
                    return;// 跳出并结束登录后的操作页面
                } else {
                    System.out.println("你输入的密码有误-");
                }
            }
        }
    }

6展示当前登录的账户信息

/** 展示当前登录的账户信息 */
    private void showLoginAccount(){
        System.out.println("==当前您的账户信息如下==");
        System.out.println("卡号:" + loginAccount.getCardId());
        System.out.println("户主:" + loginAccount.getUserName());
        System.out.println("户主性别:" + loginAccount.getSex());
        System.out.println("余额:" + loginAccount.getMoney());
        System.out.println("每次取现额度:" + loginAccount.getLimit());
    }

7.展示登录后的操作页面

/** 展示登录后的操作界面 */
    private void showUserCommand(){
        while (true) {
            System.out.println(loginAccount.getUserName() + "您可以选择以下操作 ");
            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 = scanner.nextInt();
            switch (command){
                case 1:
                    // 查询账户
                    showLoginAccount();
                    break;
                case 2:
                    // 存款
                    depositMoney();
                    break;
                case 3:
                    // 取款
                    drawMoney();
                    break;
                case 4:
                    // 转账
                    transfarMoney();
                    break;
                case 5:
                    // 密码修改
                    updatePassWord();
                    return;// 跳出并结束当前方法
                case 6:
                    // 退出
                    System.out.println(loginAccount.getUserName() + "退出系统成功");
                    return;// 跳出并结束当前方法
                case 7:
                    // 注销当前账户
                    if(deleteAccount()){
                        // 销户成功,回到欢迎页面
                        return;
                    }
                    break;
                default:
                    System.out.println("您输入的命令有误,请重试");
            }
        }
    }

4.存钱

1.输入存款金额

2.更新当前账户的余额

/** 存钱 */
    private void depositMoney() {
        System.out.println("==存款操作==");
        System.out.println("请您输入存款金额");
        double money = scanner.nextDouble();

        // 更新当前账户的余额
        loginAccount.setMoney(loginAccount.getMoney() + money);
        System.out.println("恭喜您,存钱" + money + "成功,先余额为" + loginAccount.getMoney());
    }

5.取款

1.先判断余额是否大于等于100元,如果不足,则不允许取钱

2.判断余额是否足够

3.判断取款金额是否小于等于取款限额

4.更新账户余额

/** 取款 */
    private void drawMoney(){
        System.out.println("==取款操作==");
        // 1.判断账户余额是否达到100元,如果不足100元,则不允许账户取钱
        if (loginAccount.getMoney() < 100){
            System.out.println("您的余额不足100元,不允许取钱");
            return;
        }

        // 2.判断余额是否足够
        while (true) {
            System.out.println("请输入取款金额");
            double getMoney = scanner.nextDouble();

            // 3.判断余额是否足够
            if (loginAccount.getMoney() >= getMoney){
                // 余额足够
                // 4.判断取款金额是否超过单次取款限度
                if (getMoney > loginAccount.getLimit()){
                    System.out.println("此次取款超过单次取款额度,你每次最多取款" + loginAccount.getLimit());
                }else {
                    loginAccount.setMoney(loginAccount.getMoney() - getMoney);
                    System.out.println("恭喜你,取款" + getMoney + "余额还有" +loginAccount.getMoney());
                    // System.out.println("恭喜您,取款成功,您的剩余余额是" + (loginAccount.getMoney() - getMoney) );
                    break;
                }
            } else {
                System.out.println("你的余额不足,余额为" + loginAccount.getMoney());
            }
        }
    }

6.转账

1.要先判断ATM系统中是否存在两个账户

2.然后判断自身账户中是否有钱

3.可以开始转账了

4.输入对方的卡号

5.验证对方的账号是否存在

6.若对方账号存在,则继续验证对方的姓氏

7.然后判断转账金额是否大于自身账户金额,若大于,则更新自身和对方账户的余额

/** 转账 */
    private void transfarMoney() {
        System.out.println("==用户转账==");
        // 1.判断系统中是否有两个账户
        if (accounts.size() < 2){
            System.out.println("当前系统中只要你一个账户,无法进行转账操作");
        }

        // 2.判断自身账户中是否有钱
        if (loginAccount.getMoney() == 0){
            System.out.println("自身账户没钱,不能转账");
            return;
        }

        // 3.真正可以开始转账了
        while (true) {
            System.out.println("请输入要转账用户的卡号");
            String cardId = scanner.next();

            // 4.判断账户卡号是否存在
            Account account = getAccountByCardId(cardId);
            if (account == null){
                System.out.println("您输入的卡号不存在,请重试");
            }else{
                // 对方的账户存在,继续让用户验证姓氏
                String name = '*' + account.getUserName().substring(1);
                System.out.println("请您输入【" + name + "】的姓氏 ");
                String preName = scanner.next();
                // 5.判断认证的姓氏是否正确
                if (account.getUserName().startsWith(preName)){
                    // 姓氏认证通过了,可以开始转账了
                    while (true) {
                        System.out.println("请输入转款金额 :");
                        double money = scanner.nextDouble();
                        // 6.判断转账金额是否超出自身余额
                        if (loginAccount.getMoney() >= money){
                            // 可以转账
                            // 更新自身的账户余额
                            loginAccount.setMoney(loginAccount.getMoney() - money);
                            // 更新对方的账户余额
                            account.setMoney(account.getMoney() + money);
                            System.out.println("恭喜你,转账成功!");
                            return;
                        }else {
                            System.out.println("余额不足,不能转账那么多,最多可转" + loginAccount.getMoney());
                        }
                    }
                }else{
                    System.out.println("您认证的姓氏有误,请重试");
                }
            }
        }
    }

7.销户

1.确认是否进行销户操作

2.查看账户中是否有钱,有的话,不允许销户

/** 消除账户 */
    private boolean deleteAccount() {
        System.out.println("==销户操作==");
        // 1.问问用户是否真的要进行销户操作
        System.out.println("您真的要进行销户吗 y / n");
        String command = scanner.next();
        switch (command){
            case "y":
                // 进行销户
                // 2.判断用户卡中是否还有余额,如果有,则不允许销户
                if (loginAccount.getMoney() == 0){
                    // 销户成功
                    accounts.remove(loginAccount);
                    System.out.println("您的账户已经销户");
                    return true;
                }else {
                    // 卡中有余额,不允许销户,返回操作页面
                    System.out.println("对不起,你的账户中存在余额,无法销户");
                    return false;
                }
            default:
                System.out.println("好的,您的账户保留 ");
                return false;
        }
    }

8.密码修改

1.输入当前账户的密码

2.输入账号的新密码

3.再次输入账号的新密码

4. 比较两次新密码是否一致,一致则密码修改成功

/** 账户密码修改 */
    private void updatePassWord() {
        System.out.println("==账户密码修改操作==");
        //
        while (true) {
            System.out.println("请输入当前账户的密码 :");
            String passWord = scanner.next();
            if (loginAccount.getPassWord().equals(passWord)){
                // 认证通过,
                while (true) {
                    System.out.println("请输入您账户的新密码");
                    String newPassWord = scanner.next();
                    System.out.println("请再一次输入您账户的新密码");
                    String newPassWord2 = scanner.next();
                    if (newPassWord2.equals(newPassWord)){
                        loginAccount.setPassWord(newPassWord);
                        System.out.println("您账户的密码已经修改成功");
                        return;
                    }else {
                        System.out.println("您输入的两次密码不一致,请重试");
                    }
                }
            }else {
                System.out.println("你输入的此账号当前的密码有误");
            }
        }
    }

二.面对对象高级一

1.static修饰符

1.类变量

有static修饰,属于类,在计算机中只有一份,被类的全部对象共享

 // 1.类变量的用法
        // 类名.类变量(推荐)
        Student.name = "袁华";

        // 对象.类变量(不推荐)
        Student s1 = new Student();
        s1.name = "马冬梅";

        Student s2 = new Student();
        s2.name = "秋雅";

        System.out.println(s1.name); // 秋雅
        System.out.println(Student.name); // 秋雅

2.实例变量(对象的变量)

无static修饰,属于每个对象的

// 2.实例变量的用法:属于每个对象的变量
        // 对象.实例变量
        s1.age = 23;
        s2.age = 18;
        System.out.println(s1.age); // 23

        // System.out.println(Student.age); // 报错
      

3.类方法

 // 类方法
    public static void printHelloWorld(){
        System.out.println("Hello World");
        System.out.println("Hello World");
    }
// 1.类方法的用法
        // 类名.类方法(推荐)
        Student.printHelloWorld();

        // 对象.类方法(不推荐)
        Student s = new Student();
        s.printHelloWorld();

4.实例方法

// 实例方法(对象的方法)
    public void printPass(){
        System.out.println("成绩" +
                (score >= 60 ? "及格" : "不及格"));
 // 2.实例方法的用法
        // 对象.实例方法
        s.printPass();
        // Student.printPass(); // 报错

5.使用类方法和实例方法的注意事项

public class Student {
    static String schoolName;// 类变量
    double score;

    // 1.类方法中可以直接访问类的成员,不可以直接访问实例成员
    public static void printHelloWorld(){
        // 注意:同一个类中,访问类成员,可以省略类名不写
        schoolName = "黑马";
        printHelloWorld2();

        // System.out.println(score); // 会报错的
        // printPass(); // 报错的

        // System.out.println(this); // 报错
    }


    // 类方法
    public static void printHelloWorld2(){

    }

    // 2.实例方法中既可以直接访问类成员,也可以直接访问实例成员
    // 实例方法
    // 3.实例方法中可以出现this关键字,类方法中不可以出现this关键字的
    public void printPass(){
        schoolName = "黑马2";
        printHelloWorld2();

        System.out.println(score);
        printPass2();

        System.out.println(this);
    }

    // 实例方法
    public void printPass2(){

    }
}

6.代码块

1.静态代码块

// 格式:static{}
    // 特点:类加载时自动执行,由于类只会加载一次,所有静态代码块也只会执行一次
    // 作用:完成类的初始化,例如:对类变量的初始化赋值
    static {
        System.out.println("静态代码块执行了");
        schoolName = "黑马";
    }

2.实例代码块

// 格式{}
    // 特点:每次创建对象时,执行实例代码块,并在构造器前执行
    // 作用:和构造器一样,都是用来完成对象的初始化的,例如:对实例变量进行初始化赋值
    {
        System.out.println("实例代码块执行了");
    }

    public Student() {
        System.out.println("无参数构造器执行了");
    }

    public Student(String name) {
        System.out.println("有参数构造器执行了");
    }
}

下面这是随机生成验证码的一段代码块,可以直接调用,减少了重复代码的编写

public class MyUtil {
    // 工具类不需要创建对象,建议将工具类的构造器私有化
    private MyUtil(){

    }

    public static String createCode(int n) {
        String code = "";
        String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

        Random r = new Random();
        // 2.开始定义一个循环产生每位随机字符
        for (int i = 0; i < n; i++) {
            // 3.随机一个字符范围内的索引
            int index = r.nextInt(data.length());
            // 4.根据索引在全部字符中提取该字符
            code += data.charAt(index); // code = code + 字符
        }
        return code;
    }
}
  • 上述代码可以直接调用,如:
public class LoginDemo {
    public static void main(String[] args) {
        System.out.println(MyUtil.createCode(4));

    }
}
public class RegisterDemo {
    public static void main(String[] args) {
        System.out.println(MyUtil.createCode(6));
    }
}

2.继承

认识继承

(B类可以通过extends继承A类,则B类为子类,A类为父类)

public class B extends A{
}

继承的特点

父类用private私有化的不能被继承

继承的好处

继承的两个注意事项

  • Java是单继承的,一个类只能继承一个直接父类,Java中的类不支持多继承,但是支持多层继承
  • Object是Java中所有祖宗的类

3.不同权限修饰符的使用(就是在哪能访问,在哪不能方法的问题)

public class Fu {
    // 1.私有:只能在本类中访问
    private void privateMethod(){
        System.out.println("==private==");
    }

    // 2.缺省:本类,同一个包下的类
    void method(){
        System.out.println("==缺省==");
    }

    // 3.protected:本类,同一个包下的类,任意包下的子类
    protected void protectedMethod(){
        System.out.println("==protected==");
    }

    // 4.public: 本类,同一个包下的类,任意包下的子类,任意包下的任意类
    public void publicMethod(){
        System.out.println("==public==");
    }

    public void test(){
        privateMethod();
        method();
        protectedMethod();
        publicMethod();
    }
}

4.方法重写

什么是方法重写

  • 当子类决定父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称,参数列表一样的方法,去覆盖父类的这个方法
  • 注意;重写后,方法的访问,Java会遵循就近原则
    重写前的方法
public class A {
    public void print1(){
        System.out.println("111");
    }

    public void print2(){
        System.out.println("111111");
    }
}

重写后的方法

public class B extends A {
    // 方法重写
    @Override
    public void print1(){
        System.out.println("666");
    }
	@Override
    public void print2(){
        // 方法重写
        System.out.println("666666");
    }
}

方法重写的其他注意事项

1.要使用Override注释,它可以指定Java编辑器,检查我们方法重写的格式是否正确,代码可读性也会更好
2。子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限(public > protected > 缺省)
3.重写的方法返回值类型,必须与别重写方法的返回值类型一样,或者范围更小
4.私有方法,静态方法不能被重写,如果重写会报错的

子类中访问其他成员变量的特点:就近原则
启动项

public class Test {
    public static void main(String[] args) {
        // 目标:掌握子类中访问其他成员的特点:就近原则
        Z z = new Z();
        z.showName();
    }
}

public class Z extends F {
    String name = "子类名称";

    public void showName(){
        String name = "局部名称";
        System.out.println(name); // 局部名称
        System.out.println(this.name); // 子类成员变量,访问子类的成员变量时要这样写
        System.out.println(super.name);// 父类的成员变量
    }

访问子类成员变量时

System.out.println(this.name);

访问父类成员变量时

System.out.println(super.name);

如果直接访问,则是局部的

public void showName(){
        String name = "局部名称";
        System.out.println(name);
        }

在子类方法中访问其他成员(成员变量,成员方法),时按照就近原则的
先子类局部范围找
然后子类成员范围找
然后父类成员范围找,如果父类范围还没有找到则报错

如果子父类中,出现了重名的成员,会优先使用子类的,如果一定要在子类中使用父类的怎么办?
可以通过super关键字,指定访问父类的成员:super。父类成员变量/父类成员方法

5.构造器

调用子类的构造器时会先调用父类的无参数构造器

class F{
    public F() {
        System.out.println("==父类F的无参数构造器执行了==");
    }
}

class Z extends F{
    public Z(){
        // super();// 默认存在的
        System.out.println("==子类Z的无参数构造器执行了==");
    }

    public Z(String name){
        // super();// 默认存在的
        System.out.println("==子类Z的有参数构造器执行了==");
    }
}
public class Test {
    public static void main(String[] args) {
        // 目标:先认识子类构造器的特点,再掌握这个特点的常见应用场景
        Z z = new Z();
        Z z2 = new Z("波妞");
    }
}

执行结果
执行结果

子类调用父类构造器的应用场景

public class Test2 {
    public static void main(String[] args) {
        // 目标:搞清楚子类构造器为什么要调用父类构造器,有啥应用场景
        Teacher t = new Teacher("播妞",19 ,"java");
        System.out.println(t.getName());
        System.out.println(t.getAge());
        System.out.println(t.getSkill());
    }
}

class Teacher extends People{
    private String skill;

    public Teacher(String name,int age,String skill){
        // 调用父类的构造器,(应用场景)
        super("波妞",17);
        this.skill = skill;
    }

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }
}

class People{
    private String name;
    private int age;

    public People() {
    }

    public People(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;
    }
}

通过this(…)调用兄弟构造器


public class Test3 {
    public static void main(String[] args) {
        // 目标:掌握在类中的构造器,通过this(。。。)调用兄弟构造器的作用
        Student s1 = new Student("波仔",19,"淮中");

        // 需求:如果学生没有填写学校,那么学校默认就是黑马程序员
        Student s2 = new Student("里斯",23);
        System.out.println(s1.getName());
        System.out.println(s1.getAge());
        System.out.println(s1.getSchoolName());
        System.out.println(s2.getName());
        System.out.println(s2.getAge());
        System.out.println(s2.getSchoolName());
    }
}

class Student{
    private String name;
    private int age;
    private String schoolName;

    public Student() {
    }

    public Student(String name,int age){
        // this.name = name;
        // this.age = age;
        // this.schoolName = "黑马程序员";
        this(name,age,"黑马程序员");
    }

    public Student(String name, int age,String schoolName) {
        this.name = name;
        this.age = age;
        this.schoolName = schoolName;
    }

    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 String getSchoolName() {
        return schoolName;
    }

    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
    }
}

三.面向对象高级二

1. 多态

(1)前提
有继承或实现关系,存在父类引用子类对象,存在方法重写
对象多态

public class Test {
    public static void main(String[] args) {
        People p1 = new Teacher();
        p1.run();// 识别技巧:编译看左边,运行看右边
        System.out.println(p1.name);// 注意:对于变量,编译看左边,运行也看左边

        People p2 = new Student();
        p2.run();// 识别技巧:编译看左边,运行看右边
        System.out.println(p2.name);// 注意:对于变量,编译看左边,运行也看左边
    }
}

多态的好处

public class Test {
    public static void main(String[] args) {
        // 目标:理解多态的好处
        // 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机应变
        People p1 = new Student();
        p1.run();
        // p1.test();// 多态下存在的问题:无法直接调用子类的独有功能

        // 强制类型转换
        Student s1 = (Student)p1;
        s1.test();

        // 强制类型转换可能存在的问题:编译阶段有继承或者实现关系可以强制类型转换,但是运行时可能出现强制类型转换异常
        // Teacher t1 = (Teacher)p1; // 运行时出现了:ClassCastException
        if (p1 instanceof Student){
            Student s2 = (Student)p1;
            s2.test();
        } else if (p1 instanceof Teacher) {
            Teacher t2 = (Teacher)p1;
            t2.teach();
        }

        System.out.println("-------------------");

        // 好处2:可以使用父类类型的变量作为形参,可以接受一切子类对象
        Student s = new Student();
        go(s);

        Teacher t = new Teacher();
        go(t);

    }

    public static void go(People p){
        p.run();
        if (p instanceof Student){
            Student s = (Student) p;
            s.test();
        } else if (p instanceof Teacher) {
            Teacher t = (Teacher) p;
            t.teach();
        }
    }
}

-上面有个强制类型转换

 // 强制类型转换
        Student s1 = (Student)p1;
        s1.test();

        // 强制类型转换可能存在的问题:编译阶段有继承或者实现关系可以强制类型转换,但是运行时可能出现强制类型转换异常
        // Teacher t1 = (Teacher)p1; // 运行时出现了:ClassCastException
        if (p1 instanceof Student){
            Student s2 = (Student)p1;
            s2.test();
        } else if (p1 instanceof Teacher) {
            Teacher t2 = (Teacher)p1;
            t2.teach();
        }

2.final的使用

注意:
final修饰基本类型的变量,变量存储的数据不能被改变
final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向的内容
常量:通过static final修饰的成员变量被称为常量
常量的命名规范: 建议使用大写英文字母,多个单词使用下划线连接起来

3. 抽象类

认识抽象类和其特点

抽象类中可以不写抽象方法,但有抽象方法的类一定是抽象类
类有的成员(成员变量,方法,构造器)抽象类都具备
抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现
一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义为抽象类

抽象方法

public abstract class A {
    // 抽象方法:必须用abstract修饰,只要方法签名,一定不能有方法体
    public abstract void run();
}

抽象类的好处

更好的支持多态

abstract class Shape {
    // 抽象类中的方法一般要求都是抽象方法,抽象方法没有方法体
    abstract void draw();
}
// 当一个普通类继承一个抽象类后,这个普通类必须重写抽象类中的方法
class Cycle extends Shape {
    @Override
    void draw() {  // 重写抽象类中的draw方法
        System.out.println("画一个圆圈");
    }
}
 
public class Test4 {
    public static void main(String[] args) {
        //Shape shape = new Shape();  抽象类虽然不能直接实例化
        // 但可以把一个普通类对象传给一个抽象类的引用呀,即父类引用指向子类对象
        Shape shape = new Cycle(); // 这称作:向上转型
        
        /*Cycle cycle = new Cycle();
          Shape shape = cycle // 这是向上转型的另一种写法
         */
        shape.draw();         // 通过父类引用调用被子类重写的方法
    }
}

抽象类的应用场景之一

经常用来设计模板方法设计模式

public class Test {
    public static void main(String[] args) {
        // 目标:搞清楚抽象类的应用场景之一:经常用来设计模板方法设计模式
        // 场景:学生,老师都要写一篇作文:我的爸爸
        // 第一段是一样的
        // 正文部分自由发挥
        // 最后一段也是一样的
        Teacher t = new Teacher();
        t.write();

        Student s = new Student();
        s.write();
    }
}
 abstract class People {
    /*
    设计模板方法设计模式
    1.定义一个模板方法出来
     */
    public final void write(){
        System.out.println("\t\t\t\t\t《我的爸爸》");
        System.out.println("\t\t我的爸爸好啊,牛逼啊,来看看我的爸爸有多牛");
        // 2.模板方法并不清楚正文部分到底应该怎么写,但是它知道子类肯定要写
        System.out.println(writeMain());
        System.out.println("有这样的爸爸真好");
    }

    // 3.设计一个抽象方法写正文,具体的实现交给子类来完成
    public abstract String writeMain();
}
 class Student extends People {
    @Override
    public String writeMain(){
        return "我的爸爸很牛";
    }
}
 class Teacher extends People{
    @Override
    public String writeMain(){
        return "我的爸爸很好";
    }
}

4.接口

(1)概述

抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”——接口(Interface)
使用接口的好处

public class Test {
    public static void main(String[] args) {
        // 目标:搞清楚使用接口的好处
        /*
        弥补了类单继承的不足,一个类同时可以实现多个接口
        让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现
         */
        Driver d = new A();
        d.drive();

        Singer s = new A();
        s.sing();

        Student s2 = new A();
        s2.student();

    }
}
class A extends Student implements Driver,Singer{

    @Override
    public void drive() {
        System.out.println("回开车");
    }

    @Override
    public void sing() {
        System.out.println("会唱歌");
    }
}

class Student{
    void student(){
        System.out.println("我是一个学生");
    }
}

interface Driver{
    void drive();
}

interface Singer{
    void sing();
}

在这里插入图片描述

接口的多继承

能够用来有更少的代码量来实现更多的功能

public class Test {
    public static void main(String[] args) {
        // 目标: 理解接口的多继承,作用:便于实现类去实现
    }
}
interface A{
    void test1();
}
interface B{
    void test2();
}
interface C{}

// 接口是多继承的
interface D extends C,B,A{

}
class E implements D{

    @Override
    public void test1() {

    }

    @Override
    public void test2() {

    }
}


接口的几点注意事项

public class Test2 {
    public static void main(String[] args) {
        // 目标:理解使用接口的几点注意事项
        Zi z = new Zi();
        z.run();

    }
}

// 1.一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承
interface I{
    void test1();
}
interface J{
    String test1();
}
// interface K extends I,J{}// 报错,上面方法签名冲突

// 2.一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现


// 3.一个类继承了父类,有同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的
class Fu{
    public void run(){
        System.out.println("===父类中的run()方法执行了===");
    }
}
interface IT{
    default void run(){
        System.out.println("===接口中的run()方法实现了===");
    }
}
class Zi  extends Fu implements IT{

}

// 4.一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可
interface IT1{

}

interface IT2{

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值