Chapter 07 OOP初级 part1
侧边栏壁纸
  • 累计撰写 53 篇文章
  • 累计收到 5 条评论

Chapter 07 OOP初级 part1

bbchen
2022-09-18 / 0 评论 / 60 阅读 / 正在检测是否收录...

面向对象

引入问题:

image-20220828062750617

单独变量解决 => 不利于数据的管理

数组 => (1)数据类型无法体现 (2)只能通过下标获取信息,造成变量名和内容对应关系不明确 (3)不能体现行为

类与对象

类:自定义的数据类型,(属性,行为)

对象:一个具体的实例

对象内存分布

image-20220828070054664

引用数据类型放在常量池

属性/成员变量(field)

可以是基本数据类型,也可以是引用类型

1) 访问修饰符:控制属性的访问范围,四种(public private protected 默认)
2) 属性的定义类型可以为任意类型
3) 属性如果不赋值,则默认值和数组相同

创建对象

  1. 先声明在创建
Cat cat;
cat = new Cat();
  1. 直接创建
Cat cat = new Cat();

类和对象的内存分配机制

image-20220828071855948

本质是地址引用

image-20220828072147551

java创建对象的流程简单分析

image-20220829121402901

  1. 先加载Person类信息(属性和方法信息,只会加载一次)
  2. 在堆中分配空间,进行默认初始化,
  3. 把地址赋给 p,p 就指向对象
  4. 进行指定初始化,p.name = "jack" p.age = 10

成员方法(简称方法)

定义

public 返回类型 方法名 (形参列表...){ //方法体
    语句;
    return 返回值;
}

image-20220906231500565

例子:

image-20220829123304144

public class Method01 {
    public static void main(String[] args) {
        Person aPerson = new Person();

        // 方法写好后,不调用不会输出
        aPerson.speak();    // 调用方法

        System.out.println(aPerson.cal01());
        System.out.println(aPerson.cal02(20));
        System.out.println(aPerson.getSum(13, 17));
    }
}

class Person {
    
    String name;
    int age;

    // public 表示方法公开, void 表示没有返回值
    // speak() speak 是方法名, ()形参列表
    public void speak(){
        System.out.println("I\'m a good man.");
    }

    // 计算 1 + 2 + ... + 1000 的结果
    public int cal01() { 
        int res = 0;
        for (int i = 1; i < 1001; i++) {
            res += i;
        }
        return res;
    }
    
    // (int n) 形参列表,表示当前有一个形参 n, 可以接受用户输入
    public int cal02(int n){
        int res = 0;
        for (int i = 1; i < n + 1; i++) {
            res += i;
        }
        return res;
    }

    public int getSum(int num1, int num2){
        int res = num1 + num2;
        return res;
    }
}

方法调用内存分析

image-20220829124244955

方法调用小结

  1. 当程序执行到方法时,会开辟出一个独立的空间(栈空间)
  2. 当方法执行完毕,或者执行到 return 语句时,就会返回
  3. 返回到调用方法的地方
  4. 返回后,继续执行方法后面的代码
  5. 当 main 方法(栈)执行完毕,这个程序退出

成员方法的好处

  • 提高代码的复用性
  • 可以将实现的细节封装起来,然后供其他用户来调用即可

细节

返回数据类型
  1. 一个方法最多有一个返回类型(如果返回多个结果,返回数组)
  2. 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
  3. 如果方法有返回数据类型,则方法体中最后执行的语句必须为 return 值;而且返回要求返回值类型必须和 return 的值类型一致或兼容
  4. 如果方法是void,则方法体中可以没有 return,或者只写 return ;
  5. 方法名遵循驼峰命名法,如 getSum
参数列表
  1. 一个方法可以有 0 个参数,也可以有多个参数,中间用逗号隔开,例如 :

    getSum(int n1, int n2)
  1. 参数类型可以为任意类型,包含基本类型和引用类型,比如 :

    printArr(int[][] map)
  2. 调用带参数的方法时,一定对应这参数列表传入相同类型或兼容类型的参数。
  3. 方法定义时的参数称为形式参数,简称形参;方法调用时的参数成为实际参数,简称实参,实参和形参的类型要一致或兼容,个数、顺序必须一致。
成员方法
  1. 同一个类中的方法调用:可以直接调用。
  2. 跨类的方法 A 类调用 B 类方法:需要先创建 B 对象,再通过对象名调用。对象名.方法名(参数)
  3. 访问修饰符,后面再细说。

练习

image-20220908193148722

image-20220908193348244

public class MethodExercise01 {
    public static void main(String[] args) {
        AA j = new AA();
        System.out.println(j.isOdd(3));
        j.print(3, 4, '#');
    }
}


class AA{
    // 判断奇数还是偶数,奇数odd返回 true,偶数返回 false
    public boolean isOdd(int inputNum){
        return inputNum  % 2 == 0 ? false : true;
    }

    public void print(int row, int column, char c){
        for(int i = 0; i < row; i++){
            for (int j = 0; j < column; j++) {
                System.out.print(c + " ");
            }
            System.out.println();
        }
    }
}

成员方法传参机制

基本数据类型
public class MethodParameter01{
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        System.out.println("main中交换前:");
        System.out.println("a = " + a + " b = " + b);
        
        AA obj = new AA();
        obj.swap(a, b);
        
        System.out.println("main中交换后:");
        System.out.println("a = " + a + " b = " + b);
    }
}

class AA{
    
    public void swap(int a, int b){
        System.out.println("swap中交换前:");
        System.out.println("a = " + a + " b = " + b);
        int tmp = a;
        a = b;
        b = tmp;
        System.out.println("swap中交换后:");
        System.out.println("a = " + a + " b = " + b);
    }
}
引用数据类型

image-20220908200119221

public class MethodParameter02{
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        B b = new B();
        b.test(arr);
        System.out.println("main中数组:");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}


class B{
    public void test(int[] arr){
        arr[0] = 200;
        System.out.println("test中数组:");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
}

引用类型传递的是地址(也是值,但是值是地址),可以通过形参影响实参

置空时注意是哪一个栈置空,对象指向指控并不影响对象属性。

深刻理解内存图,基本数据类型传递,引用传递

练习

image-20220910181903703

public class MethodExercise02 {
    public static void main(String[] args) {
        Person p = new Person();
        p.name = "Jack";
        p.age = 20;
        MyTools tools = new MyTools();
        Person p2 = tools.copyPerson(p);
        System.out.println("p: " + p.name + " is " 
                        + p.age + " years old.");
        System.out.println("p2: " + p2.name + " is " 
                        + p2.age + " years old.");
        // p 和 p2 是 Person 对象,但是两个对象独立,属性相同
        // 可以通过 输出对象的 hashCode 看对象是否是一个
        System.out.println("p的hashCode: " + p.hashCode());
        System.out.println("p2的hashCode: " + p2.hashCode());
        System.out.println(p == p2);
    }
}

class Person {
    String name;
    int age;
}

class MyTools {
    public Person copyPerson (Person p){
        Person p2 = new Person();
        p2.name = p.name;   // 名字赋值
        p2.age = p.age;     // 年龄赋值
        // 克隆对象
        return p2;
    }
}

递归(recursion)

递归调用机制

public class recursion01 {
    public static void main(String[] args) {
        
        T t1 = new T();
        t1.test(4);
    }
}

class T {

    public void test(int n){
        if(n > 2){
            test(n - 1);
        }
        System.out.println("n = " + n);
    }
}

结果:

image-20220916223150608

image-20220916223906364

加一个else:
public class recursion01 {
    public static void main(String[] args) {
        
        T t1 = new T();
        t1.test(4);
    }
}

class T {

    public void test(int n){
        if(n > 2){
            test(n - 1);
        }
        else{
            System.out.println("n = " + n);
        }
    }
}

输出:

image-20220916224301308

==》每一个栈完整执行方法

public class recursion01 {
    public static void main(String[] args) {
        
        T t1 = new T();
        System.out.println(t1.factorial(5));
    }
}

class T {

    // factorial => 阶乘
    public int factorial(int n){
        if(n == 1){
            return 1;
        }
        else{
            return n * factorial(n - 1);
        }
    }
}

输出

image-20220917011505657

递归细节

  1. 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
  2. 方法的局部变量是独立的,不会相互影响,比如n变量
  3. 如果方法中使用的是引用变量(数组,对象),就会共享该引用类型的数据
  4. 递归必须向推出递归的条件逼近,否则就是无限递归,出现StackOverflowError
  5. 当一个方法执行完毕,或遇到return,就会返回遵循谁调用就将结果返回给谁,同时,当方法执行完毕或者返回时,该方法也就执行完毕
public class RecursionExercise01 {
    public static void main(String[] args) {
        // 桃子问题
        Fib f = new Fib();
        int day = 1;
        int peachNum = f.peach(day);
        if(peachNum != -1){
            System.out.println("第 " + day + " 天有 " + peachNum
            + " 个桃子!");
        }
    }
}

class Fib{

    public int peach(int day){
        if(day == 10){  // 第十天只有一个桃子
            return 1;
        }else if( day >= 1 && day <= 9){
            return ((peach(day + 1) + 1) * 2);
        }else{
            System.out.println("day在1-10");
            return -1;
        }
    }
}
0

评论

博主关闭了所有页面的评论