06_面向对象

一、类和对象

面向对象和面向过程的思想对比:

  • 面向过程:是一种以过程为中心的编程思想,实现功能的每一步,都是自己实现的
  • 面向对象:是一种以对象为中心的编程思想,通过指挥对象实现具体的功能

1.1 类和对象的关系

客观存在的事物皆为对象,所以我们也常常说万物皆对象

    • 类的理解
      • 类是对现实生活中一类具有共同属性和行为的事物的抽象
      • 类是对象的数据类型,类是具有相同属性和行为的一组对象的集合
      • 简单理解:类就是对现实事物的一种描述
    • 类的组成
      • 属性:指事物的特征,例如:手机事物(品牌、价格、尺寸)
      • 行为:指事物能执行的操作,例如:手机事物(打电话、发短信)
  • 类和对象的关系
    • 类:类是对现实生活中一类具有共同属性和行为的事物的抽象
    • 对象:是能够看得到摸得着的真实存在的实体
    • 简单理解:类是对事物的一种描述,对象则是具体存在的事物

1.2 类的定义(应用)

类的组成是由属性和行为2部分组成

  • 属性:在类中通过成员变量来体现(类中方法外的变量)
  • 行为:在类中通过成员方法来体现

类的定义步骤:

  1. 定义类
  2. 编写类的成员变量
  3. 编写类的成员方法
package com.it.pojo;

// 学生类
public class Student {
    // 属性:姓名、年龄
    // 成员变量:类中方法外
    String name;
    int age;
    
    // 行为:学习
    // 成员方法
    public void study(){
        System.out.println("学习");
    }
}

1.3 对象的创建和使用

  • 创建对象的格式:

    类名 对象名 = new 类名();

  • 调用成员的格式:

    • 对象名.成员变量
    • 对象名.成员方法();
  • 实例代码

    package com.it.test;
    
    public class TestStudent {
        public static void main(String[] args) {
            // 类名 对象名 = new 类名();
            Student stu = new Student();
            
            // 对象名.变量名
            // 默认初始化值
            System.out.println(stu.name); // null
            System.out.println(stu.age); // 0
    
            // 设置值
            stu.name = "张三";
            stu.age = 29;
            System.out.println(stu.name); // 张三
            System.out.println(stu.age); // 29
    
            // 修改值
            stu.name = "李四";
            System.out.println(stu.name); // 李四
    
            // 对象名.方法名();
            stu.study(); // 学习
            System.out.println(stu); // com.it.test.Student@1540e19d 全类名(包名 + 类名)
        }
    }
    

1.4 案例

  • 需求

    手机类的创建和使用,首先定义一个手机类,然后定义一个手机测试类,在手机测试类中通过对象完成成员变量和成员方法的使用

  • 分析:

    1.成员变量:品牌、价格

    2.成员方法:打电话、发短信

  • 示例代码:

    Phone.java

    package com.it.test;
    
    public class Phone {
        // 品牌、价格
        String brand;
        int price;
    
        // 打电话
        public void call(String name){
            System.out.println("给" + name + "打电话");
        }
    
        // 发短信
        public void sendMessage(){
            System.out.println("群发短信");
        }
    }
    

    TestPhone.java

    package com.it.test;
    
    public class TestPhone {
        public static void main(String[] args) {
            // 创建对象
            Phone p = new Phone();
            // 给成员变量赋值
            p.brand = "荣耀";
            p.price = 2999;
            // 打印赋值后的成员变量
            System.out.println(p.brand + "..." + p.price); // 荣耀...2999
            // 调用成员方法
            p.call("雷军"); // 给雷军打电话
            p.sendMessage(); // 群发短信
        }
    }
    

二、对象内存图

2.1 示例

Student.java

package com.it.test;

public class Student {
    // 属性:姓名、年龄
    // 成员变量:类中方法外
    String name;
    int age;

    // 行为:学习
    // 成员方法
    public void study(){
        System.out.println("学习");
    }
}

TestStudent.java

package com.it.test;

public class TestStudent {
    public static void main(String[] args) {
        // 类名 对象名 = new 类名();
        Student stu = new Student();

        // 对象名.变量名
        // 默认初始化值
        System.out.println(stu.name); // null
        System.out.println(stu.age); // 0

        // 设置值
        stu.name = "张三";
        stu.age = 29;
        System.out.println(stu.name); // 张三
        System.out.println(stu.age); // 29

        // 修改值
        stu.name = "李四";
        System.out.println(stu.name); // 李四

        // 对象名.方法名();
        stu.study(); // 学习
        System.out.println(stu); // com.it.test.Student@1540e19d 全类名(包名 + 类名)
    }
}

流程:

  1. 测试类的字节码文件(TestStudent.class)加载到方法区,这个里面有一个主方法字节码(main)会被加载
  2. 主方法会进入栈内存去执行
  3. 执行到Student s的时候,Student.class会在方法区加载,会将study()方法加载进方法区
  4. new Student();的时候,会在堆内存中开辟一块空间,会将成员变量name、age加载在这里 String name = null,int age = 0;同时,也会在堆内存中的这块地址里,存储study()成员方法的地址,指向方法区中的study()方法所在的字节码
  5. 创建完毕,这时,堆内存中的这块区域也有一个地址,比如001stu,会赋值给 Student s = 001stu;,现在通过s这个变量,就可以找到堆内存中的这块空间
  6. System.out.println(s); 打印这个地址值
  7. System.out.println(s.name); 打印这个属性
  8. s.name = "张三",将堆内存中的这块地址的name属性改为张三
  9. 执行到s.study()的时候,通过s找到堆内存中的这块地址,.study(),通过这个方法的引用去找方法区的这个地址,然后把方法加载到栈内存中去执行
  10. study()方法执行完毕,就弹栈
  11. 主方法(main)执行完毕,也弹栈

2.2 单个对象内存图

2.3 多个对象内存图

总结:

多个对象在堆内存中,都有不同的内存划分,成员变量存储在各自的内存区域中,成员方法多个对象共用一份

2.4 多个对象指向相同内存图

总结:

当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的),只要有任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,都是修改后的数据

三、成员变量和局部变量

3.1 成员变量和局部变量的区别

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

四、封装

4.1 private关键字

  • 概述

    private是一个修饰符,可以用来修饰成员(成员变量、成员方法)

  • 特点

    private修饰的成员,只能在本类进行访问,针对private修饰的成员变量,如果需要被其他类使用,提供相应的操作

    1. 提供 get变量名() 方法 ,用于获取成员变量的值,方法用public修饰
    2. 提供 set变量名(参数) 方法,用于设置成员变量的值,方法用public修饰
  • 示例代码

    Student.java

    package com.it.test;
    
    // 学生类
    public class Student {
        // 成员变量
        String name;
        private int age;
    
        // 提供get、set方法
        public int getAge() {
            return age;
        }
        public void setAge(int a) {
            if(a < 0 || a > 120){
                System.out.println("你给的年龄有误");
            }else{
                age = a;
            }
        }
    
        // 成员方法
        public void show(){
            System.out.println(name + "," + age);
        }
    }
    

    StudentDemo.java

    package com.it.test;
    
    public class StudentDemo {
        public static void main(String[] args) {
            // 创建对象
            Student stu = new Student();
            // 给成员变量赋值
            stu.name = "林青霞";
            stu.setAge(30);
            // 调用成员方法
            stu.show(); // 林青霞,30
        }
    }
    

4.2 private关键字的使用

  • 需求:

    1. 定义标准的学生类,要求nameage使用private修饰
    2. 并提供getset方法及便于显示数据的show方法
    3. 测试类中创建对象并使用,最终控制台输出 林青霞,30
  • 示例代码

    Studnet.java

    package com.it.test;
    
    // 学生类
    public class Studnet {
        // 成员变量
        private String name;
        private int age;
    
        // get、set方法
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        // 成员方法
        public void show(){
            System.out.println(name + "," + age);
        }
    }
    

    StudentDemo.java

    package com.it.test;
    
    // 学生测试类
    public class StudentDemo {
        public static void main(String[] args) {
            // 创建对象
            Studnet stu = new Studnet();
            // 使用set方法给成员变量赋值
            stu.setName("林青霞");
            stu.setAge(30);
            // 调用成员方法
            stu.show(); // 林青霞,30
    
            // 使用get方法获取成员变量的值
            System.out.println(stu.getName() + "---" + stu.getAge()); // 林青霞---30
        }
    }
    

4.3 this关键字

  • 概述

    • this修饰的变量用于指代成员变量,其主要作用是(区分局部变量和成员变量的重名问题)
    • 方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量
    • 方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量
  • 代码实现

    package com.it.test;
    
    // 学生类
    public class Studnet {
        // 成员变量
        private String name;
        private int age;
    
        // get、set方法
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        // 成员方法
        public void show(){
            System.out.println(name + "," + age);
        }
    }
    

4.4 this内存原理

  • 概述

    this代表当前调用方法的引用,哪个对象调用的方法,this就代表哪一个对象

  • 图解

4.5 封装思想

  • 概述

    是面向对象的三大特征之一(封装、继承、多态)

    是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的

  • 原则

    将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问

    成员变量private,提供对应的getset方法

  • 好处

    通过方法来控制成员变量的操作,提高了代码的安全性

    把代码用方法进行封装,提高了代码的复用性

五、构造方法

5.1 构造方法的格式和执行时机

  • 格式

    • 方法名与类名相同,大小写也要一致
    • 没有返回值类型,连void都没有
    • 没有具体的返回值(不能由return带回结果数据)
  • 执行时机

    • 创建对象的时候调用,每创建一次对象,就会执行一次构造方法
    • 不能手动调用构造方法
  • 示例

    Student.java

    package com.it.test02;
    
    public class Student {
        private String name;
        private int age;
    
        public Student() {
            System.out.println("无参构造方法");
        }
    
        public void show(){
            System.out.println(name + "," + age);
        }
    }
    

    StudentDemo.java

    package com.it.test02;
    
    public class StudentDemo {
        public static void main(String[] args) {
            Student stu = new Student(); // 无参构造方法
            stu.show(); // null,0
        }
    }
    

5.2 构造方法的作用

用于给对象的数据(属性)进行初始化

Student.java

package com.it.test03;

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

    // 如果一个类中没有编写任何构造方法,系统将会提供一个默认的无参数构造方法
    public Student() {
    }

    // 如果手动编写了构造方法,系统就不会再提供默认的无参数构造方法了
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("我是Student类的构造方法");
    }

    public void show(){
        System.out.println(name + "," + age);
    }
}

StudentDemo.java

package com.it.test03;

public class StudentDemo {
    public static void main(String[] args) {
        Student stu = new Student("张三", 20); // 我是Student类的构造方法
        stu.show(); // 张三,20
    }
}

5.3 构造方法的注意事项

  • 构造方法的创建

    • 如果没有定义构造方法,系统将会给出一个默认的无参数构造方法
    • 如果定义了构造方法,系统将不再提供默认的构造方法
  • 推荐的使用方式

    无论是否使用,都手动书写无参数构造方法和带参数构造方法

5.4 标准类的代码编写和使用

Student.java

package com.it.test04;

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

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void show(){
        System.out.println(name + "," + age);
    }
}

StudentDemo.java

package com.it.test04;

public class StudentDemo {
    public static void main(String[] args) {
        // 无参数构造方法创建对象,通过set方法给成员变量进行赋值
        Student stu = new Student();
        stu.setName("张三");
        stu.setAge(20);
        stu.show(); // 张三,20

        // 通过带参数的构造方法,直接给属性进行赋值
        Student stu2 = new Student("李四", 23);
        stu2.show(); // 李四,23
    }
}

问题

  1. 为啥不同的包不能对象.属性名获取属性,同一个包可以?
posted @ 2023-07-08 10:38  徐林俊  阅读(13)  评论(0编辑  收藏  举报