前言:

  • 引出类与对象(oop) — 为什么需要类与对象(oop)
  • 例:我有两只小狗,有姓名,年龄,性别,怎么完成该操作?
//用变量 
String DogName = "小白"int DogAge = 6char DogSex= ''

String DogName = "小新"int DogAge = 6char DogSex= ''

//用数组
String[] Dog = {"小白","6",""}; //数字类型不明确
String[] Dog = {"小新","6",""}; //数字类型不明确
  • 上面案例中完成了小狗的属性创建,那么现在我想给小狗添加一个爱好怎么办?是不是特别麻烦,如果是100只小狗呢?

类与对象是什么:

  • 看前言已经知道,用变量和数组创建一个猫是多么的麻烦,增加一个属性就需要重复大量代码
  • 类:如猫类 ->  把所有猫的属性和行为提取到该猫类中形成一个类
    • 猫类:是自定义的数据类型,如int就是java提供的数据类型  
  • 对象:如猫类 ->  提供猫类去创建出来的就是对象,猫对象

快速入门:

  • 看下面代码就可知道和原本的变量和数组好处在哪,属性类型明确,添加属性值方便,开发效率高
    public static void main(String[] args) {

        Cat cat1 = new Cat();//创建第一个猫对象
        cat1.name = "小白";//给属性赋值
        cat1.age = 10;
        System.out.println(cat1.name +" "+ cat1.age);//输出属性值

        Cat cat2 = new Cat();//创建第二个猫对象
        cat2.name = "小新";//给属性赋值
        cat2.age = 20;
        System.out.println(cat2.name +" "+ cat2.age);

    }

}
class Cat{//定义一个猫类
    String name;//属性
    int age;
}
  • 类属性的不同叫法和细节:

Class Cat{
  String name; // 可以叫 1.属性 2.成员变量 3.字段    
  int[] age;  // 可以放所有基本数据类型和引用类型
  doeble money;       
}

pring(car.name+" "+car.age...)//直接输出属性,会输出属性默认值
//int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,
//boolean false,String null
  • 对象内存布图:

 类和对象的内存分配机制:

  • java内存结构分析:

    • 栈:一般存放基本数据类型(局部变量)
    • 堆:一般存放对象或数组
    • 方法区:一般存放常量池和类加载信息
  • java创建对象流程简单分析: 

    • 创建对象然后在方法区加载类信息 — (只是加载一次,不会创建一个对象加载一次)
    • 在堆中创建空间,进行默认初始化
    • 把栈地址指向对象
    • 进行初始化如:cat,pag = 10; cat.name = “小白”  

 成员方法:

  • 什么是成员方法?就是在类在写一个方法(方法是基础里的知识),和写一个属性是一样的
  • 为什么需要成员方法?:
    • 循环遍历一个数组 是否需要写代码遍历循环,
    • 在遍历一个数组呢,复制粘贴代码在循环一次?那我要改动遍历代码,所有的复制粘贴代码都要改?
    • 解决问题:所以只需要通过调用成员方法,就可以减少代码的复用 
  • 快速入门:

public static void main(String[] args) {
        Cat cat = new Cat();
        cat.show();//调用方法
    }
}
class Cat{
    String name = "小白";
/*
    public 公共的 -- 作用域(当然还有其它的)
    void -- 表示方法没有返回值
    int -- 表示方法返回值,基本数据类型,引用类型都可以
    return -- 表示把值返回 
    show-- 方法名
    () -- 形参列表,表示可以接收形参
    {} -- 方法体     
*/
 public void show(){
  //方法体
   System.out.println("我叫"+name); 
  } 

//有参返回
public int show2(int i, int n ){ return i+n; } }
  •  方法调用机制:

  • 方法的定义:

访问修饰符 返回数据类型 方法名(形参列表..) {//方法体
            语句;
            return 返回值; //如果是viod就需要该存在了
}
  • 成员方法的下细节:

    • 一个方法最多一个返回值(但是可以有多个返回结果,返回数组形式)
    • 可以返回任意类型,基本数据类引用类型(数组,对象)
    • 如果方法是void,不需要写return,或者只写return(不能用返回值)
    • 返回值类型return必须和返回值统一或者兼容,如:需要返回值是double,return可以返回int,反过来就不可以需要数据类型可以转换  
    • 遵循驼峰命名法
class Dog{
  //1.返回多个结果
   public int[] king(){
      int[] sum = new int[3];
      sum[0] = 1;
      sum[1] = 2;
     return sum; //返回多个结果    
   }
  
  //2.void可以写return,但不能有返回值
   public void king2(){
     pring("加油");
     return;
    
   }

 //3.可以返回兼容的类型
  public double king3(){
     int  i = 99;
     return i ; 
    
   }
      
}
  • 成员方法 – 形参列表细节:

    • 一个方法可以有0个参数,也可以有多个参数有逗号隔开
    • 参数类型可以是任意类型,基本数据类型或引用类型
    • 调用参数方法时,传入的参数一定是相同的类型或兼容的类型
    • 方法定义时的参数叫形参(形式参数),调用方法时传入的叫实参,实参和形参必须统一或兼容
//一个方法可以有0个参数,也可以有多个参数有逗号隔开
    public int show(int num1, int num2){
        return num1+num2;
    }
    //参数类型可以是任意类型,基本数据类型或引用类型
    public int[][] show2(int[][] map){
        int[][] nums = new int[11][11];
        return nums;
    }
  • 成员方法 – 方法体细节:

    • 方法体中不能嵌套方法  
  • 成员方法 – 方法调用细节

    • 同类中可以直接调用同类中的其它方法
    • 在方法中可以通过对象调用其它类中的方法 – 这里注意因为跨类调用还需要考虑访问修饰符
class A{
    public void print(){
        System.out.println("我在同类中的其它方法调用了");
    }
    //同类中可以直接调用其它方法
    public void sayOK(){
        print();
        System.out.println("我调用了print()方法");
    }

    //在方法中可以,通过对象调用其它类方法
    public void m1(){
        System.out.println("A的m1被调用");
        new B().hi();
        System.out.println("A的m1现在执行 ");
    }

}
class B{

    public void hi(){
        System.out.println("我是B类的hi()方法");
    }
}
  •  成员方法 – 基本数据类型传递机制

    • 基本数据类型传递的是值拷贝,形成不会改变实参 

  •  成员方法 – 引用类型传递机制

    • 引用类型传递的是地址 – 会对引用类型改变
    • 如果在方法中改变了传递过去的地址,改变了地址或指空,那么对引用类型不会进行影响  

 

 方法的重载:

  • 什么是重载?-> 同一个类中,多个方法名称一样的方法存在,但是形成列表不一致
  • 重载的好处 -> 如我的方法是显示加法后的结果,那可以是int加int,doblue加int,那么可以通过同一方法名来实现,只需要传递不同的参数
class AA{
    public void show(int i ,int n){
        System.out.println(i+n);
    }
    public void show(int i ,double n){
        System.out.println(i+n);
    }
    public void show(double i ,double n){
        System.out.println(i+n);
    }
    public void show(double i, int n){
       System.out.println(i+n);
    }
   
}
  • 重载细节:

    • 方法名必须相同
    • 形成列表不能一致
    • 可以是任意返回类型(如:可以返回int double void Cat 数组类型 等) 
    //返回形成列表不能一致,返回类型不同也不行
    public void show(double i ,double n){
        System.out.println(i+n);
    }
    public double show(double i ,double n){
        System.out.println(i+n);
    }

 可变参数:

  • 什么是可变参数?就是可以传递零个或多个数
  • 使用可变参数,可以当数组使用
  • 语法:int… sum — 就是int类型的可变参数
public int sum(int... nums){
        int res = 0;
        for (int i = 0; i < nums.length; i++) {
            res += nums[i];
        }
        return res;
    }
  • 可变参数 – 细节:

    • 可变参数实参可以是0个或多个
    • 可变参数的实参可以是数组
    • 可变参数本质就是数组
    • 可以参数可以和普通类型参数一起放在形成列表中,可变参数必须放在普通参数后面
    • 一个形成列表,只能出现一个可变参数
public class Test {
    public static void main(String[] args) {
        AA aa = new AA();
        //可变参数的实参可以是数组
        int[] num = {1,2,3};
        int sum = aa.sum(num);
    }
}
class AA{
    public int sum(int... nums){
        int res = 0;
        for (int i = 0; i < nums.length; i++) {
            res += nums[i];
        }
        return res;
    }
//可以参数可以和普通类型参数一起放在形成列表中,可变参数必须要在普通类型参数后面 public void sum(String name,int... nums){ };
//一个形成列表只能出现一个可变参数 //public void sum(double... num,int... nums){};//错误 }

作用域: 

  • 什么是作用域?就是属性在该类中的使用范围
  • 作用域一般访问:全局变量局部变量
  • 全局变量:在该类中都可以使用
  • 局部变量:只能在自己的一亩三分地使用,在自己的代码块中使用
//快速入门
class AA{
    //该属性在AA类中都可以访问
    String name = "king";  //成员变量/属性/全局变量
    public void show(){ //成员方法
        //该属性只能在show()方法中使用
        char sex = ''; //局部变量
    }
}
  • 作用域细节:

    • 全局变量(属性)有默认值;局部变量没有默认值(定义时必须赋值)
    • 全局变量(属性)和局部变量名字可以重复,访问时就近原则,靠我近访问谁
    • 全局变量(属性)可以使用访问修饰符,局部变量不可以
    • 全局变量(属性)伴随着对象的销毁而销毁,局部变量是代码块的销毁而销毁
      • 通俗易懂版:new一个对象,该对象不销毁全局变量还在,局部变量一般中方法中,如方法结束局部变量就销毁  
class AA{
    //1.属性默认值:String是null
    String name; 
    //2.属性和局部变量名字可以一致,就近原则访问
    int age;
    //3.属性可以使用访问修饰符
    public char sex;
    public void show(){
        //1.局部变量:没有默认值,不写就错
        char sex = '男'; 
        //2.属性和局部变量名字可以一致,就近原则访问
        int age = 18;
    }
}

 构造器:

  •  什么是构造器?完成对新对象的初始化
    • 理解:调用构造器时,对象已存在内存中,调用构造器去完成对象属性的的初始化
    • 在理解:等于AA类中有 String name; 我的操作等于 String name = “小白”; 
  • 语法:【修饰符】类名 (形参列表) {代码块}
class AA{
    String name;
    int age;

   public AA(String name,int age){
       System.out.println("name+age");
       name = name;
       age = age;
   }
}
  • 构造器 – 细节:

    • 可以构造器的重载
    • 控制器没有返回值
    • 控制器名和类名相同
    • 构造器完成对象的初始化,不是创建对象
    • 类中没有定义构造器,系统默认是给一个默认的无参构造器
    • 定义了自定义的构造器后,默认的构造器就会被覆盖,需要重新定义才能使用  

对象创建的流程+构造器版本:

  • 类加载
  • 在堆在分配空间   ==  空对象
  • 对象初始化 – 属性先赋值(默认值先赋值,在到定义值,在到构造器)
  • 栈中接收堆中地址

 this关键字:

  • 什么是this?我直接调用我自己
  • 为什么要使用this?如:构造器中形参为 name 类属性 name 我要name = name怎么办?是不是太含糊不清,谁是谁的name
    • 案例说明什么是,我直接调用我自己:
public class Test {
    public static void main(String[] args) {
        AA aa = new AA("小白",20);
        //1.调用该方法name = null,age = 0
        aa.show();
    }
}
class AA{
    String name;
    int age;
    public AA(String name, int age) {
        //2.因为:这里把name当成了局部变量
        //自己 给 自己 赋值肯定是错误的
        name = name;
        age = age;
        //3.this.name表示当前对象的name属性
        //当前对象是谁?AA aa = new AA("小白",20);
        //所以说是:我自己调用我自己
        this.name = name;
        this.age = age;
    }
    public void show(){
        System.out.println(name+" "+age);
    }
}
  • 深入了解,我自己调用我自己:

    • 每个对象都会有一个hashcode,Java可以通过这个hashcode来识别一个对象 

  • this细节:

    • this关键字可以访问,本类属性,方法,构造器
      • 访问方法语法:this.方法名(参数列表)
      • 访问构造器语法:this(参数列表) – 必须写在构造器中使用,必须在构造器中第一条中,不能递归调用(就是我调用你,你调用我)  
    • this关键字可以区分属性和局部变量
    • this关键字只能在类定义的内部使用,去类外部使用谁知道this是什么
class AA{
    String name;
    int age;
    public AA(String name, int age) {
        //this关键字访问本类构造器
        this("小白");
        //this关键字访问本类属性
        this.name = name;
        this.age = age;
    }

    public AA(String name) {
        String name = "oop";
        //this关键字可以区分属性和局部变量
        this.name = name;
        this.age = age;
    }
    
    public void t1(){
        //this关键字可以访问本类方法
        this.t2();
        System.out.println("我是t1");
    }
    public void t2(){
        System.out.println("我是t2");
    }
}