Java 三大特性之封装

目录

一、什么是封装

二、访问限定符 

三、什么是包

1、导入包中的类

2、自定义包

3、包的访问权限控制举例 

四、static成员

1、static修饰成员变量

2、static修饰成员方法 

五、static成员变量初始化 

1、就地初始化

2、静态代码块初始化

六、代码块

1、普通代码块

2、构造代码块

3、静态代码块

七、初始化的顺序


一、什么是封装

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

比如:对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器,USB插孔等,让用户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU、显卡、内存等一些硬件元件。计算机厂商在电脑出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。


二、访问限定符 

Java 中主要通过 类和访问权限 来实现封装:

  1. 类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认知;
  2. 而访问权限用来控制方法或者字段能否直接在类外使用。

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

(绿色代表允许访问)
范围privatedefaultprotectedpublic
同一包中的同一类
同一包中的不同类
不同包中的子类
不同包中的非子类
  • public:可以理解为一个人的外貌特征,谁都可以看得到
  • default: 什么都不写时的默认权限,对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了
  • private:只有自己知道,其他人都不知道
  • protected:因为涉及到子类,所以在继承部分详细介绍
//Computer.java
public class Computer {
    private String cpu; //cpu
    private String memory;  //内存
    public String screen;   //屏幕
    String brand;   //品牌(没写限定符时默认为default)
    public Computer(String brand,String cpu,String memory,String screen){
        this.brand = brand;
        this.cpu = cpu;
        this.memory = memory;
        this.screen = screen;
    }
    public void poweron(){
        System.out.println("开机");
    }
    public void poweroff(){
        System.out.println("关机");
    }
}

//TestComputer.java
public class TestComputer {
    public static void main(String[] args) {
        Computer computer = new Computer("小米","R7","16","15.6");
        System.out.println(computer.brand);
        System.out.println(computer.screen);
        //System.out.println(computer.cpu);   //报错,只能在Computer类中访问
    }
}

什么时候下用哪一种呢?

        我们希望类要尽量做到 "封装",即隐藏内部实现细节, 只暴露出 必要 的信息给类的调用者。 因此我们在使用的时候应该尽可能的使用 比较严格 的访问权限。 例如如果一个方法能用 private, 就尽量不要用 public。


三、什么是包

在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。

在Java中也引入了包,包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一个包中的类不想被其他包中的类使用。包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。

1、导入包中的类

最熟悉的就是Scanner类,当你输入Scanner+回车,会自动出现;

import java.util.Scanner;    //导入java.util这个包中Scanner类

public class Test{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
    }
}

如果还想使用Java.util 这个包中的其他类,可以

import java.util.*;

但是我们更建议显式的指定要导入的类名. 否则还是容易出现冲突的情况,比如不同包中有同名的类,编译器编译时不知道你想使用的是哪个包中的类;如果你还是想用上面这种方法,那就需要完整的类名,以Date类举例

import java.util.*;
import java.sql.*;    //这两个包中都有Date类

public class Test {
    public static void main(String[] args) {
        //util和sql中都存在Date类, 此时就会出现歧义, 编译出错
        //Date date = new Date();    
        java.util.Date date = new java.util.Date();    //需要使用完整的类名   
        System.out.println(date.getTime());    //得到一个毫秒级别的时间戳
    }
}

 可以使用 import static 导入包中静态的方法和字段;

import static java.lang.Math.*;
public class Test {
    public static void main(String[] args) {
        double x = 30;
        double y = 40;
        // 静态导入的方式写起来更方便一些.
        // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        double result = sqrt(pow(x, 2) + pow(y, 2));
        System.out.println(result);
    }
}

2、自定义包

(1)在 IDEA 中先新建一个包: 右键 src -> 新建 -> 包

(2)在弹出的对话框中输入包名, 例如 yxj

(3)在包中创建类 ,右键包名 -> 新建 -> 类,然后输入类名即可

(4)此时可以看到我们的磁盘上的目录结构已经被 IDEA 自动创建出来了

(5)同时我们也看到了, 在新创建的 Test.java 文件的最上方, 就出现了一个 package 语句

3、包的访问权限控制举例 

以上面的Computer类和TestComputer类举例,将他们移入不同的包中

package demo1;
public class Computer {
    private String cpu; //cpu
    private String memory;  //内存
    public String screen;   //屏幕
    String brand;   //品牌(没写限定符时默认为default)
    public Computer(String brand,String cpu,String memory,String screen){
        this.brand = brand;
        this.cpu = cpu;
        this.memory = memory;
        this.screen = screen;
    }
    public void poweron(){
        System.out.println("开机");
    }
    public void poweroff(){
        System.out.println("关机");
    }
}

package demo2;
import demo1.Computer;
public class TestComputer {
    public static void main(String[] args) {
        Computer computer = new Computer("小米","R7","16","15.6");
        //System.out.println(computer.brand);   //报错,brand是default,不允许被其他包中的类访问
        System.out.println(computer.screen);
        //System.out.println(computer.cpu);   //报错,只能在Computer类中访问
    }
}

四、static成员

在Java中,被 static 修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对 象,是所有对象所共享的。

1、static修饰成员变量

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

我们创建一个学生类,假设三个同学是同一个班的,那么他们上课肯定是在同一个教室

//Student.java
public class Student {
    public String name;
    public String gender;
    public int age;
    public double score;
    public static String classRoom = "高三一班";  //static 修饰成员变量

    public Student(String name, String gender, int age, double score) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.score = score;
    }
}

//TestStudent.java
public class TestStudent {
    public static void main(String[] args) {
        // 静态成员变量可以直接通过类名访问
        System.out.println(Student.classRoom);  //通过类来访问
        Student s1 = new Student("小张", "男", 18, 3.8);
        Student s2 = new Student("小刘", "女", 19, 4.0);
        Student s3 = new Student("小李", "男", 18, 2.6);
    }
}

【静态成员变量特性】

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

2、static修饰成员方法 

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

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

//Student.java
public class Student {
    public String name;
    public String gender;
    public int age;
    public double score;
    private static String classRoom = "高三一班";  //public 改为 private

    //加这个静态成员方法
    public static String getClassRoom() {
        return classRoom;    //返回静态成员变量
    }
}

//TestStudent.java
public class TestStudent {
    public static void main(String[] args) {
        //报错
        //System.out.println(Student.classRoom);         
        //通过访问静态方法来访问private修饰的静态成员变量
        System.out.println(Student.getClassRoom());
    }
}

【静态成员方法特性】

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

五、static成员变量初始化 

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

静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化

1、就地初始化

在定义时直接给出初始值,上面的学生类的静态成员变量就是这么初始化的。

2、静态代码块初始化

在下面的代码块中讲解。


六、代码块

使用 {} 定义的一段代码称为代码块。

根据代码块定义的位置以及关键字,又可分为以下四种

  • 普通代码块
  • 构造块
  • 静态块
  • 同步代码块(后续详解)

1、普通代码块

定义在方法中的代码块。

public class TestStudent {
    public static void main(String[] args) {
        //普通代码块
        {
            //...
        }
    }
}

2、构造代码块

定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。

public class TestStudent {
    //实例代码块
    {
        //...
    }
    public static void main(String[] args) {
        //普通代码块
        {
            //...
        }
    }
}

3、静态代码块

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

public class TestStudent {
    //静态代码块
    static{
        //...
    }

    //实例代码块
    {
        //...
    }
    public static void main(String[] args) {
        //普通代码块
        {
            //...
        }
    }
}

【注意】

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

七、初始化的顺序

public class TestStudent {
    //静态代码块
    static{
        System.out.println("静态代码块执行");
    }
    //实例代码块
    {
        System.out.println("实例代码块执行");
    }
    //构造方法
    public TestStudent() {
        System.out.println("构造方法执行");
    }

    public static void main(String[] args) {
        TestStudent testStudent = new TestStudent();   
    }
}

//输出
//静态代码块执行
//实例代码块执行
//构造方法执行

  • 30
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值