0
点赞
收藏
分享

微信扫一扫

Java SE基础知识详解第[8]期—面向对象进阶(包、权限修饰符、抽象类、接口)

秀儿2020 2022-04-18 阅读 56
java学习

目录

1.包

2.权限修饰符

3.final

4.枚举

5.抽象类

5.1抽象类概念

5.2抽象类案例

5.3抽象类的特征、注意事项:

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

6.接口

6.1接口的概述、特点

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

6.3JDK8开始接口新增方法

6.4接口注意事项


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

1.

什么是包?

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

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

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

导包

        相同包下的类可以直接访问,不同包下的类必须导包才可以使用。

        导包格式:import 包名.类名;

        若一个类中需要用到不同包下的两个同名类,那么默认只能导入一个类另一个类要带包名访问

        示例代码如下:

        现有一个包com.itheima.d1_package,包下有User类和Test类,两个包com.itheima.d1_package.testanotherpackage和com.itheima.d1_package.testanotherpackage2,每个包下均有学生类Student。

package com.itheima.d1_package;

// 导包
import com.itheima.d1_package.testanotherpackage.Student;
//import com.itheima.d1_package.testanotherpackage2.Student; // 报错,在实例化Student对象时会引起歧义,所以同名包只能导入一个,其他的用全包名.类名的形式访问,无需导入

public class Test {
    public static void main(String[] args) {
        // 相同包下的类可以直接互相访问
        System.out.println(User.onlineNumber);

        // 不同包下的类必须先进行导包,才可以访问
        Student stu = new Student();

        // 若一个类中需要用到不同包下的两个同名类,那么默认只能导入一个类,另一个类要带包名访问
        com.itheima.d1_package.testanotherpackage2.Student stu2 = new com.itheima.d1_package.testanotherpackage2.Student();
    }
}

2.权限修饰符

什么是权限修饰符?

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

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

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

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

权限修饰符

修饰符

同一类

同一包下不同类

不同包下的子类

不同包下无关系类

private

缺省

protected

public

        现有如下图所示结构的包与类,分析权限修饰符的作用范围。

 

        示例代码如下:

同一类

/**
 * 同一类
 */
public class Father {
    /*
        1.定义私有的成员:private   允许在本类中访问
     */
    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 static void main(String[] args) {
        Father father = new Father();
        father.privateMethod();
        father.method();
        father.protectedMethod();
        father.publicMethod();
    }

}

同一包下的不同类

/**
 * 同一包下的不同类
 */
public class Test {
    public static void main(String[] args) {
        Father father = new Father();
//        father.privateMethod(); // 报错,private定义的成员只允许在本类中访问
        father.method();
        father.protectedMethod();
        father.publicMethod();
    }
    
}

不同包下的无关类

// 相同包下的类可以直接访问,不同包下的类必须导包才可以使用
import com.itheima.d2_modifier.Father;

/**
 * 不同包下的无关类
 */
public class Test2 {
    public static void main(String[] args) {
        Father father = new Father();
//        father.privateMethod(); // 报错,private定义的成员只允许在本类中访问
//        father.method(); // 报错,权限修饰符缺省时定义的成员只允许在本类、同一包下的其他类中访问
//        father.protectedMethod(); // 报错,protected定义的成员只允许在本类、同一包下的其他类、不同包下的子类中访问
        father.publicMethod();
    }
    
}

不同包下的子类

import com.itheima.d2_modifier.Father;

/**
 * 不同包下的子类
 */
public class Son extends Father {
    public static void main(String[] args) {
        Father father = new Father();
//        father.privateMethod(); // 报错,private定义的成员只允许在本类中访问
//        father.method(); // 报错,权限修饰符缺省时定义的成员只允许在本类、同一包下的其他类中访问
//        father.protectedMethod(); // 报错,protected定义的成员允许在同一类、同一包下不同类、不同包下的子类中访问
        // 不同包下的子类访问指的是不同包下的子类中的子类对象可以访问父类对象成员,而不是子类中的父类对象访问父类成员
        Son son = new Son();
        son.protectedMethod();
        father.publicMethod();
    }

}

3.final

final的作用

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

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

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

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

      示例代码如下:

修饰类与方法

public class Test {
    public static void main(String[] args) {
        // 1.修饰类:表明该类是最终类,不能被继承
        // 2.修饰方法:表明该方法是最终方法,不能被重写
    }
}

//class Wolf extends Animal { // 报错,修饰类:表明该类是最终类,不能被继承。
//}
//
//final class Animal {
//}

//class Student extends People {
//    public void eat() { // 报错,修饰方法:表明该方法是最终方法,不能被重写
//        System.out.println("学生吃东西");
//    }
//}
//
//class People {
//    public final void eat() {
//        System.out.println("人吃东西");
//    }
//}

修饰变量

public class Test2 {
    public static final String name = "张三"; // public static final修饰分变量称为常量
    public final int age = 10; // 使用final必须要赋初值,否则报错
    public static void main(String[] args) {
        // 1.局部变量
        final double rate = 1.5;
//        rate = 1.2; // 报错,修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)
        // 2.成员变量
        // 2.1静态成员变量
//        name = "李四"; // 报错,修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)
        // 2.2实例成员变量
        Test2 test2 = new Test2();
//        test2.age = 20; // 报错,修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)
    }

//    public static void buy(final double z) {
//        z = 0.1; // 报错,参数传入时是第一次为z赋值,此时属于第二次赋值了
//    }
}

常量

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

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

常量的执行原理

        在编译阶段会进行“宏替换”,把使用常量的地方全部替换成真实的字面量,这样做的好处是让使用常量的程序的执行性能与直接使用字面量是一样的。

        常量常做信息标志和分类,提高代码可读性。

4.枚举

枚举的概述

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

        枚举的作用:做信息的标志和信息的分类。

        枚举的格式:

        将上图中的示例代码反编译后观察枚举的特征:

枚举特征:

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

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

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

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

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

5.抽象类

5.1抽象类概念

        在Java中abstract是抽象的意思,如果一个类中的某个方法的具体实现不能确定,就可以声明成abstract修饰的抽象方法(不能写方法体),这个类必须用abstract修饰,被称为抽象类。

        抽象类、抽象方法的格式如下图所示。

抽象类的使用场景

        抽象类可以理解成不完整的设计图,一般作为父类,让子类继承。

        当父类知道子类一定要完成某些行为,但是每个子类该行为的实现又不同,于是该父类就把该行为定义成抽象方法的形式,具体实现交给子类去完成,这个类声明为抽象类。

5.2抽象类案例

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

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

分析实现

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

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

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

        以白金卡为例,代码如下:

卡片类(抽象类)

public abstract class Card {
    private String name;
    private double money;

    public abstract void pay(double money);
    // setter、getter方法
}

白金卡类(继承卡片类并具体实现抽象方法)

public class GoldCard extends Card{
    @Override
    public void pay(double money) {
        System.out.println(getName() + "卡片余额:" + getMoney());
        System.out.println(getName() + "当前消费:" + money);
        // 优惠价格计算
        double rs = money * 0.8;
        System.out.println(getName() + "实际需要支付:" + rs);
        // 更新账户余额
        double accountMoney = getMoney() - rs;
        setMoney(accountMoney);
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        GoldCard goldCard = new GoldCard();
        goldCard.setName("张三");
        goldCard.setMoney(10000);
        goldCard.pay(600);
        System.out.println(goldCard.getName() + "卡片余额:" + goldCard.getMoney());
    }
}

        程序运行结果如下:

张三卡片余额:10000.0

张三当前消费:600.0

张三实际需要支付:480.0

张三卡片余额:9520.0

5.3抽象类的特征、注意事项:

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

        ②抽象类中可以没有抽象方法,但是有抽象方法的类必须是抽象类。

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

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

        ⑤※抽象类不能创建对象—有得有失。

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

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

模板方法模式实现步骤

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

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

模板方法模式的原理:

        模板方法已经定义了通用结构,模板方法不能确定的部分定义成抽象方法,交给子类实现,因此,使用者只需要关心自己需要实现的功能即可,提高了代码的复用性

        需求:现在有两类学生,一类是中学生,一类是小学生,他们都要写一篇作文。要求每种类型的学生,标题第一段和最后一段,内容必须一样。正文部分自己发挥。

        请选择最优的面向对象方案进行设计。

        使用模板方法模式解决:将大量重复代码添加到父类的模板方法中去,不同子类实现的不同功能定义成抽象方法,同样加到模板方法中,并在子类中重写这些不同功能的具体方法。

        在不同对象实现时,调用父类中的模板方法,实现重复代码,其中此对象特有的具体功能,通过在模板方法中调用子类中重写的具体功能的形式实现。

        示例代码如下:

学生类

public abstract class Student {
    /*
        模板方法模式
     */
    public final void write() { // 模板方法使用final修饰,防止子类重写
        // 开头,所有对象都一样
        System.out.println("开头");

        // 正文部分每个子类都要写,但具体内容不同
        // 因此将正文部分定义成模板方法,交由不同的对象实现不同的功能
        writeMain(); // 调用抽象方法,在子类具体实现时重写该重抽象方法
        // 结尾,所有对象都一样
        System.out.println("结尾");
    }
    // 将模板方法中的具体实现不同的方法定义成抽象方法
    public abstract void writeMain();
}

中学生类

public class MiddleSchoolStudent extends Student {
    // 大量重复代码
//    public void write() {
//        System.out.println("开头");
//        System.out.println("中学生正文");
//        System.out.println("结尾");
//    }
    // 使用模板方法模式,只需要写不同的部分,提高代码复用性
    // 重写实现不同功能的方法
    @Override
    public void writeMain() {
        System.out.println("中学生正文");
    }
}

小学生类

public class Pupil extends Student {
    // 大量重复代码
//    public void write() {
//        System.out.println("开头");
//        System.out.println("小学生正文");
//        System.out.println("结尾");
//    }
    // 使用模板方法模式,只需要写不同的部分,提高代码复用性
    // 重写实现不同功能的方法
    @Override
    public void writeMain() {
        System.out.println("小学生正文");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        Pupil pupil = new Pupil();
        // 调用父类中的模板方法,实现重复代码,其中此对象特有的具体功能,通过在模板方法中调用子类中重写的具体功能的形式实现
        pupil.write();
        System.out.println("-----------");
        MiddleSchoolStudent middleStu = new MiddleSchoolStudent();
        middleStu.write();
    }
}

        程序运行结果如下:

开头

小学生正文

结尾

-----------

开头

中学生正文

结尾

6.接口

6.1接口的概述、特点

        接口的格式如下图所示。

        接口是一种规范,是公开的(接口中的成员变量默认pubic static final修饰,成员方法默认public abstract修饰)

        接口不能实例化。

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

        示例代码如下:

public interface InterfaceDemo {
    // 常量
    public static final String SCHOOL_NAME = "光明小学";

    // 2.抽象方法
    // 接口是一种规范,是公开的(接口中的内容默认是pubic)
    public abstract void run();
    public abstract void go();
}

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

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

        实现类的格式如下图所示。

 

        示例代码如下:

Law接口

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

Athletes接口

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

实现类

/*
    实现类
*/
public class TableTennisAthletes implements Athletes, Law { // 接口可以被类单实现,也可以被类多实现。
    private String name;

    public TableTennisAthletes() {
    }

    public TableTennisAthletes(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public void run() {
        System.out.println(name + "跑步");
    }

    @Override
    public void competition() {
        System.out.println(name + "比赛");
    }
    @Override
    public void rule() {
        System.out.println(name + "遵纪守法");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        TableTennisAthletes tableTennisAthletes = new TableTennisAthletes("张三");
        tableTennisAthletes.run(); // 张三跑步
        tableTennisAthletes.competition(); // 张三比赛
        tableTennisAthletes.rule(); // 张三遵纪守法
    }
}

6.3JDK8开始接口新增方法

第一种:默认方法实例方法

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

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

第二种:静态方法

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

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

第三种:私有方法

        就是私有的实例方法:,必须使用private修饰,从JDK1.9才开始有的。

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

6.4接口注意事项

        1、※接口不能创建对象。

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

        3、一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,默认用父类的。

        4、一个类实现了多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可。

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

        示例代码如下:

public class Test {
    public static void main(String[] args) {
//        1、※接口不能创建对象
    }
}

//        2、一个类实现多个接口,多个接口中有同样的静态方法不冲突。
interface A {
    static void test() {
        System.out.println("A");
    }
}

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

class C implements A, B {
    public static void main(String[] args) {
//        C.test(); // 报错,接口的静态方法只允许通过接口名.静态方法的形式访问
        A.test(); // A
        B.test(); // B
    }
}

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

class Animal {
    public void eat() {
        System.out.println("父类中的吃方法");
    }
}

class Cat extends Animal implements Food {
}

class Test2 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat(); // 父类中的吃方法
    }
}

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

interface B2 {
    default void run() {
        System.out.println("B2");
    }
}

class Test3 implements A2, B2 {

    @Override
    public void run() {
        System.out.println("Test3");
    }
}

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

interface B3 {
    void run();
}
//interface Test4 extends A3, B3 {} // 报错,多个接口中存在规范冲突(同名方法两种不同的返回值),无法进行接口继承(合并)
举报

相关推荐

0 条评论