十三、OOP之理解《封装》

面向对象的三大特性,封装、继承、多态
什么是封装?什么是多态?什么又是继承?怎么去理解?本篇幅详细的说一下OOP的封装、构造方法、静态。

一、封装

简单的说就是 (数据的隐藏)
它可以提高程序的安全性,隐藏代码的实现细节,统一接口,提高系统的可维护性
首先封装的最大特点就是,属性私有!常使用getset方法获取设置内部细节
封装的原则是:(该漏的漏,该藏的藏) 提高代码的复用性
(1) 隐藏事物的属性(实现细节) 提高安全性
(2) 隐藏事物的实现细节
(3) 提供一个公共的访问方式 get,set

(1)private关键字

private (私有的私密的) 可以修饰成员变量成员方法构造方法内部类

被private修饰,只能在类的内部直接访问,在类的外部是不能直接访问的

注意: private只是封装的一种体现形式

public class Demo01 {
    public static void main(String[] args) {
        Student s = new Student();
//       s.name = "陈毅";属性私有之后再student类之外就无法直接访问了
         s.study();//通过公开的方法间接的访问私有的属性
//       s.play();
//       s.age = -18;
        s.setAge(88);
        System.out.println(s.getAge());
    }
}
class Student {
    //私有的属性
    private String name;
    //私有的内容只能在本类中被访问
    private int age;
    public void study() {
        System.out.println("好好学习,天天加班" + name);
        play();
    }
    private void play() {
        System.out.println("悄悄的玩游戏,一般不告诉");
    }
    public void setAge(int i) {
        if (i >= 0 && i <= 120) {
            age = i;
        }
    }
    public int getAge(){
        return age;
    }
}

(2)Get和Set

1、当属性被私有化之后,外界不能直接访问了,所以需要提供的公共的访问方式,让外界可以间接的访问成员变量 getset方法就是公共的访问方式

2、属性赋值的格式: private 数据类型 变量名;

public void set+首字母大写的变量名(数据类型 参数名){

 变量名 = 参数名;

}

3、属性值获取的格式:

public 返回值类型 get+首字母大写的变量名(){

 return 变量名;

}

举个栗子:

public class Demo02 {
    public static void main(String[] args) {
        OldMan o = new OldMan();
        //此时不能直接访问属性值了,要通过OldMan类型中提供的公共的访问方式去访问
        o.setName("张三");      //通过公共的访问方式可以间接的访问这些私有的属性
        System.out.println(o.getName());//输出张三
    }
}
class OldMan { //创建一个老男人类 成员变量有name 行为有获得name 设置name
    //一般所有的属性都要私有,所以成员变量使用private修饰
    private String name;      //私有的只能在本类中被访问
    //name提供公共的访问方式
    public void setName(String n) {
        name = n;
    }
    public String getName() {
        return name;
    }
}

再举个栗子:

//类 
public class Student { //创建一个学生类,学生有姓名,学号,性别,年龄
    //属性私有    private英文是 :私有的意思
    private String name;    //名字
    private int id;         //学号
 //**   private char sex;        //性别
    private  int age;       //年龄
    //提供一些操作这个属性的方法!
    //提供一些public的get,set方法
    //学习()
    //睡觉()
    //get 获得这个数据
   public String getName(){
       return this.name;
   }
    //set 给这个数据设置值
    public void  setName(String name){
       this.name=name;
    }
    //idea 使用alt+insert可以快捷键生成get和set方法
    public int getId() {
        return this.id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getAge() {
        return this.age;
    }
    public void setAge(int age) {
      if (age>120 || age<0){
          this.age=3;//小朋友3岁
      }else {
          this.age = age;
      }
    }
}
/*Student s1 = new Student();
        s1.setName("暴书源");
                System.out.println(s1.getName());
                s1.setId(2020020199);
                System.out.println(s1.getId());
                s1.setAge(-70);//不合法
                System.out.println(s1.getAge());
 */

练习(截图题目自己做,然后在参考以下答案)

1、定义一个汽车类:
(1)属性 颜色color轮胎个数number价格price
(2)行为 跑 查看汽车详情(showInfo) 要求查看汽车详情的方法可以输出颜色、轮胎个数、价格
(3)属性私有化并提供公共的访问方式

public class Demo03 {
    public static void main(String[] args) {
        Car c = new Car();
        c.setColor("绿色");
        c.setNumber(3);
        c.setPrice(1111);
        System.out.println(c.getColor());
        System.out.println(c.getNumber());
        System.out.println(c.getPrice());
        c.showInfo();
    }
}
class Car {
    private String color;      //一个类中的属性,一般都要进行私有
    private int number;        //私有意味着不能在当前类以外进行直接访问
    private int price;
    //要提供公共的访问方式用于操作这些属性
    //属性的修改值的方式  set
    //通过该方法可以间接的给color属性赋值
    public void setColor(String c){
        color = c;
    }
    //通过间接的方式获取值
    public String getColor(){
        return color;
    }
    public int getNumber() {
        return number;
    }
    public int getPrice() {
        return price;
    }
    public void setNumber(int n){
        number = n;
    }
    public void setPrice(int p){
        price = p;
    }
    //属性获取值的方式  get
    public void run() {
        System.out.println("跑");
    }
    public void showInfo() {
        System.out.println(color + number + price);
    }
}

(3)变量的访问原则

(1) 变量的定义:定义变量的时候一定是带着数据类型的

(2) 变量的使用:如果不带数据类型的变量,就一定是在使用某个变量

(3) 就近原则

① 访问变量的时候,在访问语句所在的大括号中寻找有没有定义此变量,如果找到了就用,如果没有找到,就会到括号外去寻找,如果找到了就用,找不到就报错

② 当成员变量和局部变量同名的时候,访问变量就看谁距离访问的这个语句更近,就使用谁的数据

(4) this关键字

this.变量名 访问的是成员变量,不加this的一般都是局部变量

作用: 可以区分同名的成员变量和局部变量

① 表示本类当前对象的引用

② 哪个对象调用this所在的方法,this就表示哪个对象

public class Demo04 {
    public static void main(String[] args) {
        Girl g = new Girl();
        g.setName("小明");
        System.out.println(g.getName());
        g.show();
        System.out.println(g);
        //哪个对象调用this所在的方法,this就代表哪个对象
        Girl g2 = new Girl();
        g2.show();
    }
}
//成员变量和局部变量同名
//成员变量和成员变量,不能出现同名  类变量不能同名
//局部变量和局部变量,不能出现同名  方法变量不能同名
//成员变量和局部变量同名,按照就近原则访问
class Girl{
    //this可以理解为类中提供的一个成员,可以记录当前对象的地址值
    private String name;//成员变量
    public void setName(String name){//局部变量
        //成员和局部同名,根据就近原则,
        this.name = name;//给局部变量的name赋值
        //加上this就一定是成员变量
    }
    public String getName(){
        return name;
    }
    int a = 666;    //成员变量
    public void show(){
        int a = 10;
        System.out.println(a);//根据就近原则就是10
        System.out.println(this);
        //如果一个变量名前面加上了this,此时一定是一个成员变量
        System.out.println(this.a);
    }
}

二、构造方法

1、构造方法,有一些别称,构造器、构造函数、Constructor

2、作用:用于给对象的成员变量赋值,在new对象时,jvm虚拟机会自动调用 等对象创建完成之后,该对象的变量就已经有指定的值了

使用new关键字时,必须要有构造器(new的时候本质是在调用构造器)

3、格式:

修饰符 方法名 (参数列表){ 方法名 必须和类的名字相同

方法体;

}

  • 修饰符:可以是public或者private,private修饰的就是私有的构造方法,public修饰的就是公开的构造方法

  • 构造方法: 必须没有返回类型,也不能写void

  • 构造方法可以有return,但是只能写return; 表示结束方法

4、注意事项:

(1) 构造方法是虚拟机自动调用

(2) 不能使用对象名调用构造方法

(3) 只要创建一个对象,构造方法就调用一次

public class Demo05 {
    public static void main(String[] args) {
        Person p = new Person();//() 表示调用了一个方法,括号内部放实际参数 (实际参数)
        //此时创建对象的同时,对象就已经有了具体的值
        Person p2 = new Person("小黑");
        p2.show();
        Person p3 = new Person("小白");
        p3.show();
        //set和构造方法的区别
        //set方法主要用于创建对象完成之后,后期修改对象的属性值
        //构造方法主要是创建对象的同时,给对象赋值属性值
    }
}
class Person{
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //如果一个类中没有书写任何一个构造方法,此时系统默认会提供一个空参构造
    //最简单的构造方法,无参数构造方法
    //格式 public 类名(形式参数){}
    public Person(){
        //只是用于创建对象,没有任何其他操作
        System.out.println("空参构造被执行了");
    }
    //方法的重载:在同一个类中,方法名相同,参数列表不同,与返回值类型无关
    public Person(String name){
        this.name = name;
        System.out.println("有参构造执行了");
    }
    public void show(){
        System.out.println(name);
    }
}

构造方法的注意事项:

1、构造方法可以是有参数的,也可以是没有参数的

(1) 如果没有参数,创建对象时调用构造方法,是不可以传递参数的,此时通过这种方式创建的对象,属性初始值均相同

(2) 如果有参数,外界可以通过构造方法,传递参数,给成员变量赋值,这样创建出来的对象,成员变量的值都是不同的

2、类中没有手动添加任何构造方法,系统会默认提供一个空参构造

3、类中手动添加了任何一个构造方法,系统都不会再提供任何构造方法

4、构造方法也算重载:在同一个类中,方法名都是类名,参数列表一定不同,返回值类型直接没有

5、一般的类中,既要有空参构造,也要有全参构造,都是手动定义出来的

public class Demo06 {
    public static void main(String[] args) {
        Person p = new Person();//() 表示调用了一个方法,括号内部放实际参数 (实际参数)
        //此时创建对象的同时,对象就已经有了具体的值
        Person p2 = new Person("小黑");
        p2.show();
        Person p3 = new Person("小白");
        p3.show();
        //set和构造方法的区别
        //set方法主要用于创建对象完成之后,后期修改对象的属性值
        //构造方法主要是创建对象的同时,给对象赋值属性值
    }
}
class Person{
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //如果一个类中没有书写任何一个构造方法,此时系统默认会提供一个空参构造
    //最简单的构造方法,无参数构造方法
    //格式 public 类名(形式参数){}
    public Person(){
        //只是用于创建对象,没有任何其他操作
        System.out.println("空参构造被执行了");
    }
    //方法的重载:在同一个类中,方法名相同,参数列表不同,与返回值类型无关
    public Person(String name){
        this.name = name;
        System.out.println("有参构造执行了");
    }
    public void show(){
        System.out.println(name);
    }
}

2.创建对象的内存理解

1、创建一个对象的过程中,成员变量最多经过三次初始化

(1) 默认初始化

(2) 显式初始化

(3) 构造方法初始化

2、执行晚的内容,会把执行早的内容覆盖掉(最新的生效)

3、三种初始化的顺序,从早到晚: 默认初始化 > 显式初始化 > 构造方法初始化

4、一个对象创建的完整流程:

(1) 把创建对象所在的类.class加载到方法区

(2) 在栈内存中给该类型的引用开辟一块空间,用来存储堆内存中的地址

(3) 在堆内存中开辟空间,给成员变量赋值

(4) 给成员变量默认初始化赋值

(5) 给成员变量显式初始化赋值

(6) 给成员变量构造方法初始化赋值

(7) 把堆内存中的对象地址,赋值给栈内存中的引用

public class Demo07 {
    public static void main(String[] args) {
        Boy b = new Boy("小明",22);
        b.show();
    }
}
class Boy{
    private String name;//此时默认值 null 此时叫做默认初始化赋值
    private int age = 20;//在声明的同时并赋值,被称为显式初始化
    //构造方法初始化
    public Boy(String name,int age){
        this.name = name;
        this.age = age;
    }
    public void show(){
        System.out.println(name + age);
    }
}

三、静态

没有静态的时候

某个类型的对象都有一个相同的属性值,那么这个属性就没必要定义在所有的对象中,如果定义在所有的对象中,每个对象此时都要存储一份,会浪费空间,不利于后期维护,一旦要修改该属性的值,就需要修改所有对象的属性值

有了静态之后

如果某个类型的某个属性值都一样,那么就没有必要给每个对象都设计该属性的值,而是把这个属性前面加上一个static修饰符,加上static之后,该变量就存储到方法区中,此时该属性就是静态的属性,在这个类型中只存储一份,但是这个变量的数据可以被所有的对象访问,这样节省空间,如果要修改,此时修改一处,其他地方也全部会跟着修改

public class Demo08 {
    public static void main(String[] args) {
        //加上静态的属性,被称为类变量 静态变量
        //随着类的加载而加载
        //可以直接通过类名访问
        System.out.println(OldMan.sex);
        OldMan.sex = "男人";
        OldMan o = new OldMan();
        o.show();
        OldMan o1 = new OldMan();
        //想改变一下 性别的描述
        o1.show();
        OldMan o2 = new OldMan();
        o2.show();
    }
}
class OldMan{
    String name;
    static String sex = "男";
    public void show(){
        System.out.println(name + sex);
    }
}

1.静态属性

1、静态关键字:static,静态 静止的,静态的内容不会随着对象的变化而变化

2、静态的加载时机:随着类的加载而加载。加载时进入方法区,进入方法区之后会在静态区中开辟空间存储数据

3、静态变量出现的时机早于对象

4、静态变量能被当前类的所有对象共享,该类的每一个对象都可以访问

5、以后可以使用类名访问静态变量,虽然通过对象名可以,但是静态变量属于类,还是使用类名访问

6、格式: 类名.静态变量名;

2.静态方法

1、在定义方法的时候,在修饰符的位置加上static,这个方法就是一个静态方法

2、静态方法,可以通过类名去访问,也可以通过对象名去访问

3、只能通过类名去访问的内容,本质上都是属于类最好都通过类名去访问

4、静态方法使用注意事项:

(1) 静态方法中不能访问成员变量

  1. 静态方法,没有创建对象的时候就能调用,成员变量是在对象完成之后才可以使用,

  2. 假如静态的方法能访问成员变量,就相当于在创建对象之前,就使用对象内容(所以不能访问成员变量)

(2) 静态方法能不能访问成员方法,不能,原理同上

(3) 静态方法只能访问静态的内容,可以访问静态的属性,也可以访问静态的方法

(4) 静态方法能不能有this关键字,this表示本类当前对象,有了对象才有this,所以还是不行

5、总结:

(1) 静态不能访问非静态的内容,非静态内容可以访问静态的内容

public class Demo09 {
}
class Teacher{
    String name;
    int age;
    static String department = "教研室";//        department静态属性,可以在创建对象之前被访问,也可以通过对象名去访问
    //成员方法
    public void sayHi(){   //非静态既可以访问静态的内容,也可以访问非静态的内容
        //非静态可以访问静态的内容
        System.out.println("哈喽,大家好,我是老师" + name + age + department);
    }
    public static void teaching(){       //静态不能访问非静态,非静态可以访问静态
        System.out.println("师者传道受业解惑也");
//        System.out.println("师者传道受业解惑也" + name);     //name是非静态的,静态中不能访问非静态
//       sayHi();             //方法是非静态的,必须对象创建完成之后才可以调用
    }
}

3.静态变量和非静态变量的区别

1、概念上所属不同:

(1) 非静态变量属于对象

(2) 静态变量属于类

2、内存空间位置不同:

(1) 非静态变量存储在堆内存中,和对象一个区域

(2) 静态变量属于类,和类.class文件在一个区域,都在方法区中,只不过静态变量在静态区

3、存储的时间不同,生命周期不同

(1) 非静态变量属于对象,所以生命周期和对象一致,随着对象的创建而创建,随着对象的消亡而消亡

(2) 静态变量属于类,所以生命周期和类一致,随着类的加载而加载,.class的销毁而销毁

4、访问方式的不同:

(1) 非静态变量,只能通过对象名访问

(2) 静态变量,既可以通过类名访问,也可以通过对象名来访问

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值