Java 面向对象编程笔记(基础)

面向对象编程(基础)

  • 本人是初学者,跪求各位路过的大佬给点建议,真心想学习进步,先在这谢过各位姥爷了

1. 类与对象

  1. 引入案例

    /*
    张老太养了两只猫猫;一只名字叫小白,今年3岁,白色。还有一只叫叫小花,今年100岁,花色。请编写一个程序,当用户输入小猫的名字时,就显示该猫的民字,年龄,颜色。如果用户输入的小猫名错误,则显示张老太没有这只猫猫。
    */
    // 传统方法解决
    public class object01{
        public static void main(String arr[]){
            String cat1Name = "小白";
            String cat2Name = "小花";
            
           	int cat1Age = 3;
            int cat2Age = 100;
            
            String cat1Color = "Write";
            String cat2Coloe = "many color";
        }
    }
    // 可以做出来,但是始终无法体现猫的行为,效率较低
    
    • 引入类与对象

      public class object02{
          public static void main(String arg[]){
              //	1.new Cat() 创建一只猫
          //	2.Cat cat1 = new Cat(); 把创建的猫赋给 cat1
          Cat cat1 = new Cat();
          cat1.name = "小白";
          cat1.age = 3;
          cat1.color = "白色";
          
          //创建第二只猫
          Cat cat2 = new Cat();
          cat2.name = "小花";
          cat2.age = 100;
          cat2.color = "花色";
              
       	//访问对象的属性
         	System.out.println(cat1.name + cat1.age + cat1.color);
          }
      }
      
      class Cat{
          //属性
          String name;
          int age;
          String color;
      }
      //字符串存放在常量池内,int型数据直接放在堆内
      
  2. 概述

    • 一个程序就是一个世界
  3. 属性/成员变量/字段(field)

    • 属性的定义语法类变量 访问修饰符 属性类型 属性名;
    • 访问修饰符:控制属性的访问范围
    • 有四种访问修饰符 public,proctected,默认,private
    • 注意:属性如果不赋值,有默认值,规则和数组一致
  4. 创建对象

    1. 先声明在创建

      Cat cat;
      cat = new Cat();
      
    2. 直接创建

      Cat cat = new Cat();
      
  5. 访问属性

    • 基本语法:对象名.属性名;

    • 思考题

    • Person p1 = new Person();
      p1.age = 10;
      p1.name = "小明";
      Person p2 = p1;
      //把 p1 赋给了 p2,也可以说是让 p2 指向 p1(内存空间由此可知)
      //即 p2 和 p1 一样都是指向一个内存地址
      //而不是新开辟内存地址再将 p1 的内容装填进去
      System.out.println(p2.age);
      
    • 把 p1 赋给了 p2,也可以说是让 p2 指向 p1(内存空间由此可知)

    • 即 p2 和 p1 一样都是指向一个内存地址

    • 而不是新开辟内存地址再将 p1 的内容装填进去

  6. Java内存的结构分析:

    1. 栈:一般存放基本数据类型(局部变量)
    2. 堆:存放对象(Cat cat,数组等)
    3. 方法区:常量池(常量,比如字符串),类加载信息
    4. Person类信息只加载一次,多次加载无意义

2.成员方法

  1. 引入案例

    • 成员不仅有属性,还有方法(行为)

    • /*
      1.添加一个speak成员方法,输出 我是一个好人
      2.添加cal01成员方法,可以计算从1 + ... + 1000的结果
      3.添加cal02成员方法,该方法可以接受一个数n,计算从1 + .. + n
      4.添加一个getSum成员方法,可以计算两个数的和
      */
      
    • public class Method1{
          public static void main(String arg[]){
              // 创建对象
              Person p1 = new Person();
              p1.speak(); //调用方法,只有调用才会执行
      }
      }
      
      class Person{
          String name; //常量池
          int age; //堆中
          //添加方法 1
          public void speak(){
              System.out.println("我是一个好人");
      	}
          //添加方法 2
          public void cal01(){
              int res = 0;
              for(int i = 0; i < 1001; i++){
                  res = res + i;
      		}
             	System.out.println(res);
      	}
          //添加方法 3 动态版2
          public void cal02(int n){  //调用方法时给方法需要传递参数
              int res = 0;
              for(int i = 0; i < n+1; i++){
                  res += i;
      		}
              System.out.println(res);
          }
          //添加方法 4 类似方法3
      }
      
  2. 内存机制

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

    1. 同一个类中的方法调用:直接调用即可。比如print(参数);
    2. 跨类中的方法A类调用B类方法:需要通过对象名调用。比如 对象名.方法名(参数);
    3. 特别说明:跨类的方法调用和方法的访问修饰符相关。
  4. 方法的参数传递机制

    • public class Method{
          public static void main(String arr[]){
              Person p = new Person();
              p.name = "jack";
              p.age = 10;
              
              b.test200(p);
              System.out.prinln("main 的 p.age = "+ p.age);
              //此时输出10
          }
      }
      
      class Person{
          String name;
          int age;
      }
      class B{
          public void test200(Person){
              p = null;  
              // 这里改变的是传递过来的形参(也可以理解为切断了形参的指针)
              // 也就是说原来的p没有任何改变(也可以理解为原来的指针没有任何改变)
          }
      }
      
    • 案例强化:

      /*
      编写一个方法copyPerson,可以复制一个Person类对象,返回复制的对象。克隆对象。
      注意:要求得到新对象和原来的对象是两个独立的对象,只是他们的属性像同。
      */
      
      public class MethodExercise02{
          public static void main(String arr[]){
              Person p = new Person();
              p.name = "milan";
              p.age = 100;
              Mytools tool = new Mytools();
              tool.copyPerson(p);
              //并且此时p和p2是两个独立的对象,并且属性相同
          }
      }
      
      class Person{
          String name;
          int age;
      }
      
      class Mytools{
          public Person copyPerson(person p){
              Person p2 = new Person(); 
              //new出来的p2,所以p2指向新的空间(独立)
              p2.name = p.name;
              p2.age = p.age;
          }
      }
      
  5. 方法递归调用

    • 打印问题

      public class Recursion01{
          public static void main(String arr[]){
              T t1 = new T();
              t1.test(4);
          }
      }
      
      class T{
          public void test(int n){
              if(n > 2){
                  test(n-1);  //递归打印
              }
              Ststem.out.println("n="+n);
          }
      }
      
    • 阶乘

      public  class Recursion02(int n){
          T t1 = new T();
          t1.factorial(5); //输出120
      }
      
      class T{
          public int factorial(int n){
              if(n == 1) return 1;
              else return factorial(n-1) * n;
          }
      }
      
    • 斐波那契数列

      public class Fibonacci{
          public static void main(String arr[]){
              
          }
      }
      
      class Fib{
          public int Fibo(int n){
              if(0 < n && n < 3){
                  return 1;
              }
              else if(n > 2) return Fibo(n-1) + Fibo(n-2);
              else Ssytem.out.println("输入格式错误!");
      }
      
    • 猴子吃桃子

      /*
      有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个;以后猴子每天都吃其中的一半,然后还多吃一个。当到第10天的时候,想再吃时(此时还没吃),发现桃子只有一个了。问题:最初有多少个桃子?
      */
      
    • 迷宫问题

      1. 二维数组表示迷宫地图;
      2. 元素值为1时表示障碍物,元素值为0时表示有路可以走
      3. 要求:测试回溯
      public class MiGong{
          public static void main(String arr[]){
              //1.创建迷宫地图
              int[][] map = new int[8][7];
              for(int i = 0; i < 7; i++){
                  map[0][i] = 1;
                  map[7][i] = 1;
              }
              for(int i = 0; i < 7; i++){
                  map[i][0] = 1;
                  map[i][6] = 1;
              }
              map[3][1] = 1;
              map[3][2] = 1;
              
              T t1 = new T();
              t1.findWay(map,1,1);//将当前位置传给findWay()方法
          }
      }
      
      class T{
          public boolean findWay(int[][] map, int i, int j){
          if(map[6][5]==2){  //2表示已经走过,并且可以走通
              return true;  //说明已经找到了
          }else{
              if(map[i][j] = 0){  //当前这个位置可以走
                  map[i][j] = 2;
                  //改变搜寻策略会影响最终的路线
                  if(findWay(map, i - 1, j)){  	//上
                      return true;
                  }else if(findWay(map, i, j + 1)){	//右
                      return true;
                  }else if(findWay(map, i + 1, j)){	//下
                      return true;
                  }else if(findWay(map, i, j - 1)){	//左
                      return true;
                  }else{
                      map[i][j] = 3;  //表示该路走不通,标记为3
                      return false;
                  }
              }
          }
      //改变策略
      public boolean findWay2(int[][] map, int i, int j){
          if(map[6][5]==2){  //2表示已经走过,并且可以走通
              return true;  //说明已经找到了
          }else{
              if(map[i][j] = 0){  //当前这个位置可以走
                  map[i][j] = 2;
                  //改变搜寻策略会影响最终的路线
                  if(findWay2(map, i + 1, j)){  	//下
                      return true;
                  }else if(findWay2(map, i, j + 1)){	//右
                      return true;
                  }else if(findWay2(map, i - 1, j)){	//上
                      return true;
                  }else if(findWay2(map, i, j - 1)){	//左
                      return true;
                  }else{
                      map[i][j] = 3;  //表示该路走不通,标记为3
                      return false;
                  }
              }
          }
      }
          }
      
      
    • 汉诺塔

    • 三根柱子,A、B、C,其中A主子上有64个圆盘,按从大到小从底摆放,要将这64根柱子移动到C柱上,且移动过程中不能将较小的盘子放到较大的盘子上将64个盘子简化成5个盘子解决问题

    • 需求:将移动盘子的过程打印出来、将移动的次数记录并打印出来

    • 思考:最少移动多少次即可完成

      
      
    • 八皇后

    • 在8 * 8的国际象棋棋盘上摆放八个皇后,使其任意两个皇后都不能同处与同一行,同一列或同一斜线上,问有多少种摆法。

  6. 方法重载

    • 概述:Java中允许在同一个类中,多个同名方法的存在,但要求形参列表不一致(顺序或者类型),返回类型不同不构成重载。

3.可变参数

  1. 概述:Java允许将同一个类中多个同名同功能参数个数不同的方法,封装成一个方法。

  2. 基本语法:访问修饰符 返回类型 方法名(数据类型…形参名) {}

  3. 快速入门:

    public class VarParameter01{
        public static void main(String arr[]){
            
        }
    }
    
    class HspMethod{
        //可以计算 2 个数的和,3个数的和,等等...
        //可以使用方法重载(麻烦到死)
        //可变参数
        public int sum(int... nums){  
        	// int... 表示接受的是可变参数,类型是int,即可以接收多个int
        	// 使用时可以当作数组使用
            System.out.println("接收的参数个数是"+nums.length);
        }
    }
    
    • 注意:
      1. 可变参数的实参可以是0个或任意多个;
      2. 可变参数的实参可以为数组;
      3. 可变参数的本质就是数组;
      4. 可变参数可以和普通参数类型的参数一起放在形参列表,但必须保证可变参数放在最后;
      5. 一个形参列表中只能出现一个可变参数。

4.作用域(scope)

  1. 注意:

    • 属性和局部变量可以重名,访问时遵循就近原则

      public class VarScopeDetail{
          public static void main(String arr[]){
              Person p1 = new Person();
              p1.say;
          }
      }
      
      class Person{
          String name = "jack";  //局部变量
          
          public void say(){
              String name = "king";  //属性
              System.out.println("say() name = " + name);
              //就近原则,输出 king
          }
      }
      
    • 在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名

    • 属性生命周期长,伴随着对象的创建而创建,伴随着对象的死亡而死亡。局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而死亡。

    • 作用域范围不同:

      1. 全局变量属性:可以被本类使用,或者其他类使用(通过对象调用)
      2. 局部变量:只能在本类中对应的方法中使用
    • 修饰符不同

      1. 全局变量/属性可以加修饰符
      2. 局部变量不能加修饰符

5.构造器/构造方法(constructor)

  1. 需求:前面我们创建人类对象时,都是先把一个对象创建好后,再给他的年龄和姓名赋值,如果现在我们要在船舰对象时,就直接指定这个对象的年龄和姓名,和该怎么做?这时就需要用到构造器。

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

  3. 说明:

    • 构造器的修饰符可以默认
    • 构造器没有返回值
    • 方法名和类名必须一致
    • 参数列表和成员方法一致
    • 构造器的调用由系统完成
    • 如果没有定义构造器,系统会自动给类生成一个无参构造器
    • 一旦定义了自己的构造器,系统定义的构造器将被覆盖
  4. 作用:完成对对象的初始化

  5. 入门:

    • 需求实现:

      public class Constructor01{
          public static void main(String arr[]){
              Person p1 = new Person("Smith",80);
              //自动调用构造方法(已经完成对象的属性的创建和初始化 )
          }
      }
      
      class Peerson{
          String name;
          int age;
          //构造器
          public Person(String pName, int pAge){
          	name = pName;
              age = pAge;
          }
      }
      
  6. 流程分析

    1. 加载Person类信息(Person.class),只会加载一次
    2. 在堆中分配空间(地址)
    3. 完成对象的初始化
      • 3.1 默认初始化 age = 0 name = null
      • 3.2 显式初始化 age = 20 name = “小倩”
    4. 在对象在堆中的地址返回给p(p 是对象名,也可以理解成是对象的引用)

6.this

  1. 问题引入

    class Dog{
        String name;   
        int age;
        public Dog(String name , int age){
            name = name;
            age = age;
    }
        public void info(){
            System.out.println(name+"\t"+age+"\t");
            //输出的是属性,而上面构造器中是给局部变量赋值,故而输出为空
    }
    }
    
  2. 入门

    • Java虚拟机会给每个对象分配 this,代表当前对象。坦白来讲,要明白 this 不是一件简单的事情
    class Dog{
        String name;
        int age;
        public Dog(String name , int age){
            this.name = name;
            this.age = age;
            //this.XXXX 指的是对象的属性
    }
        public void info(){
            System.out.println(name+"\t"+age+"\t");
            //此时就会有值输出了,当前对象的属性得到了赋值
    }
    }
    
    • 每一个对象都有默认的this,并且this指向这个对象本身
    • hashCode():这是一个将一个对象地址转换成10进制数字的方法(特点)
    • 注意:
    public static void main(String arr[]){
        Dog dog1 = new Dog("大壮",3);
        System.out.println("dog1的hashCode=" + dog1.hashCode());
        
        Dog dog2 = new Dog("大黄",2);
        System.out.println("dog2的hashCode=" + dog2.hashCode());
    }
    
    class Dog{
        String name;
        int age;
        
        public Dog(String name, int age){
            this.name = name;
            this.age = age;
            System.out.println("this.hashCode() = "+this.hashCode);
        }
        public info(){
            System.out.println(name+" "+age);
        }
    }
    
  3. 注意:

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

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

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

    • 访问构造器的语法:this(参数列表); 注意只能在 构造器中使用(即只能再构造器中访问另外一个构造器)

      此时这条访问构造器的语句必须放在第一条去执行

      class T{
          public T(){
              this("jack",100);
              System.out.println("T() 构造器");
              //这里去访问 T(String name, int age) 构造器
          	//this("jack",100);  !!!错误
          }
          public T(String name; int age){
              System.out.println("这里是构造器T(String name, int age)");
          }
      }
      
    • this不能在类定义的外部使用,只能再类定义的方法中使用

  • 12
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值