day-12-面向对象进阶(包、权限修饰符、抽象类、接口)

面向对象进阶(包、权限修饰符、抽象类、接口)

(一)、包

1.什么是包?

包是用来分门别类的管理各种不同类的,类似于文件夹、建包利于程序的管理和维护。

建包的语法格式:package 公司域名倒写.技术名称。报名建议全部英文小写,且具备意义

package com.itheima.javabean;
public class Student {
    
}

建包语句必须在第一行,一般IDEA工具会帮助创建

2.导包

相同包下的类可以直接访问,不同包下的类必须导包,才可以使用!导包格式:import **包名.类名

假如一个类中需要用到不同类,而这个两个类的名称是一样的,那么默认只能导入一个类,另一个类要带包名访问。

(二)、权限修饰符

1.什么是权限修饰符?

权限修饰符:是用来控制一个成员能够被访问的范围的。

可以修饰成员变量,方法,构造器,内部类,不同权限修饰符修饰的成员能够被访问的范围将受到限制。

2.权限修饰符的分类和具体作用范围:

权限修饰符:有四种作用范围由小到大(private -> 缺省 -> protected - > public )

修饰符 同一 个类中 同一个包中 其他类 不同包下的 子类 不同包下的 无关类
private
缺省
protected
public

代码测试如下:

package com.itheima.d2_modifier.itcast;

public class Fu {
    // 1.private 只能本类中访问
    private void show1() {
        System.out.println("private");
    }

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

    // 3.protected:本类,同一个包下的类中,其他包下的子类
    protected void show3() {
        System.out.println("protected");
    }

    // 4.任何地方都可以
    public void show4() {
        System.out.println("public");
    }

    public static void main(String[] args) {
        //创建Fu的对象,测试看有哪些方法可以使用
        Fu f = new Fu();
        f.show1();
        f.show2();
        f.show3();
        f.show4();
    }
}

demo测试:

package com.itheima.d2_modifier.itcast;

public class Demo {
    public static void main(String[] args) {
        //创建Fu的对象,测试看有哪些方法可以使用
        Fu f = new Fu();
//        f.show1(); // 私有的
        f.show2();
        f.show3();
        f.show4();
    }
}

3.学完权限修饰符需要具备如下能力

能够识别别人定义的成员的访问权限。

自己定义成员(方法,成员变量,构造器等)一般满足如下要求:

成员变量一般私有。

方法一般公开。

如果该成员只希望本类访问,使用private修饰。

如果该成员只希望本类,同一个包下的其他类和子类访问,使用protected修饰。

(三)final

1.final的作用

final 关键字是最终的意思,可以修饰(方法,变量,类)

修饰方法:表明该方法是最终方法,不能被重写。

修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)。

修饰类:表明该类是最终类,不能被继承。

2.final修饰变量的注意

final修饰的变量是基本类型:那么变量存储的数据值不能发生改变。

final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,但是地址指向的对象内容是可以发生变化的。

final没有儿子,不可以更改。

代码解释如下:

package com.itheima.d3_final;

/**
    目标:明白final一些基本语法知识
 */
public class Test {
    // 属于类,只加载一次,可以共享 (常量)
    public static final String schoolName = "黑马";
    public static final String schoolName2;
    static{
        schoolName2 = "传智";
        // schoolName2 = "传智"; // 第二次赋值,报错了!
    }

    // 属于对象的! (final基本上不会用来修饰实例成员变量,没有意义!)
    private final String name = "王麻子";

    public static void main(String[] args) {
       // final修饰变量,变量有且仅能被赋值一次。
        /* 变量有几种:
           局部变量。
           成员变量。
                -- 1、静态成员变量。
                -- 2、实例成员变量。
       */
        final int age;
        age = 12;
        // age = 20; // 第二次赋值,报错了!
        System.out.println(age);

        final double rate = 3.14;

        buy(0.8);

        // schoolName = "传智"; // 第二次赋值,报错了!
        Test t = new Test();
        // t.name = "麻子"; // 第二次赋值,报错了!
        System.out.println(t.name);
    }

    public static void buy(final double z){
        // z = 0.1; // 第二次赋值,报错了!
    }
}

/**
   final修饰类 类不能被继承了
 */
//final class Animal{
//}
//class Cat extends Animal{
//}

/**
   final修饰方法,方法不能被重写
 */
class Animal{
    public final void run(){
        System.out.println("动物可以跑~~");
    }
}

class Tiger extends Animal{
//    @Override
//    public void run() {
//        System.out.println("老虎跑的贼快~~~");
//    }
}

(四)、常量

4.1常量概述和基本作用

4.1.1常量

常量是使用了public static final修饰的成员变量,必须有初始化值,而且执行的过程中其值不能被改变。

常量的作用和好处:可以用于做系统的配置信息,方便程序的维护,同时也能提高可读性。

注意:常量命名规范:英文单词全部大写,多个单词下划线连接起来。

4.1.2常量的执行原理

在编译阶段会进行“宏替换”,把使用常量的地方全部替换成真实的字面量。

这样做的好处是让使用常量的程序的执行性能与直接使用字面量是一样的。

代码效果如下:

package com.itheima.d4_constant;

/**
    目标:学会常量的使用,并理解常量。
 */
public class ConstantDemo1 {
    public static final String SCHOOL_NAME = "传智集团";
    public static final String USER_NAME = "itheima";
    public static final String PASS_WORD = "123456";

    public static void main(String[] args) {
        System.out.println(SCHOOL_NAME);
        System.out.println(SCHOOL_NAME);
        System.out.println(SCHOOL_NAME);
        System.out.println(SCHOOL_NAME);
        System.out.println(SCHOOL_NAME);
        System.out.println(SCHOOL_NAME);

        if(USER_NAME.equals("")){

        }
    }
}

4.2 常量做信息标志和分类

4.2.1案例说明:

现在开发的超级玛丽游戏需要接收用户输入的四个方向的信号(上下左右),以便控制玛丽移动的方向。

选择常量做信息标志和分类:

代码可读性好,实现了软编码形式。

代码如下:

package com.itheima.d4_constant;

import javax.swing.*;
import java.awt.event.ActionEvent;

/**
    目标: 常量的其他作用,做信息标志和信息分类(其实也是一种配置形式)
 */
public class ConstantDemo2 {
    public static final int UP = 1; // 上
    public static final int DOWN = 2; // 上
    public static final int LEFT = 3; // 左
    public static final int RIGHT = 4; // 右

    public static void main(String[] args) {
        // 1、创建一个窗口对象(桌子)
        JFrame win = new JFrame();
        // 2、创建一个面板对象(桌布)
        JPanel panel = new JPanel();
        // 3、把桌布垫在桌子上
        win.add(panel);
        // 4、创建四个按钮对象
        JButton btn1 = new JButton("上");
        JButton btn2 = new JButton("下");
        JButton btn3 = new JButton("左");
        JButton btn4 = new JButton("右");
        // 5、把按钮对象添加到桌布上去
        panel.add(btn1);
        panel.add(btn2);
        panel.add(btn3);
        panel.add(btn4);
        // 6、显示窗口
        win.setLocationRelativeTo(null);
        win.setSize(300,400);
        win.setVisible(true);


        btn1.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                move(UP) ; // 让玛丽往上跳
            }
        });
        btn2.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                move(ConstantDemo2.DOWN) ; // 让玛丽往下跳
            }
        });
        btn3.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                move(LEFT) ; // 让玛丽往左跑
            }
        });
        btn4.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                move(RIGHT) ; // 让玛丽往右跑
            }
        });
    }

    public static void move(int flag){
        // 控制玛丽移动
        switch (flag) {
            case UP:
                System.out.println("玛丽往上飞了一下~~");
                break;
            case DOWN:
                System.out.println("玛丽往下蹲一下~~");
                break;
            case LEFT:
                System.out.println("玛丽往左跑~~");
                break;
            case RIGHT:
                System.out.println("玛丽往→跑~~");
                break;
        }
    }
}

(五)、枚举

5.1枚举的概述

5.1.1枚举的概述

枚举是Java中的一种特殊类型

枚举的作用:“是为了做信息的标志和信息的分类”。

5.1.2定义枚举类的格式:

enum Season{
    SPRING , SUMMER , AUTUMN , WINTER;
}

5.1.3反编译后观察枚举的特征:

Compiled from "Season.java"
    public final class Season extends java.lang.Enum<Season> {
        public static final Season SPRING = new Season();
        public static final Season SUMMER = new Season();
        public static final Season AUTUMN = new Season();
        public static final Season WINTER = new Season();
        public static Season[] values();
        public static Season valueOf(java.lang.String);
    }

5.1.4枚举的特征

枚举类都是继承了枚举类型:java.lang.Enum

枚举都是最终类,不可以被继承。

构造器都是私有的,枚举对外不能创建对象。

枚举类的第一行默认都是罗列枚举对象的名称的。

枚举类相当于是多例模式。

5.2枚举的使用场景演示

案例说明:

现在开发的超级玛丽游戏需要接收用户输入的四个方向的信号(上下左右),以便控制玛丽移动的方向。

选择常量做信息标志和分类。

虽然可以实现可读性,但是入参值不受约束,代码相对不够严谨。

枚举做信息标志和分类:

代码可读性好,入参约束严谨,代码优雅,是最好的信息分类技术!建议使用!

EnumDemo2.java

package com.itheima.d5_enum;

import javax.swing.*;
import java.awt.event.ActionEvent;

/**
    目标: 常量的其他作用,做信息标志和信息分类(其实也是一种配置形式)
 */
public class EnumDemo2 {
    public static void main(String[] args) {
        // 1、创建一个窗口对象(桌子)
        JFrame win = new JFrame();
        // 2、创建一个面板对象(桌布)
        JPanel panel = new JPanel();
        // 3、把桌布垫在桌子上
        win.add(panel);
        // 4、创建四个按钮对象
        JButton btn1 = new JButton("上");
        JButton btn2 = new JButton("下");
        JButton btn3 = new JButton("左");
        JButton btn4 = new JButton("右");
        // 5、把按钮对象添加到桌布上去
        panel.add(btn1);
        panel.add(btn2);
        panel.add(btn3);
        panel.add(btn4);
        // 6、显示窗口
        win.setLocationRelativeTo(null);
        win.setSize(300,400);
        win.setVisible(true);


        btn1.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                move(Orientation.UP) ; // 让玛丽往上跳
            }
        });
        btn2.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                move(Orientation.DOWN) ; // 让玛丽往下跳
            }
        });
        btn3.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                move(Orientation.LEFT) ; // 让玛丽往左跑
            }
        });
        btn4.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                move(Orientation.RIGHT) ; // 让玛丽往右跑
            }
        });
    }

    public static void move(Orientation o){
        // 控制玛丽移动
        switch (o) {
            case UP:
                System.out.println("玛丽往上飞了一下~~");
                break;
            case DOWN:
                System.out.println("玛丽往下蹲一下~~");
                break;
            case LEFT:
                System.out.println("玛丽往左跑~~");
                break;
            case RIGHT:
                System.out.println("玛丽往→跑~~");
                break;
        }
    }
}

orientation.java

package com.itheima.d5_enum;

/**
   做信息标志和分类
 */
public enum Orientation {
    UP, DOWN, LEFT, RIGHT;
}

(六)、抽象类

6.1抽象类概述

6.1.1抽象类

在Java中abstract是抽象的意思,如果一个类中的某个方法的具体实现不能确定,就可以申明成abstract修饰的抽象方法(不能写方法体了),这个类必须用abstract修饰,被称为抽象类day-12-面向对象进阶(包、权限修饰符、抽象类、接口)_第1张图片

6.1.2抽象的使用总结与注意事项

抽象类可以理解成类的不完整设计图,是用来被子类继承的。

一个类如果继承了抽象类,那么这个类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。

6.1.3总结:

1、抽象类的作用是什么样的?

可以被子类继承、充当模板的、同时也可以提高代码复用。

2、抽象方法是什么样的?

只有方法签名,没有方法体,使用了abstract修饰。

3、继承抽象类有哪些要注意?

一个类如果继承了抽象类,那么这个类必须重写完抽象类的全部抽象方法。

否则这个类也必须定义成抽象类。

6.2抽象类的案例

系统需求

某加油站推出了2种支付卡,一种是预存10000的金卡,后续加油享受8****折优惠,另一种是预存5000的银卡 ,后续加油享受8.5****折优惠

l请分别实现2种卡片进入收银系统后的逻辑,卡片需要包含主人名称,余额,支付功能。

分析实现

创建一张卡片父类:定义属性包括主人名称、余额、支付功能(具体实现交给子类)

创建一张白金卡类:重写支付功能,按照原价的8折计算输出。

创建一张银卡类:重写支付功能,按照原价的8.5折计算输出。

代码如下:

Card类:

package com.itheima.d7_abstract_test;

/**
     抽象父类
 */
public abstract class Card {
    private String name; // 主人名称
    private double money;

    /**
      子类一定要支付的,但是每个子类支付的情况不一样,所以父类把支付定义成抽象方法,交给具体子类实现
     */
    public abstract void pay(double money);

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}

GoldCard类:

package com.itheima.d7_abstract_test;

/**
   金卡
 */
public class GoldCard extends Card{
    @Override
    public void pay(double money) {
        // 优惠后的金额算出来:
        double rs = money * 0.8;
        double lastMoney = getMoney() - rs;
        System.out.println(getName() + "当前账户总金额:"
                + getMoney() +",当前消费了:" + rs +",消费后余额剩余:" +
                lastMoney);

        setMoney(lastMoney); // 更新账户对象余额
    }
}

测试类:

package com.itheima.d7_abstract_test;

public class Test {
    public static void main(String[] args) {
        GoldCard c = new GoldCard();
        c.setMoney(10000); // 父类的
        c.setName("三石");
        c.pay(300);
        System.out.println("余额:" + c.getMoney());
    }
}

6.3抽象类的特征、注意事项小结

6.3.1特征和注意事项

Ø有得有失: 得到了抽象方法,失去了创建对象的能力。

Ø抽象类为什么不能创建对象?

Ø 类有的成员(成员变量、方法、构造器)抽象类都具备

Ø抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类

Ø一个类继承了抽象类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。

Ø不能用abstract修饰变量、代码块、构造器。

6.3.2final和abstract是什么关系?

互斥关系

abstract定义的抽象类作为模板让子类继承,final定义的类不能被继承。

抽象方法定义通用功能让子类重写,final定义的方法子类不能重写。

6.4抽象类的应用知识:模板方法模式

6.4.1什么时候使用模板方法模式

**6.4.1.1使用场景说明:**当系统中出现同一个功能多处在开发,而该功能中大部分代码是一样的,只有其中部分可能不同的时候。

6.4.1.2模板方法模式实现步骤

把功能定义成一个所谓的模板方法,放在抽象类中,模板方法中只定义通用且能确定的代码。

模板方法中不能决定的功能定义成抽象方法让具体子类去实现。

案例:

某软件公司要为某银行的业务支撑系统开发一个利息结算系统,账户有活期和定期账户两种,

活期是0.35%,定期是 1.75%,定期如果满10万额外给予3%的收益。

结算利息要先进行用户名、密码验证,验证失败直接提示,登录成功进行结算

模板方法我们是建议使用final修饰的,这样会更专业,那么为什么呢?

答:模板方法是给子类直接使用的,不是让子类重写的,一旦子类重写了模板方法就失效了。

(七)、接口

7.1接口概述、特点

7.1.1接口的定义与特点

接口的格式如下:

接口用关键字interface来定义
public interface 接口名 {
       // 常量
       // 抽象方法
} 

JDK8之前接口中只能是抽象方法和常量,没有其他成分了。

接口不能实例化(不能创建对象)。

接口中的成员都是public修饰的,写不写都是,因为规范的目的是为了公开化。

package com.itheima.d10_interface;

/**
   接口
 */
public interface SportManInterface {
    // 接口中的成员:JDK 1.8之前只有常量 和 抽象方法
    // public static final 可以省略不写,接口默认会为你加上!
    // public static final String SCHOOL_NAME = "黑马";
    String SCHOOL_NAME = "黑马";

    // 2、抽象方法
    //  public abstract 可以省略不写,接口默认会为你加上!
    // public abstract void run();
    void run();

    // public abstract void eat();
    void eat();
}

7.2接口的基本使用:被实现

7.2.1接口的用法

接口是用来被类实现(implements)的,实现接口的类称为实现类。实现类可以理解成所谓的子类。

修饰符 class 实现类 implements 接口1, 接口2, 接口3 , ... {
}
实现的关键字:implements

从上面可以看出,接口可以被类单实现,也可以被类多实现。

7.2.2接口实现的注意事项:

一个类实现接口,必须重写完全部接口的全部抽象方法,否则这个类需要定义成抽象类。

Law接口:

package com.itheima.d11_interface_implements;

public interface Law {
    void rule(); // 遵章守法
}

PingPongMan类

package com.itheima.d11_interface_implements;

/**
   实现类(子类)
 */
public class PingPongMan implements SportMan , Law{
    private String name;
    public PingPongMan(String name) {
        this.name = name;
    }

    @Override
    public void rule() {
        System.out.println(name + "要遵章守法,不能随意外出,酗酒,约会~~~");
    }

    @Override
    public void run() {
        System.out.println(name + "必须要跑步训练~~");
    }

    @Override
    public void competition() {
        System.out.println(name + "需要参加国际比赛~~");
    }
}

SportMan接口:

package com.itheima.d11_interface_implements;

public interface SportMan {
    void run();
    void competition();
}

测试类:

package com.itheima.d11_interface_implements;

public class Test {
    public static void main(String[] args) {
        PingPongMan p = new PingPongMan("张继科");
        p.rule();
        p.run();
        p.competition();
    }
}

7.3接口与接口的关系:多继承

7.3.1基本小结

类和类的关系:单继承。

类和接口的关系:多实现。

接口和接口的关系:多继承,一个接口可以同时继承多个接口。

接口多继承的作用

规范合并,整合多个接口为同一个接口,便于子类实现。

BasketballMan类

package com.itheima.d12_interface_extends;

/**
   实现类
 */
// public class BasketballMan implements Law, SportMan, People {
public class BasketballMan implements SportMan{

    @Override
    public void rule() {

    }

    @Override
    public void eat() {

    }


    @Override
    public void run() {

    }

    @Override
    public void competition() {

    }
}

Law接口:

package com.itheima.d12_interface_extends;

public interface Law {
    void rule(); // 遵章守法
    void eat();
}

People接口:

package com.itheima.d12_interface_extends;

public interface People {
    void eat();
}

SportMan接口:

package com.itheima.d12_interface_extends;

public interface SportMan extends Law, People {
    void run();
    void competition();
}

7.4 JDK8开始接口新增方法

7.4.1第一种:默认方法

类似之前写的普通实例方法:必须用default修饰

默认会public修饰。需要用接口的实现类的对象来调用

default void run(){
    System.out.println("--开始跑--");
}
7.4.2静态方法

默认会public修饰,必须static修饰。

注意:接口的静态方法必须用本身的接口名来调用。

static void inAddr(){
System.out.println("我们都在黑马培训中心快乐的学习Java!");
}

7.4.3私有方法

就是私有的实例方法:,必须使用private修饰,从JDK 1.9才开始有的

只能在本类中被其他的默认方法或者私有方法访问。

private void go(){
System.out.println("--准备--");
}

代码:

package com.itheima.d13_interface_jdk8;

public interface SportManInter {
    /**
       1、JDK 8开始 :默认方法(实例方法)
       -- 必须default修饰,默认用public修饰
       -- 默认方法,接口不能创建对象,这个方法只能过继给了实现类,由实现类的对象调用。
     */
    default void run(){
        go();
        System.out.println("跑的很快~~~");
    }

    /**
      2、静态方法
        必须使用static修饰,默认用public修饰
        -- 接口的静态方法,必须接口名自己调用。
     */
    static void inAddr(){
        System.out.println("我们都在学习Java新增方法的语法,它是Java源码自己会用到的~~~");
    }

    /**
       3、私有方法(实例方法)
         -- JDK 1.9开始才支持的。
         -- 必须在接口内部才能被访问
     */
    private void go(){
        System.out.println("开始跑~~~");
    }

}

class PingPongMan implements SportManInter{
}

class Test{
    public static void main(String[] args) {
        PingPongMan p = new PingPongMan();
        p.run();


        SportManInter.inAddr();
        // PingPongMan.inAddr();
    }
}
7.4.4、JDK8开始后新增了那些方法?

默认方法:default修饰,实现类对象调用。

静态方法:static修饰,必须用当前接口名调用

私有方法:private修饰,jdk9开始才有的,只能在接口内部被调用。

他们都会默认public修饰

7.5使用接口的注意事项

package com.itheima.d14_interface_attention;

public class Test {
    public static void main(String[] args) {
//        1、接口不能创建对象(接口更加彻底的抽象)

//        2、一个类实现多个接口,多个接口中有同样的静态方法不冲突。


//        3、一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,默认用父类的。
            Cat c = new Cat();
            c.eat();
//        4、一个类实现了多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可。

//        5、一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承。

    }
}

//   5、一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承。
//interface AAA{
//    int run();
//}
//interface BBB{
//    void run();
//}
//
//interface CCC extends AAA, BBB{
//}

//   4、一个类实现了多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可。
interface AA{
    default void go(){
        System.out.println("AA");
    }
}
interface BB{
    default void go(){
        System.out.println("BB");
    }
}
class CC implements AA, BB{
    @Override
    public void go() {
    }
}



// 3、一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,默认用父类的。
interface Food{
    default void eat(){
        System.out.println("接口中的吃方法~~");
    }
}
class Animal{
    public void eat(){
        System.out.println("父类动物吃~~");
    }
}
class Cat extends Animal implements Food {
}



interface A{
    static void test(){
        System.out.println("A");
    }
}

interface B{
    static void test(){
        System.out.println("B");
    }
}
/**
 2、一个类实现多个接口,多个接口中有同样的静态方法不冲突。 原因是接口的静态方法不能C调用,只能A调用A的  只能B调用B的
 */
class C implements A,B{

}

你可能感兴趣的:(intellij-idea,java,intellij,idea)