面向对象三大特性之——封装

一、引言

此篇文章来自一个初学Java不久的学生,内容的用词、深度、广度甚至部分理解不够到位,再加上Markdown语法的不熟练,所以排版不够美观。但还是希望有疑问的读者能够读完全文,大家遇到问题可以一起交流。谢谢!

二、类和对象的初步理解

:使用一个通用类来定义同一类型的对象。类是一个模板或者称为合约,用来定义对象的数据域是什么以及方法是做什么的。

对象:对象代表现实世界中可以明确标识的一个实体。例如:一个学生、一张桌子甚至是一个圆都可以看作是一个对象。并且每个对象都有自己独特的标识、状态和行为。一个对象是一个类的实例

类和对象的关系:类是对事物的一种描述,对象则为具体存在的事物 。举个例子:定义一个类用来装水,那么它的对象可以是水杯也可以是茶壶。只要能够装水的都可以通过这个类来实例化获得它的对象。

如果你还是不懂怎么意思,或许你可以看一下我的面向过程编程和面向对象编程的区别,希望对你有帮助

三、五个有必要知道问题

一、正确理解A a = new A();

做为一个初学者,我表示会写这句话,但是对这句话的理解就模棱两可了。

//第一种书写方式
A a;
a = new A ();
//第二种书写方式
A a = new A ();

第一种书写方式

第一步:声明一个A类型的变量a

第二步:创建一个A类型的对象,并且将它赋值给变量a

第二种书写方式

声明一个A的变量a,用来引用变量,再创建一个对象,并且将创建的对象赋值给变量a。

总结的大白话:看到new就是需要在堆内存里面开辟一块属于类A的空间,然后把开辟出来的空间的地址值赋值给a,当然这个a一定要是这个类型的变量,当然如果你学了多态,这里可能又要进行讨论一番。

注意:从表面上看,对象引用变量中似乎存放了一个对象,但事实上,它只是包含了对该对象的引用。严格的来说,对象引用变量对象是不同的,但是大多数情况下,这种差异是可以忽略的。因此可以简单的说a是A的一个对象,而不用花大篇幅的来说,a是一个包含对A对象引用的变量。简单的理解就是:a是抽象出来的一个地址值,它可以不用一个实体(因为它只是把这个地址值当作了一个实体),但是它依然可以完成a对A里面方法的操作(借助地址值)。

二、基本类型变量与引用类型变量的区别

每一个变量都代表一个存储值得内存位置。声明一个变量时,就是在告诉编译器这个变量可以存放什么类型得值。对基本数据类型变量来说,对应内存所存储得值时基本类型值。对引用类型变量来说,对应内存所存储得值时一个引用,是对象得存储地址。换句话说,你得变量是在堆内存还是在栈内存,如果是堆内存就是引用类型变量,如果是栈内存,那就是基本类型变量。

三、局部变量和成员变量的区别

1.类中位置不同:成员变量(类中方法外)局部变量(方法内部或方法声明上)
2.内存中位置不同:成员变量(堆内存)局部变量(栈内存)
3.生命周期不同:成员变量(随着对象的存在而存在,随着对象的消失而消失)局部变
量(随着方法的调用而存在,随着方法的调用完毕而消失)
4.初始化值不同:成员变量(有默认初始化值)局部变量(没有默认初始化值,必须先

定义,赋值才能使用)

四、静态和实例的区别

我这里只说着重说方法的区别

其实我在很早学习方法的时候就意识到这个问题了,为什么有的方法是需要实例化以后,依靠对象来调用方法;但是有的又是可以直接.出来(Math类)。其实这就是两个类的本质的区别。

静态方法:直接用.的方式直接调用方法
面向对象三大特性之——封装_构造方法

实例化方法:需要创建这个类的对象,然后通过对象调用类里面的方法

面向对象三大特性之——封装_构造方法_02

再来一个例子

面向对象三大特性之——封装_其他_03

总结:其实在最后的那个例子里面不难看出,其实静态的方法也可以通过实例化的方式调用,但是通过实例化的方法调用,会在堆里面开辟一块内存空间,加重系统负担,静态的调用消耗的内存是在方法区。而且实例化的方法却不能通过静态的方式调用。

静态变量:其实主要的核心思想静态变量和静态方法差不多,补充一点就是,静态变量的值会随着全局的变动而变动。即你调用了一次并且赋值了,那么它就一直会跟着变。

五、构造方法

我习惯把构造方法当做一个类得灵魂。一个类是肯定需要一个灵魂。无参构造方法就是最初得灵魂,你自己写了一个带参得构造方法,那么就相当于你给这个类赋予了一个新得灵魂。

格式

public class People1 {   
    int age;
    String name;
    //无参构造方法   
    public People1() {    }
    
    //带参构造方法
    public People1(int age, String name) {      
        this.age = age;      
        this.name = name;  
    }
}

之前在继承的那篇文章里面说过,如果对继承不理解的小伙伴,可以去看看面向对象三大特性之——继承。当然里面是侧重说重写于重载得区别,其实带参构造方法和无参构造方法就是重载。

为什么需要构造方法呢?

答:每一个类在创建的时候我们一定要赋予它灵魂,请记住这句话。当然,在你每次new一个类的时候,它也就会自动运行构造方法。为什么之前你new了那么多类,没有注意到这个?因为你之前的灵魂都是与生俱来的(默认无参构造)。我想如果你需要它的带参构造方法,你可能就一目了然了。

面向对象三大特性之——封装_封装_04

四、封装核心

需求:定义一个People类用于打印输出人的姓名和年龄

一、没有运用封装技术的代码

People类:

public class People {    
    //定义的成员属性
    int age;    
    String name;    
    //定义的show方法
    public void show() {
        System.out.println("输出的人的名字是:" + name + "年龄是:" + age);    
    }
}

测试类:

public class Demo {
    public static void main(String[] args) {
        People p = new People();
        p.age= 4;
        p.name = "小明";
        p.show();
    }
}

输出结果:

输出的人的名字是:小明年龄是:4

二、运用封装技术以后的代码

People类:

public class People1 {    
    private int age;   
    private String name;  
    //两个构造方法    
    public People1() {    }    
    public People1(int age, String name) {
        this.age = age;       
        this.name = name;  
    }   
    
    //对age成员变量的封装   
    public int getAge() {       
        return age;   
    }   
    public void setAge(int age) {    
        this.age = age;   
    }  
    
    //对name成员变量的封装    
    public String getName() { 
        return name; 
    }   
    public void setName(String name) { 
        this.name = name;   
    }    
    //定义的show方法
    public void show() {     
        System.out.println("输出的人的名字是:" + name + "年龄是:" + age);  
    }
}

测试类:

public class Demo1 {
    public static void main(String[] args) {
        People1 p = new People1();
        p.setAge(4);
        p.setName("小明");
        p.show();
    }
}

输出结果:

输出的人的名字是:小明年龄是:4

三、两种的区别

其实我最开始学习这种封装写法的时候很不习惯,因为我觉得效果是一样的,为什么还要这么复杂?慢慢的,发现里面并不是这么简单。不然我问你几个问题?

1)如果封装类型的代码块里面,没有setXxx()方法,会怎么样?

答:如果没有setXxx()那么对于该方法下的数据将缺少一个设置程序,那么在给数据域里面的数据进行设置数据的时候将会报错。当然,如果你不去设置,那么就不会报错,因为这是引用数据类型,你不赋值将会被默认值取代。

面向对象三大特性之——封装_封装_05

2)在setXxx()方法里面加入部分条件语句,会怎么样?

答:这里就体现了封装的数据安全,对于用户输入的数据需要保证其正确性,但是用户的输入误差太大,这个时候就需要代码的提示。
面向对象三大特性之——封装_构造方法_06

3)private关键字去掉会怎么样?

答:去掉private关键字后,将会失去数据的封装性,那个在外界就可以直接利用对象.成员变量的方法修改数据。这样就会失去setXxx()/getXXxx()方法本来的意义。

面向对象三大特性之——封装_构造方法_07

四、总结

使用封装的技术主要是为数据的安全而提供的一种使用方式,将数据域设置为私有的保护数据,使程序更安全而更有利于后期的维护。出于不能让外界的数据直接访问内部数据,所以使用了关键字private,但是有的时候,我们又需要对数据域中的数据进行操作,所以我们就需要提供一组setXxx()/getXXxx()方法,分别称为修改器和访问器。依靠着修改器和访问器的特性,达到数据的安全性。