【Java】封装

路漫漫其修远兮

吾将上下而求索


目录

1.封装 

1.1 封装的概念

1.2 访问限定符

1.3 封装扩展之包 

2.static成员

2.1 static修饰的成员变量 

2.2 static修饰的成员方法

2.3 static成员变量初始化 

3.代码块

3.1代码块的概念以及代码块的分类

3.2 普通代码块 

3.3 构造代码块 

3.4 静态代码块 

4.内部类 

4.1 什么是内部类 

4.2 内部类的分类 

4.3 实例内部类 

4.4 静态内部类 

4.5 局部内部类 


1.封装 

1.1 封装的概念

面向对象程序三大特性:封装、继承、多态。我们今天就来学习三大特性中的封装

问题:究竟什么是封装了? 

从封装的字面意思,我们就可以看出封装就是把一个东西封起来,让别人看不见 这其实就是封装

那我们举例说明,让大家对封装大致的认知 

我们就拿计算机的主板来举例,我们知道计算机大多硬件都是按装在主板上的,而主板安装在主机箱内的,我们平时是看不到主板的,除非把主机箱打开才可以看到主板。那我们就可以说主板封装在了主机箱内,将内部实现细节给隐藏起来了,提供给用户的只是一些接口,我们通过这些接口就可以使用到整个主板以及主板上硬件的功能。比如:用户通过接口键盘、显示器一些外部设备,让用户能跟计算机进行交互

通过上述的举例相信大家对封装有了大致的了解,那接下来我们就引出封装的概念 

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互 

1.2 访问限定符

我们经常在成员变量成员方法前面加上 public ,其实 public 也就是访问限定符

Java中主要通过访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,而访问权限用来控制方法或者字段能否直接在类外使用。

Java中提供了四种访问限定符: 

  1. public:公开的,在任何地方都可以使用。可以理解为一个人的外貌特征,谁都可以看得到
  2. protected:主要是用在继承中(先做了解,会面讲)
  3. default: 只能在同一个包中使用。可以理解为对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了
  4. private:私有的,只能在同一个包的同一个类中使用。可以理解为只有自己知道,其他人都不知道 

 注:

  • 什么都不写时的默认权限是 default
  • 访问权限除了可以限定类中成员的可见性,也可以控制类的可见性 
  •  一般情况下成员变量设置为private,成员方法设置为public

1.3 封装扩展之包 

1.包的概念

包就相当于计算机中的文件夹,假设有一个歌曲的文件夹那么里面肯定都是存放歌曲的, 假设有一个笔记的文件夹那么里面肯定都是存放笔记的。

这样做的目的就是为了更好的文件,把多个相同类型的文件收集在一起成为一组,就变成了文件夹 

通过上面的例子,我们就可以引出包的概念了 

包的概念:为了更好的管理类,把多个类收集在一起成为一组,称为软件包 

在Java中也引用了包,包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式。比如:一个包中的类不想被其他包中的类使用

注:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可

2.如何导入包中的类 

你们还记得我们之前写代码的时候需要输入,就需要 实例化一个 Scanner ,而 Scanner 这个类是Java提供的,当我们输入Scanner敲回车的时候,编译器会自动在文件顶部自动导入包

import java.util.Scanner;

 这句代码就是敲回车时,自动导入的包。这种就是用 import 导入包

 除了这个导入包的方法,还可以用完整类名导入包

java.util.Scanner scanner = new java.util.Scanner(System.in);

那么现在我们就知道导入包有两种方式:①使用完整的类名导入包 ②使用 import 语句导入包 

① 使用完整的类名导入包

Java 中已经提供了很多现成的类供我们使用. 例如Date类:可以使用 java.util.Date 导入 java.util 这个包中的 Date

public class Test {
    public static void main(String[] args) {
        java.util.Date date = new java.util.Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
    }
}

Data 这个类是 Java 已经提供的,但是在不同包中类名是可以一样的,所以 Data 这个类,可能在很多包中都存在,但是功能却不一样。我们需要告诉编译器用哪个包中的 Data 类,所以可以使用完整的类名告诉编译器是哪个包中的 Data 类

② 使用 import 语句导入包 

上述使用完整的类名,写起来就显得很麻烦,那么我们就可以使用 import 语句去导入包 

import java.util.Date;
public class Test {
    public static void main(String[] args) {
        Date date = new Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
    }
}

在文件的开头用 import 导入 Data 完整类名(import java.util.Date) 或者类所在的包( java.util ),这样当我们使用 Data 类时,就知道用哪个包中的Data 类

如果需要使用 java.util 中的其他类, 可以使用 import java.util.* 

但是我们更建议显式的指定要导入完整类名或者直接拿完整类名去使用, 否则还是容易出现冲突的情况 

4.自定义包 

如何自定义一个包咧?

在 IDEA 中新建一个包:右击  src --》new --》Package , 在弹出的对话框中输入包名,即可生成一个包

如何在包中新建一个类?

右击包名 --》new --》Java class ,在弹出的对话框中输入类名,即可新建一个类 

  • 一般在包中新建的类文件,通常文件的的最上方加上一个 package 语句指定该代码在哪个包中
  • 如果一个类没有 package 语句, 则该类被放到一个默认包中 

5. private访问权限控制举例 

 学习了包之后了,我们就可以来理解 private 访问权限控制的举例了

通过 package 后面的包名我们就可以知道他们是两个不同的包中的类, 我们在Test2这个类的主函数中需要实例化 Test1 这个类,就需要用 import 导入它完整的类名。实例化完成之后我们通过对象名使用 age 这个成员变量,会直接报错原因就是 age 是 private 修饰的,它只能在同一个包中的同一个类中直接使用。如果我们想要使用 age 这个成员变量就需要调用 returnAge 这个成员方法,返回 age 成员变量的值。那么 returnAge 就相当于我们之前所说的接口,age 就实现了封装。

2.static成员

2.1 static修饰的成员变量 

假设目前我有一个学生类:

public class Student {
    private String name;
    private int age;
}

我们知道一个类可以实例化多个对象,就相当于一个学生类可以实例化多个学生,假设实例化的学生对象都是属于一个班级里面的,我们现在需要在 Student 类中定一个班级,如果把这个班级定义成了成员变量,那么每次实例化的时候都会班级都会在对象中占空间,但是所有的学生都属于这个班级,这样的话,可以就会造成空间的浪费。那么我们就可以把班级定义为 static 修饰的成员变量 

public class Student {
    private String name;
    private int age;
    private static int classRoom = 2131;
}

static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。 

【静态成员变量特性】:

  • 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
  • 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问
  • 类变量存储在方法区当中
  • 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁 )

2.2 static修饰的成员方法

一般类中的数据成员都设置为 private,而成员方法设置为 public,那设置之后,Student类中classRoom属性如何在类外访问呢?

public class Student {
    private String name;
    private int age;
    private static int classRoom = 2131;

    public static int getClassRoom() {
        return classRoom;
    }
}

Java中,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。静态成员一般是通过静态方法来访问的

【静态方法特性】

  • 不属于某个具体的对象,是类方法
  • 可以通过对象调用,也可以通过类名.静态方法名(...)方式调用,更推荐使用后者
  • 不能在静态方法中访问任何非静态成员变量 
  • 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用

2.3 static成员变量初始化 

构造方法中初始化的是与对象相关的实例属性,所有静态成员变量一般不会放在构造方法中来初始化

静态成员变量初始化一共有两种:①就地初始化 ②静态代码块初始化 

①就地初始化 

就地初始化:在定义静态成员变量的时候直接初始化

private static int classRoom = 2131;

 这个就是直接初始化

②静态代码块初始化 

说到静态代码块初始化,那么我们就不得不详谈一下什么是代码块 

3.代码块

3.1代码块的概念以及代码块的分类

用 { } 定义的一段代码就叫做代码块

代码块可以根据代码定义的位置以及关键字进行关键字进行分类:

  • 普通代码块
  • 构造代码块
  • 静态代码块
  • 同步代码块 

3.2 普通代码块 

普通代码块:定义在方法中的代码块 

public class Test {
    public static void main(String[] args) {
        {
            int x = 10;
            System.out.println(x);
        }
        int x = 20;
        System.out.println(x);
    }
}

普通代码块中定义的 x 变量,只能在普通代码块中使用,出了普通代码块直接销毁

3.3 构造代码块 

构造代码块也叫做实例代码块:定义在类中的代码块。通常用来初始化实例成员变量 

public class Student {
    private String name;
    private int age;
    
    //实例代码块
    {
        this.name = "小美";
        this.age = 1;
    }
}

3.4 静态代码块 

静态代码块:使用 static 定义的代码块称为静态代码块。一般用于初始化静态成员变量。 

public class Student {
    private String name;
    private int age;
    private static int classRoom;

    static {
        classRoom = 2131;
    }
}

【注意事项】

  • 静态代码块不管生成多少个对象,其只会执行一次
  • 静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
  • 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)
  • 实例代码块只有在创建对象时才会执行 

实例代码块,静态代码块,构造方法的执行顺序:

  1. 静态代码块
  2. 实例代码块
  3. 构造方法

这些都是由编译器自动调用的 

4.内部类 

4.1 什么是内部类 

内部类:将一个类定义的定义到另一个类的类部或者是方法的内部就叫做内部类 

public class Student {
    class Pets {
        
    }
}
  • Student 类:是外部类
  • Pets 类:是内部类 

内部类和外部类共用同一个 java 源文件,但是经过编译之后,内部类会形成单独的字节码文件 

4.2 内部类的分类 

内部类可以按照在一个类的那个位置定义来分类:

  • 实例内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类(只能使用一次,后期讲)
public class OutClass {
    // 成员位置定义:未被static修饰 --->实例内部类
    public class InnerClass1{
    }
    // 成员位置定义:被static修饰 ---> 静态内部类
    static class InnerClass2{
    }
    public void fun(){
    // 方法中也可以定义内部类 ---> 局部内部类:几乎不用
        class InnerClass3{
        }
    }
}

4.3 实例内部类 

public class ExampleClass {
    public int data1 = 1;
    private int data2 = 2;
    public static int data3 = 33;

    public void fun() {
        System.out.println("hahaha");
    }

    /**
     * 实例内部类
     * 1. 如何获取 实例内部类的对象
     * 方法一:
     *     ①首先创建一个外部类对象
     *     ExampleClass exampleClass = new ExampleClass();
     *     ②然后  外部类名.内部类名 对象名 = 外部类名.new 内部类名();
     *     ExampleClass.Example exmaple = exampleClass.new Example();
     * 方法二:
     *        外部类与内部类一起创建
     *        ExampleClass.Example exmaple = new ExampleClass().new Example();
     *
     * 2. 实例内部类当中 不能有静态的成员变量. 非要定义,那么只能是被static final修饰的
     * 3. 在实例内部类当中,如何访问外部类当中,相同的成员变量?
     *     在实例内部类当中 获取外部类的this : ExampleClass.this.data3
     */
    class Example {
        public int data3 = 3;
        public int data4 = 4;
        public static final int data5 = 5;//final相当于常量

        public void func() {
            // 在实例内部类中可以直接访问外部类中:任意访问限定符修饰的成员
            System.out.println(data1);
            System.out.println(data2);
            // 如果外部类和实例内部类中具有相同名称成员时,优先访问的是内部类自己的
            System.out.println(data3);
            // 如果要访问外部类同名成员时候,必须:外部类名称.this.同名成员名字
            System.out.println(ExampleClass.this.data3);
            System.out.println(data4);
            System.out.println(data5);

        }

    }

}

class Test1 {
    public static void main(String[] args) {
        ExampleClass exampleClass = new ExampleClass();
        ExampleClass.Example exmaple = exampleClass.new Example();

        // ExampleClass.Example exmaple = new ExampleClass().new Example();
        exmaple.func();

    }

}

 【注意事项】

  • 外部类中的任何成员都可以在实例内部类方法中直接访问
  • 实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束
  • 在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名 称.this.同名成员 来访问
  • 实例内部类对象必须在先有外部类对象前提下才能创建
  • 实例内部类的非静态方法中包含了一个指向外部类对象的引用
  • 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。

4.4 静态内部类 

public class StaticClass {
    public int data1 = 1;
    private int data2 = 2;
    public static int data3 = 3;

    /**
     * 1.如何获取静态内部类对象
     *      可以直接获取因为静态内部类不属于对象,属于外部类,
     *      所以不需要创建外部类对象就可以直接创建
     *      外部类名.内部类名 内部类对象名 = new 外部类名.内部类名();
     * 2. 静态内部类当中,不能访问外部类的非静态成员。外部类的非静态成员,
     *    需要通过外部类的对象的引用才能访问。
     *    如果非要访问就要在静态内部类当中创建外部类对象
     *    非要访问:StaticClass staticClass = new StaticClass();
     *              System.out.println(staticClass.data1);
     */
    static class Static {
        public int data4 = 4;
        private int data5 = 5;
        static int data6 = 6;

        public void setDate() {
            data4 = 7;
            StaticClass staticClass = new StaticClass();
            System.out.println(staticClass.data1);
            // 在内部类中只能访问外部类的静态成员
            System.out.println(data3);
            System.out.println(data4);
            System.out.println(data5);
            System.out.println(Static.data6);
        }

    }
}
class Test2 {
    public static void main(String[] args) {
        StaticClass.Static example = new StaticClass.Static();
        example.setDate();
    }
}

【注意事项】

  • 在静态内部类中只能访问外部类中的静态成员
  • 创建静态内部类对象时,不需要先创建外部类对象 

4.5 局部内部类 

定义在外部类的方法体或者{}中,该种内部类只能在其定义的位置使用,一般使用的非常少 

public class PartClass {
    public int data1 = 1;
    private int data2 = 2;
    public static int data3 = 3;

    /**
     * 局部内部类:定义在方法体内部
     *不能被public、static等访问限定符修饰
     * 只能在该方法体内部使用,其他位置都不能用
     */
    public void fun() {
        class Part {
            public int data3 = 3;
            public void print() {
                System.out.println(data1);
                System.out.println(data2);
                System.out.println(PartClass.this.data3);
                System.out.println(data3);
            }
        }
        Part part = new Part();
        part.print();
    }
}
class Test3 {
    public static void main(String[] args) {
        PartClass partClass = new PartClass();
        partClass.fun();

    }
}

 【注意事项】

  • 局部内部类只能在所定义的方法体内部使用
  • 不能被public、static等修饰符修饰
  • 编译器也有自己独立的字节码文件,命名格式:外部类名字$内部类名字.class
  • 几乎不会使用
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拼命阿紫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值