java基础快速入门--面向对象(基础)

247 阅读13分钟

类与对象

  • 看一个养猫问题 张老太养了两只猫:一只名字叫小白,今年三岁,白色。还有一只叫小花,今年一百岁,花色。请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,则显示张老太没有这只猫猫

    • 使用现有的技术解决

      /**
       * @author L.yn
       * @version 1.0
       * @date 2021/12/12 14:55
       */
      public class Object01 {
          public static void main(String[] args) {
              /*张老太养了两只猫:
              一只名字叫小白,今年三岁,白色。
              还有一只叫小花,今年一百岁,花色。
              请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,年龄,颜色。
              如果用户输入的小猫名错误,则显示张老太没有这只猫猫*/
      
              //一、单独变量来解决 => 不利于数据的管理(把一只猫的信息拆解)
              //第一只猫信息
              String cat1Name = "小白";
              String cat1Color = "白色";
              int cat1Age = 3;
      
              //第二只猫信息
              String cat2Name = "小花";
              String cat2Color = "花色";
              int cat2Age = 100;
      
              //二、数组 => (1)数据类型体现不出来
              // (2)只能通过[下标]获取信息,造成变量名字和内容的对应关系不明确
              // (3) 不能体现猫的行为
              String[] cat1 = {"小白", "3", "白色"};
              String[] cat2 = {"小花", "100", "花色"};
          }
      }
      
      
      • 现有技术解决的缺点分析
        • 不利于数据的管理
        • 效率低======>引出我们的新知识:类与对象(OOP)
  • 一个程序就是一个对象,有很多事务(对象[属性,行为])

  • 类与对象的关系示意图 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fb0Lff6W-1639298383841)(C:\Users\MSI-NB\AppData\Roaming\Typora\typora-user-images\image-20211212151006021.png)]

    • 对上图说明
      • 类就是数据类型,比如Cat
      • 对象就是一个具体的实例
  • 快速入门-面向对象的方式解决养猫问题

    /**
     * @author L.yn
     * @version 1.0
     * @date 2021/12/12 14:55
     */
    public class Object01 {
        public static void main(String[] args) {
            /*张老太养了两只猫:
            一只名字叫小白,今年三岁,白色。
            还有一只叫小花,今年一百岁,花色。
            请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,年龄,颜色。
            如果用户输入的小猫名错误,则显示张老太没有这只猫猫*/
    
            //使用oop面向对象解决
            //实例化一只猫(创建一只猫对象)
            /**
             * 一、new Cat();创建一只猫
             * 二、Cat cat1 = new Cat(); 把创建的猫赋给cat1
             * 三、cat1、cat2就是一个对象
             */
            Cat cat1 = new Cat();
            cat1.name = "小白";
            cat1.age = 3;
            cat1.color = "白色";
            Cat cat2 = new Cat();
            cat2.name = "小花";
            cat2.age = 100;
            cat2.color = "花色";
    
            //怎么访问对象的属性呢
            //第一只猫信息:小白 3 白色
            //第二只猫信息:小花 100 花色
            System.out.println("第一只猫信息:" + cat1.name + " " + cat1.age + " " + cat1.color);
            System.out.println("第二只猫信息:" + cat2.name + " " + cat2.age + " " + cat2.color);
        }
    }
    
    
    /**
     * 使用面向对象的方式来解决养猫问题
     * 字定义一个猫类  Cat -> 字定义的数据类型
     */
    class Cat {
        //属性
        String name;//名字
        int age;//年龄
        String color;//颜色
    
    }
    
  • 对象在内存中存在的形式 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xon42Lom-1639298383843)(C:\Users\MSI-NB\AppData\Roaming\Typora\typora-user-images\image-20211212153656232.png)]

  • 属性/成员变量

    • 基本介绍

      • 从概念或叫法上看:成员变量 = 属性 = field(即 成员变量是用来表示属性的)

      • 属性时类的一个组成部分,一般是基本数据类型,也可以是引用类型(对象,数组)

        • class Car {
              String name;//属性,成员变量,字段 field
              double price;
              String color;
              String[] master;//属性可以是基本数据类型,也可以是引用数据类型(对象,数组)
          }
          
      • 注意事项和细节说明

        • 属性的定义语法同变量,示例:访问修饰符 属性类型 属性名;
          • 访问修饰符:控制属性的访问范围,有四种访问修饰符:public proctected default private
        • 属性的定义类型可以为任意类型,包含基本类型和引用类型
        • 属性如果不赋值,有默认值,规则和数组一致
  • 如何创建对象

    • 先声明在创建 Cat cat;//声明对象 cat = new Cat();//创建对象
    • 直接创建 Cat cat = new Cat();
  • 如何访问属性

    • 基本语法
      • 对象名.属性名 cat.name; cat.age; cat.color;
  • 类与对象的内存分配机制

    • java内存的结构分析
      • 栈:一般存放基本数据类型(局部变量)
      • 堆:存放对象(Cat cat,数组等)
      • 方法区:常量池(常量,比如字符串),类加载信息
    • java创建对象的流程简单分析 Person p = new Person(); p.name = "jack"; p.age = 10;
      • 先加载Person类信息(属性和方法信息,只会加载一次)
      • 在堆中分配空间,进行默认初始化(看规则)
      • 把地址赋值给p,p就指向对象
      • 进行指定初始化

成员方法

基本介绍

在某些情况下,我们要需要定义成员方法(简称方法)。比如人类:除了有一些属性外(年龄,姓名..),我们人类还有一些行为,比如:可以说话,跑步...,通过学习,还可以做算术题,这时就要用成员方法才能完成

  • 成员方法快速入门

    • 一:添加speak成员方法,输出我是一个好人 二:添加cal01方法,可以计算从1+...+100的结果 三:添加getSum成员方法,可以计算两个数的和

    • /**
       * @author L.yn
       * @version 1.0
       * @date 2021/12/12 16:45
       */
      public class Method01 {
          public static void main(String[] args) {
              //方法使用
              //1、方法写好后,如果不去调用,不会生效
              Person person = new Person();
              //speak方法输出我是一个好人
              //al01方法输出:5050
              //getSum方法输出:3
              person.speak();
              person.al01();
              System.out.println(person.getSum(1, 2));
          }
      }
      
      /**
       * 一:添加speak成员方法,输出我是一个好人
       * 二:添加cal01方法,可以计算从1+...+100的结果
       * 三:添加getSum成员方法,可以计算两个数的和
       */
      class Person {
          String name;
          int age;
      
          public void speak() {
              System.out.println("speak方法输出我是一个好人");
          }
      
          public void al01() {
              int sum = 0;
              for (int i = 1; i <= 100; i++) {
                  sum += i;
              }
              System.out.println("al01方法输出:" + sum);
          }
      
          public String getSum(int num1, int num2) {
              return "getSum方法输出:" + (num1 + num2);
          }
      }
      

方法递归调用

基本介绍

简单的说:递归就是方法自己调用自己,每次调用时传入不同的变量,递归有助于编程者解决复杂问题,同时可以让代码变得更简洁

递归能解决什么问题?

  • 各种数学问题:汉诺塔,阶乘问题,迷宫问题等
  • 各种算法中也会使用到递归:比如快排,归并排序,二分查找,分治算法等
  • 将用栈解决的问题-->递归代码比较简洁

递归重要规则

  • 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
  • 方法的局部变量是独立的,不会相互影响,比如变量n
  • 如果方法中使用的是引用类型变量(比如数组,对象),就会共享该引用类型的数据
  • 递归必须向退出递归的条件逼近,否则就是无限递归,出现stackoverflowerror
  • 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕

递归练习

  • 猴子吃桃子问题:有一堆桃子,猴子第一天吃了其中的一半,并在多吃了一个!以后每天猴子都吃其中的一半,然后在多吃一个,当到第十天时,想再吃时(即还没吃),发现只有一个桃子了,问题:最初共多少个桃子

方法重载(OverLoad)

  • 快速入门案例

    package com.demo.a;
    
    /**
     * @author L.yn
     * @version 1.0
     * @date 2021/12/13 18:22
     */
    public class OverLoadDemo1 {
        public static void main(String[] args) {
            //使用方法
            System.out.println(new MyCalculator().calculate(1, 2));//3
            System.out.println(new MyCalculator().calculate(1, 2.2));//3.2
            System.out.println(new MyCalculator().calculate(1.1, 2));//3.1
            System.out.println(new MyCalculator().calculate(1, 2, 3));//6
        }
    }
    
    /**
     * 下面的四个calculate方法构成了重载
     */
    class MyCalculator {
        //两个整数的和
        int calculate(int n1, int n2) {
            return n1 + n2;
        }
    
        //一个整数,一个double的和
        double calculate(int n1, double n2) {
            return n1 + n2;
        }
    
        //一个整数,一个double的和
        double calculate(double n1, int n2) {
            return n1 + n2;
        }
    
        //三个整数的和
        int calculate(int n1, int n2, int n3) {
            return n1 + n2 + n3;
        }
    }
    
  • 注意事项和使用细节

    • 方法名:必须相同
    • 形参列表:必须不同(形参类型或个数或顺序,至少有一样不同,参数名无要求)
    • 返回类型:无要求
  • 练习

    • 编写程序,类Methods中定义三个重载方法并调用。方法名字定义,参数字定义,在main方法中调用三个方法

可变参数

基本概念

java允许将同一个类中多个同名通功能但参数个数不同的方法,封装成一个方法

基本语法

访问修饰符 返回类型 方法名(数据类型... 形参名){}

快速入门案例:可以计算2个数的和,3个数的和,4,5....

package com.demo.a;

/**
 * @author L.yn
 * @version 1.0
 * @date 2021/12/15 19:14
 */
public class VarParameterDemo {

    public static void main(String[] args) {
        System.out.println(sum(1, 2, 3));//6
        System.out.println(sum());//0
        System.out.println(sum(123, 4134));//4257
    }

    /**
     * int... 表示接收的是可变参数,类型是int,即可以接收多个int(0->多)
     * 使用可变参数时,可以当作数组来使用
     * 遍历nums求和即可
     *
     * @param nums
     * @return
     */
    public static int sum(int... nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        return sum;
    }
}

注意事项

  • 可变参数的实参可以为0个或任意多个
  • 可变参数的实参可以为数组
  • 可变参数的本质就是数组
  • 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
  • 一个形参列表中只能出现一个可变参数 public int sum(int... a, String... b)//错误

作用域

基本使用

面向对象中,变量作用域是非常重要知识点,相对来说不是特别好理解

  • 在java编程中,主要的变量就是属性(成员变量)和局部变量
  • 我们说的局部变量一般是指在成员方法中定义的变量
  • java中作用域的分类
    • 全局变量:也就是属性,作用域为整个类体
    • 局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中
  • 全局变量可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值
  • 注意事项和细节
    • 属性和局部变量可以重名,访问时遵循就近原则
    • 在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名
    • 属性生命周期较长,伴随着对象的创建而创建,伴随着对象的死亡而死亡,局部变量,生命周期较短,伴随着它的代码块执行而创建,伴随着代码块的结束而死亡,即在一次方法调用过程中
    • 作用域范围不同
      • 全局变量:可以被本类使用,或其他类使用(通过对象调用)
      • 局部变量:只能在本类中对应的方法中使用
    • 修饰符不同
      • 全局变量/属性可以加修饰符
      • 局部变量不能加修饰符

构造方法/构造器

  • 看一个需求

前面我们创建人类的对象时,是先把一个对象创建好后,在给他的年龄和姓名属性赋值,如果现在我要求,在创建人类的对象时,就直接指定这个对象的年龄和姓名,该怎么做?这时就可以使用构造器

  • 基本语法
[修饰符] 方法名(形参列表){
	方法体
}

public class Person{
    String name;
    int age;
    //构造器
    /**
    *一、构造器没有返回值,也不能写void
    *二、构造器的名称和类Person一样
    */
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
}
  1. 构造器的修饰符可以默认
  2. 构造器没有返回值
  3. 方法名和类名字必须一样
  4. 参数列表和成员方法一样的规则
  5. 构造器的调用系统完成
  • 基本介绍

构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化,它有几个特点

  1. 方法名和类名相同
  2. 没有返回值
  3. 构造器时完成对象的初始化,而不是创建对象
  4. 在创建对象时,系统会自动的调用该类的构造器完成对象的初始化
  5. 如果程序员没有定义构造方法,系统会自动给类生成一个默认午餐构造方法,比如Person(){} ,使用javap指令反编译看看
  6. 一旦定义了自己的构造器,默认的构造器就覆盖了,就不能使用默认的午餐构造器,除非显示的定义一下,即:Person(){}

对象创建流程分析

  1. 加载Person类信息,只会加载一次
  2. 在堆中分配空间(地址)
  3. 完成对象初始化[3.1默认初始化,age=0 name=null]

this关键字

package com.demo.a;

/**
 * @author L.yn
 * @version 1.0
 * @date 2021/12/19 15:51
 */
public class ThisDemo {
    public static void main(String[] args) {
        Dog dog = new Dog("大壮", 18);
        dog.info();//大壮 18
    }
}

class Dog {
    String name;
    int age;

//    public Dog(String dName, int dAge) {//构造器
//        name = dName;
//        age = dAge;
//    }
    //如果我们构造器的形参,能够直接写成属性名,就更好了

    /**
     * 但是出现了一个问题,根据变量的作用域原则
     * 构造器的name是局部变量,而不是属性
     * 构造器的age是局部变量,而不是属性
     * ==> 引出this关键字来解决
     *
     * @param name
     * @param age
     */
    public Dog(String name, int age) {//构造器
        name = name;
        age = age;
    }

    public void info() {//成员方法,输出属性X信息
        System.out.println(name + " " + age);
    }
}
  • 什么是this

java虚拟机会给每个对象分配this,代表当前对象。坦白的讲,要明白this不是件容易的事

  • 使用this解决前面变量命名的问题

    package com.demo.a;
    
    /**
     * @author L.yn
     * @version 1.0
     * @date 2021/12/19 15:51
     */
    public class ThisDemo {
        public static void main(String[] args) {
            Dog dog = new Dog("大壮", 18);
            dog.info();//大壮 18
        }
    }
    
    class Dog {
        String name;
        int age;
    
    //    public Dog(String dName, int dAge) {//构造器
    //        name = dName;
    //        age = dAge;
    //    }
        //如果我们构造器的形参,能够直接写成属性名,就更好了
    
        /**
         * 但是出现了一个问题,根据变量的作用域原则
         * 构造器的name是局部变量,而不是属性
         * 构造器的age是局部变量,而不是属性
         * ==> 引出this关键字来解决
         *
         * @param name
         * @param age
         */
    //    public Dog(String name, int age) {//构造器
    //        name = name;
    //        age = age;
    //    }
    
        public Dog(String name, int age) {//构造器
            //this.name 就是当前对象的属性
            this.name = name;
            //this.age 就是当前对象的属性
            this.age = age;
        }
    
        public void info() {//成员方法,输出属性X信息
            System.out.println(name + " " + age);
        }
    }
    
  • 小结:简单的说,哪个对象调用,this就代表哪个对象

  • 注意事项和使用细节

  • this关键字可以用来访问本类的属性,方法,构造器

  • this用于区分当前类的属性和局部变量

  • 访问成员方法的语法:this.方法名(参数列表)

  • 访问构造器语法:this(参数列表);注意只能在构造器中使用

  • this不能在类定义的外部使用,只能在类定义的方法中使用

  • package com.demo.a;
    
    /**
     * @author L.yn
     * @version 1.0
     * @date 2021/12/19 16:24
     */
    public class ThisDemo1 {
        public static void main(String[] args) {
            //T(String name, int age)构造器
            //f2方法
            //f1方法
            //f1方法
            new T().f2();
        }
    }
    
    class T {
        String name;
        int age;
    
        //访问构造器语法:this(参数列表);注意只能在构造器中使用
        //注意:访问构造器语法:this(参数列表)必须放置在第一条语句
        public T() {
            this("aa", 19);
        }
    
        public T(String name, int age) {
            System.out.println("T(String name, int age)构造器");
        }
    
        //访问成员方法的语法:this.方法名(参数列表)
        public void f1() {
            System.out.println("f1方法");
        }
    
        public void f2() {
            System.out.println("f2方法");
            //第一种方式
            f1();
            //第二种方式
            this.f1();
        }
    }