Java面向对象

面向过程

  • 是站在过程的角度思考问题,强调的就是功能行为,功能的执行过程。
  • 即先干啥,后干啥。而每一个功能我们都使用函数(类似于方法)把这些步骤一步一步实现,使用的时候依次调用函数就可以了。
  • 按顺序一个一个来去做。

🐤面向过程的设计

  • 最小的程序单元是 函数,每个函数负责完成某一个功能,用以接受输入数据,函数对输入数据进行处理,然后输出结果数据。
  • 整个软件系统由一个个的函数组成,其中作为程序入口的函数称之为 主函数
  • 主函数依次调用其他函数,普通函数之间可以相互调用,从而实现整个系统功能。

🐸面向过程的缺陷

  • 面向过程的设计,是采用置顶而下的设计方式。
  • 在设计阶段就需要考虑每一个模块应该分解成哪些子模块,每一个子模块又细分为更小的子模块。
  • 如此类推,直到将模块细化为一个个函数。
public class Demo {

    static void buy(){
        System.out.println("拿钱买菜");
    }

    static void doFood(){
        System.out.println("做饭");
    }

    static void eat(){
        System.out.println("吃饭");
    }

    static void wash(){
        System.out.println("洗碗");
    }

    public static void main(String[] args) {
        buy();
        doFood();
        eat();
        wash();
    }
}

面向对象基本理论

🐤什么是对象

  • 万物皆对象。
  • 对象是具体的物体。
  • 拥有属性。
  • 拥有行为。
  • 把很多零散的东西,封装成为了一个整体。

例如

  • 王二小
    • 属性
      • 姓名
      • 年龄
      • 身高
      • 体重
      • ...
    • 行为
      • 走路
      • 吃饭
      • 放牛
      • ...

🦄面向过程和面向对象

  • 都是一种解决问题的思路(思想)

面向过程

  • 在解决问题的时候,关注的是解决问题的每一个的过程(步骤)

面向对象

  • 在解决问题的时候,关注的是解决问题所需要的对象。

🐥举个例子:做好饭之后洗碗

面向过程

    • 洗菜
    • 点火倒油
    • 放菜,材料
    • 翻炒
    • 盛出
    • 放水
    • 放碗
    • 倒洗洁精
    • 开始刷
    • 擦干水
    • 摆放好

面向对象

  • 你:对象
    • 技能1:做饭
      • 洗菜
      • 点火倒油
      • 放菜,材料
      • 翻炒
      • 盛出
    • 技能2:洗碗
      • 放水
      • 放碗
      • 倒洗洁精
      • 开始刷
      • 擦干水
      • 摆放好

🐬对比

  • 面向对象和面向过程都是解决问题的一种方式(思想),面向对象本身是对面向过程的封装。

面向过程编程最重要的是什么

  • 按照步骤划分。
  • 把一个任务,分解成具体的每一个步骤。

面向对象编程最重要的是什么

  • 按照功能对象进行划分。
  • 找到对象,确定对象的属性和行为。

如何从面向过程编程的思想,过渡到面向对象编程

  • 一样的,列举出一个任务的具体实现步骤。
  • 试图分离这些实现步骤中的功能代码块。
  • 将这些功能代码块,划分到某一个对象中。
  • 根据这个对象以及对应的行为,抽象出对应的类(设计类)

  • 某一个具体对象特征的抽象。

例如

  • 张三这个具体的人。
    • 属性
      • 年龄:23
      • 身高:180
      • 体重:250
      • ...
    • 行为
      • 吃:吧唧嘴
      • 喝:放白糖
      • 赌:没赢过
      • ...

抽象出来的类

  • 不良青年类。
    • 属性
      • 年龄
      • 身高
      • 体重
      • ...
    • 行为
      • 打架
      • ...

类的作用

  • 根据抽象的类,生产出具体的对象。

例如

    • 不良青年
      • 属性
        • 年龄
        • 身高
        • 体重
        • ...
      • 行为
        • 打架
        • ...
  • 对象
    • 张三
      • 不同的身高,体重等属性。
      • 不同的行为。
    • 李四
      • 不同的身高,体重等属性。
      • 不同的行为。
    • 王五
      • 不同的身高,体重等属性。
      • 不同的行为。

🐤列举生活中的类

类:钱
对象:具体的1毛的,5毛的,1块的,5块的,...

类:熊类
对象:熊大,熊二,...

类:汽车
对象:奥拓, 奥迪, 马自达,...

🦄对象和类的关系

对象 → 抽象 → 类 → 实例化 → 对象。

面向对象

  • 一种基于面向过程的新的编程思想,顾名思义该思想是站在对象的角度来思考问题。
  • 我们把多个功能合理的放到不同的对象里,强调的是具备某些功能的对象。
  • 具备某种功能的实体,称为对象。
  • 面向对象的最小程序单元是

面向对象三大特征

  • 封装(Encapsulation):封装是指将对象的实现细节隐藏起来,然后通过公共的方法来向外暴露该对象的功能。
  • 继承(Inheritance):继承是面向对象实现软件复用的重要手段,当子类继承父类后,子类是一种特殊的父类,能直接或间接获得父类里的成员。
  • 多态(Polymorphism):多态是可以直接把子类对象赋给父类变量,但是运行时依然表现出子类的行为特征,这意味着同一类型的对象在运行时可能表现出不同的行为特征。

对象与类的关系

类的定义

🐱‍🐉类的定义格式

[修饰符] class 类名
{
       0~N个成员变量(字段 / Field)
       0~N个方法
}

🐤注意点

  • 如果类使用了 public 修饰符,必须保证当前文件名称和当前的类名相同。
  • 类名使用名称表示,类表示某一类事物,首字母大写,如果是多个单词组成使用驼峰表示法来进行命名。

对象的创建与对象的操作

public class StackTest {

    public static void sum(int a, int b) {
        System.out.println(a + b);
    }
    
    public static void main(String[] args) {
        int x = 10;
        sum(10, 20);
    }
}

JVM 的内存分析

JVM 将内存主要划分为了:方法区本地方法栈程序计数器,这些区域。

🤳虚拟机栈

  • 执行引擎每调用一个函数时,就为这个函数创建一个栈帧,并加入虚拟机栈。
  • 换个角度理解,每个函数从调用到执行结束,其实是对应一个栈帧的入栈和出栈。
  • 声明的变量都是存到栈当中的。

🐱‍🏍堆

  • 被所有线程共享的一块区域,在虚拟机启动时创建,所有的对象实例及数组都在堆上分配。
  • 使用 new 关键字,表示在堆中开辟一块新的存储空间。

✨方法区

  • 又叫静态区,存放所有的 class字节码static变量;方法区中包含的都是在程序中永远唯一的元素。

🐱‍👤程序计数器

  • 每个线程都有个计数器记录当前执行到那个指令。可以把它看成是当前线程所执行的字节码的行号指示器。

🐱‍👓本地方法区

  • 本地方法栈与虚拟机栈所发挥的作用很相似,他们的区别在于虚拟机栈为执行 Java 代码方法而服务,而本地方法栈是为 Native(本地的 Java 代码提供的)方法服务。

🐱‍💻GC

  • 后面在介绍。

数据类型

基本数据类型:值传递

  • 只有一块存储空间, 在栈中,存放的是具体的值。

引入数据类型:内存地址传递

  • 引用数据类型有两块存储空间。
  • 一个在栈(Stack)中,一个在堆(heap)中。栈中存放的是堆中的地址。
  • 栈中的存取速度要快于存储在堆中的对应包装类的实例对象。

匿名对象与构造器

🐤匿名对象

  • 匿名对象就是没有名字的对象。
  • 匿名对象只能使用一次。
public class PersonTest {
    public static void main(String[] args) {
        // 这个zs,就是一个对象,名字就是zs
        Person zs = new Person();
        
        // 这个也是一个对象,但是没有名字
        new Person();
    }
}

构造器

  • 方法名称与类名相同 这种特殊的方法我们称之为构造器。
  • 某一个类,至少存在一个构造器。

🦄构造器的作用

  • 创建对象,凡是必须和 new 一起使用。
  • 完成对象的初始化操作。

🐬构造器的特点

  1. 构造器的名称和当前所在类的名称相同。
  2. 禁止定义返回类型,千万不要使用 void 作为返回类型,例如:void Person(){} 这就成了普通方法了,不是构造器了。
  3. 在构造器中,不需要使用 return 语句。
  4. 构造器其实是有返回值,它返回的是当前创建对象的地址。

🐥默认构造器的特点

  1. 符合构造器的特点。
  2. 无参数的。
  3. 无方法体。
  4. 如果类 A 没有使用 public 修饰,则编译器创建的构造器也没有 public 修饰,使用了 public 修饰,则编译器创建的构造器也使用 public 修饰。
  5. 如果需要证明这一点,可以自己创建一个类首先使用 public 修饰和不修饰,然后查看一下编译的字节码即可证明。

🐸自定义构造器

我们可以自己来去定义构造器,自定义的构造器也要符合构造器的特点。

  1. 我们自己写的构造器,就称为自定义构造器。
  2. 如果我们自己定义了构造器,则编译器不再创建默认构造器。
  3. 一个类至少存在一个构造器。
  4. 创建对象其实是在调用构造器。
public class User {
    String name;

    User(String userName) {
        System.out.println("---执行了自己的构造器-");
        
        //在构造器当中,对字段做了初始化
        name = userName;
    }

    public static void main(String[] args) {
        User user = new User("BNTang");
        System.out.println(user.name);
    }
}

🐪构造器的重载

  • 方法重载:方法名相同 ,参数不一样。
  • 构造器重载:构造器的名相同 ,参数不一样。
  • 参数不一样,在创建对象时,根据参数不同,调用不同的构造器。
public class User {
    String userName = null;
    int userAge;

    User(String name) {
        userName = name;
    }

    User(String name, int age) {
        userName = name;
        userAge = age;
    }

    public static void main(String[] args) {
        User user = new User("BNTang");
        
        System.out.println("用户名 = " + user.userName);
        System.out.println("用户年龄 = " + user.userAge);
    }
}

🐪自定义构造器参数传递注意事项

  • 变量赋值的顺序,先找自己方法当中的变量,没有找到就会到类中来去找对应的变量。
  • 如果想要直接赋值给类当中的变量,就必须在前面加上一个 this 关键字。
public class User {
    String userName = null;
    int userAge;

    User(String name) {
        this.userName = name;
    }

    User(String name, int age) {
        this.userName = name;
        this.userAge = age;
    }

    public static void main(String[] args) {
        User user = new User("BNTang");
        
        System.out.println("用户名 = " + user.userName);
        System.out.println("用户年龄 = " + user.userAge);
    }
}

static 关键字

  • 在我们的生活当中,有些事物不属于某一个对象,而是属于整个事物的类型。
  • 比如:全世界人口的总数。
  • 人的毁灭行为:毁灭的行为应该属于人类,不应该属于某一个人。
  • 状态和行为应该有 对象 之分。
  • 有的状态和行为,应该属于某个对象。
  • 有的状态和行为,应该属于类。

static 的作用

  • 通过 static 修饰符就能解决这个问题,它修饰的成员就不属于对象,它属于类本身。
  • 它可以修饰字段,方法,内部类。
  • 作用:确定修饰的内容是属于类还是属于对象。

static 的特点

  1. static 修饰的内容,随着类的加载而加载。
  2. 优先于对象的存在。
  3. static 修饰的成员被该类的所有对象共享。
  4. 可以直接使用当前类的类名来访问 static 成员。

DemoOne

public class Person {
    // 人口
    static int totalNums = 0;

    // 毁灭
    //静态方法,只能访问静态成员
    static void destroy() {
        System.out.println("人类毁灭啦");
    }

    // 状态:名词
    String name;
    int age;

    // 行为:动词
    void die() {
        System.out.println(name + "死了");
        Person.totalNums--;
    }

    //---------以上属于对象---------
    // 构造器的作用,创建对象,一创建对象时,就给内部的字段做初始化
    Person(String n, int a) {
        name = n;
        age = a;
        Person.totalNums++;
    }

    public static void main(String[] args) {
        System.out.println(Person.totalNums);
        Person per = new Person("zs", 1);
        System.out.println(per.name);
        System.out.println(per.age);
        per.die();

        System.out.println(Person.totalNums);
        Person per2 = new Person("ls", 2);
        System.out.println(per2.name);
        System.out.println(per2.age);

        Person.destroy();

        // 通过类名调用
        System.out.println(Person.totalNums);

        // 可以通过,对象来去调用静态成员
        // 本质还是通过类名来调用
        System.out.println(per2.totalNums);
    }
}

DemoTwo

public class Person {
    static int totalNums = 0;
    String name;
    int age;

    void eat(String food) {
        System.out.println(name + "吃了" + food);
    }

    Person(String name, int age) {
        this.name = name;
        this.age = age;
        Person.totalNums++;
    }

    Person(int age) {
        this.age = age;
        Person.totalNums++;
    }

    void die() {
        System.out.println(name + "从地球上消失");
        Person.totalNums--;
    }

    static void destroy() {
        Person.totalNums = 0;
    }
}

class test {
    public static void main(String[] args) {
        Person person = new Person("张三", 1);
        person.name = "张四";
        person.eat("奶粉");
        System.out.println(Person.totalNums);

        Person person1 = new Person(1);
        person1.name = "李四";
        person1.eat("奶粉");

        Person ww = new Person("王五", 1);
        ww.eat("奶粉");

        person.die();
        Person.destroy();
        System.out.println("总人口:" + Person.totalNums);

        // 当使用对象调用静态的内容(方法,还是字段 )在运行时, 都会去掉
        // 还是使用类名来调用
        System.out.println(ww.totalNums);
    }

}

成员变量与局部变量

所谓变量就是:数据类型 变量名 = 值;

成员变量

直接定义在类中,方法的外面,也称全局变量或字段,不要叫属性。

  • 类成员变量:使用 static 修饰的字段。
  • 实例成员变量:没有使用 static 修饰的字段。
  • 在方法中不能定义 static 变量,static 修饰的属于类。
  • 方法属于对象。

局部变量

变量除了成员变量,其它都是局部变量。

  • 方法内部的变量就是局部变量。
  • 方法的参数也是。
  • 代码块中的变量也是的。

🐤成员变量与局部变量的区别

变量的初始值

  • 成员变量:默认是有初始值的。
  • 局部变量:没有初始值,所以必须先初始化才能使用。

变量的使用域

  • 成员变量:在整个类中都有效。
  • 局部变量:只在它定义的大括号内生效。
  • 成员变量,可以先使用后定义,局部变量必须先定义之后才能使用。

🐸变量的作用域及生命周期

变量的生命周期指的是一个变量被创建并分配内存空间开始,到该变量被销毁并清除所占内存空间的过程,作用域不同,生命周期就不一样。

🐥变量使用时的注意点

  • 局部变量定义后,必须显示初始化后才能使用,因为系统不会为局部变量执行初始化操作。
  • 这就意味着,定义局部变量后,系统还没有给这个变量分配内存空间。
  • 直到程序为这个变量赋值时,系统才会为局部变量分配内存,并将初始值保存到该内存中。
  • 局部变量不属于任何类或实例,因此它总是保存在其所在方法的栈内存中。
  • 基本数据类型的局部变量,直接把这个变量的值保存到该变量数据类型所对应的内存中(栈)
  • 引用数据类型的局部变量,这个变量在内存中存的是地址,通过该地址引用到该变量实际内存中堆里的的对象的值。
  • 栈内存中的变量无需系统来做垃圾回收,其往往随,方法或代码块的运行结束而结束。
public class Person {
    // 成员变量
    static int totalNums;

    // 实例成员变量
    String name;
    int age;
    int times;

    void eat(String food) {
        // 局部变量
        int a = 10;
        if (times >= 3) {
            System.out.println("不能再吃了");
        } else {
            System.out.println("吃了" + food);
            times++;
        }
    }

    Person(String n, int a) {
        name = n;
        age = a;
        Person.totalNums++;
    }

    public static void main(String[] args) {

        Person per = new Person("zs", 18);
        System.out.println(Person.totalNums);
        per.eat("米饭");
    }
}
posted @ 2020-08-15 22:33  BNTang  阅读(110)  评论(0编辑  收藏  举报