Java学习 day05_面向对象

②对象和类

1. 引例

  • Java对象的模板——类也是这么描述对象的
    • 属性(外貌特征)
    • 行为(能力特征,能做什么)
    • 得出类的定义
      • 类就是对象的模板
      • 类抽取了同种类型的所有对象属性和行为上的共性
      • 一个类可以描述千千万万个对象

我们简单总结一下,面向对象就是在模仿我们的现实世界

这部分随便看看吧,我觉得很啰嗦

  • 类比客观世界的组成:对象是运行中的Java面向对象程序的基本组成单位,类比客观世界中的个体
  • 类比客观世界个体的描述:对象的属性和行为
  • 类比客观世界的个体的全体描述(模板):抽取对象的共性特征形成类
  • 类抽取出了同种类型的千千万万个对象的属性和行为上的共性(共同特征) ,类就是对象的模板
  • 类和对象的关系
    • 类描述了,同种类型的对象,在属性和行为上的共同特征
    • 但是,类只规定了,有什么样的属性,有什么样的行为,但是,对象属性的取值,是由对象自己决定。一个类可以有千千万万不同的对象
  • 对象与对象的关系
    • 不同类生成的对象,属性和行为往往都具有差异,不是同种对象
    • 相同类生成的对象,属性和行为具有相似性,但是也完全可能不同

2. 类的定义

定义类包括定义类结构本身,和定义类中属性和行为

2.1 定义一个类

类抽取出对象的共性的行为和共有的属性

  • 类的定义我们并不陌生
  • 语法
[各种修饰符] class 类名{

}
  • 一个Java文件中只能定义一个public修饰的类,但是可以定义多个非public类

2.2 定义类的成员

类中用成员变量来描述对象共有的属性
类中用成员方法来描述对象共性的行为

  • 成员变量和成员方法合起来统称为(类的)成员

  • 局部位置:方法或者一些代码块结构当中属于局部位置

  • 成员位置:类体种方法等局部位置外的其他位置

练习

定义学生类
    分析学生类中的属性和行为,根据学生类的属性和行为来定义学生类。
创建学生类对象,给属性赋值,并调用成员方法
  1. 成员变量来表示属性

    • 成员变量:定义在成员位置的变量,而不是方法或局部位置的局部变量
    • 语法
    [访问权限修饰符] 数据类型 成员变量名;
    
  2. 成员方法来表示行为

    • 成员方法:方法都定义在成员位置,表示对象行为的成员方法不能加static
    • 语法
    [访问权限修饰符] 返回值类型 方法名(){
        
    }
    
  3. 创建类的对象

    • 在方法和能够写语句的地方创建对象然后使用该对象,可以认为是初始化一个引用数据类型的过程
    • 语法
    类名 对象名 = new 类名();
    
    • 对象名作为一个标识符字符串,遵循变量名的命名规范,小驼峰式的书写方式
  4. 使用对象获取对象的属性和行为

    • 访问属性
    对象名.成员变量;
    
    • 调用行为(方法)
    对象名.成员方法;
    
  5. 直接输出对象名

    • 直接打印对象名得到的是类的全限定类名 + 十六进制的地址值
   打印对象名
        //com.cskaoyan.javase._0introduction.Student@1540e19d
        //com.cskaoyan.javase._0introduction.Student可以唯一的确定一个类,称之为类的全限定类名
        //@后面跟的是一个十六进制的数,它仍然可以看成是一个地址值
        //这个地方打印对象名实质上是调用了一个方法toString()
        System.out.println(s);

注意事项

  • 类可以嵌套定义叫做内部类,但是现在不要这么做,一个Java文件中定义多个class应该并列而不是包含
  • 一个Java文件中的多个class是同包(文件夹)关系
  • 一个类当中,应该开门见山的定义成员变量,而后再写成员方法
  • 类中没有的属性和行为,对象是不可能有的,类是模板,模板中有才能创建出来
  • 使用new关键字就会创建新的对象,两条new语句创建的对象是完全独立的

3. 引用数据类型的全新理解

我们通过数组内存图引入了引用数据的概念

现在我们已经知道了,引用数据类类型是由栈上的引用和堆上的对象两部分组成

  • 现在请回忆一下,基础语法部分数据类型的概念
  • 思考:
    • 能否用数据类型的概念来统一基本数据类型和引用数据类型呢?

3.1 数据类型的概念

  • 数据类型的概念

    • 一个数据集合和基于这个数据集合的一组操作,比如int,有固定的取值范围,有固定的操作
  • 类的定义中,类包括:

    • 成员变量和成员方法
    • 做一下类比,得到:
      • 数据集合: 类中成员变量的集合
      • 操作集合: 类中成员方法的集合
  • 总结

    • 一个类的定义,实际上就是定义了一种全新的数据类型,是一种自定义的数据类型
    • 这种数据类型,和基本数据类型不同,它是我们自己自定义的数据类型(引用数据类型)

3.2 引用数据类型的不同点

类实际上一种我们自定义的数据类型,里面有什么数据,能做什么操作都是我们自定义的,这种自定义的数据类型就是引用数据类型, 类实际上就是一个引用数据类型
*
引用数据类型和基本数据类型的区别:
我们在使用一个基本数据类型时,由于基本数据类型是Java当中已经定义好的
所以JVM能够正常帮助我们开辟空间,正常给变量赋值

但是引用数据类型(类)是我们自定义的数据类型,jvm是不可能预先知道这个类型的信息的
所以想要它帮助我们创建还需要一个让jvm了解该类信息的过程
这个过程在Java称之为类加载

显然

  • 类加载要在创建对象之前,也就是说创建一个类的对象触发***该类的类加载***

  • 类加载需要把一个类的class(字节码)文件读取到方法区内存中,然后经过一系列操作完成类加载

    • 类加载完毕后,JVM已经获取了该类的类型信息(有什么成员变量,方法等),能够完成创建对象
  • 类和对象的关系,就可以类比于基本数据类型和基本数据类型变量之间的关系

    int a = 1; 
    //类比
    Student s = new Student();
    //
    
    
    
  • 在Student s = new Student()中

    • s是对象名或者称之为引用,我们通过引用访问这个s对象
    • new Student()是指示JVM帮助我们创建引用类型Student的对象

3.3 对象内存图练习

练习:	
	1个对象的内存图,一个对象的基本初始化过程
	3个对象的内存图,其中有两个引用指向同一个对象

一个对象创建过程&类加载
在这里插入图片描述
三个对象创建过程


类加载过程只会执行一次,后面再有对象创建时,不会进行类加载



③局部变量和成员变量

1. 比较的方式

局部变量和成员变量的比较,我们从以下五个方面去比较:

  • 在类中定义的位置不同
  • 在内存中的位置不同
  • 生命周期不同
  • 初始化值不同
  • 作用范围

2. 结论

  • 在类中定义的位置不同
    • 局部变量
      • 方法、方法的形参或者代码块结构等位置
    • 成员变量
      • 类体中的非局部位置
  • 在内存中的位置不同
    • 局部变量
      • 栈上
    • 成员变量
      • 堆中的对象中
  • 生命周期不同
    • 局部变量
      • 随着方法的进出栈而存在而销毁
    • 成员变量
      • 对象创建以后就存在
      • 对象销毁就没了
      • 和对象同生共死,但实际上只要该对象栈上的引用被销毁,对象中的成员变量也就无效了
  • 初始化值不同
    • 局部变量
      • 没有默认的初始化值,需要手动赋值和初始化
    • 成员变量
      • 有默认的初始值
  • 作用范围
    • 局部变量

      • 只在方法范围内生效
    • 成员变量

      • 对象当中,整个类的成员方法都可以使用
      • 在加static的非普通成员方法中,不能使用


④this关键字

1. 引例

class Car {
    //成员变量
    String color;
    double speed;

    //成员方法
    public void run(int speed) {
        System.out.println(color + "的小汽车以" + this.speed + "速度嘟嘟嘟的跑!");
        //this.test("");
    }
   
   // 这个成员方法打印的速度是对象调用run方法时传参过来的int 类型的speed,而非它自身的成员变量speed,如果仍想访问成员变量speed,那必须使用到this
}

2. 就近原则

就近原则最经典的体现,就是在方法中如果存在同名的局部变量和成员变量

那么访问该同名变量,得到的结果

  • 必然是距离访问语句更近的局部变量,而不是同名成员变量
  • 就近原则在Java中非常常见,是Java语言设计者遵守的一个常规协定

3. this关键字

在就近原则的前提下,普通手段是无法访问同名成员变量的,所以引用this关键字实现访问

3.1 引入

  • this关键字(重点)
    • Java当中每个类的成员方法的形参列表中都隐含了一个传参
    • 该传参用this引用接收,this引用指向当前对象
    • 所以this关键字表示当前对象
  • 什么叫当前对象?
    • 创建对象,然后用对象名点调用成员方法
    • 对象名(引用)指向的对象,就是当前对象,就是成员方法中的隐含传参this指向的对象
  • 正是因为成员方法中,有隐含的this传参指向了当前对象
    • 所以可以直接在成员方法中,用this去访问成员变量和调用成员方法
    • 因为是隐式传参,上述访问成员时,this可以省略
    • 但是当成员方法中,有同名局部变量时,由于就近原则
      • 这个时候,如果还想要访问成员变量,就不能省略this关键字
      • 所以,可以用this访问表示成员变量,来和局部变量做区分

3.2 this关键字的作用

  1. 可以在成员方法中区分同名的成员变量和局部变量
  2. 可以在成员方法中去调用别的成员方法(实际上并没有必要写出这个this)
    • static方法和static方法之间可以直接互相调用
    • 非static成员方法之间也可以直接互相调用
    • static方法中想要访问成员方法,必须先创建对象
  3. this很重要的用途是:
    • 用来指示一个变量到底是成员变量还是局部变量
    • 在代码比较复杂的情况下,可以显著增加代码可读性
  4. 未完待续…

4. 总结和注意事项

总结和注意事项

  • this指向当前对象的隐式传参,必须是在普通成员方法中
    • 加static的方法中,没有该this传参
  • 可以在成员方法中打印该this关键字,可以发现和在main方法中打印对象名(引用)结果一致
  • 既然this指向当前对象,那么不同的this指向的对象必然不同


⑤构造方法(constructor)

1. 引例

创建一个教师类,有课程和年龄两个属性,行为是可以上课

  • 思考一下,我们给成员变量赋值的语句,是不是显得冗余?
  • 怎么改进?
  • 对象的属性,能不能"出厂"的时候就设定好呢?

2. 构造方法

构造方法:

在Java程序设计语言中,new创建对象,必须使用构造器

  • 构造方法是一种特殊方法,用来创建初始化对象(实例)
  • 作用是给对象的成员变量赋值

语法:

public 类名(参数){
	//方法体
}

注意:

  • 构造方法不是普通方法,它没有返回值,并且方法名是首字母大写的(因为类名是首字母大写)

  • new对象的时候,JVM自动去调用这个方法,构造方法无法通过普通方法的调用方式调用

    • JVM会在创建对象的最后一步去调用构造方法,保证构造器能够给成员变量正确赋值
    • “永远可以相信构造器”
  • Java默认提供无参构造方法,但是如果你提供了一个有参的构造方法,那么就没有默认的无参构造了

    • 建议写代码时,顺手提供无参构造方法
      • 有些框架可能依赖无参构造创建对象
      • 继承中,子类对象初始化可能依赖父类无参构造
  • 构造方法可以重载

  • 构造方法中可以使用this关键字,去访问对象的成员,也可以去调用已有的构造方法

    public Teacher(String course, int age, int height) {
          this(course, age);
          this.height = height;
      }
    
    • 如果使用this调用别的构造方法,那么这条语句必须在该构造方法的第一行
      每new创建一个对象,都会调用一次构造方法,而类加载仅有一次

三种给成员变量赋值方法的顺序

  • 赋默认初值–>显式初值(类中自带的成员变量赋值)–>构造器赋值


    给成员变量赋值过程

赋值顺序的文字描述
1,第一步永远是先默认初始化,成员变量具有默认值

2,去找到new对象使用的构造方法

3,考虑该构造方法的第一行有没有this去调用别的构造方法
a,如果没有,也不会立刻执行构造方法,而是先去执行成员变量的显式赋值(如果有的话)

b,如果有this构造器,立刻跳到this构造器,然后也不会立刻执行this构造器, 而是先去执行成员变量的显式赋值(如果有的话)
成员变量的显式赋值执行结束后,再执行this构造方法

this构造方法执行结束后,不会再执行显式赋值,而是立刻回去执行new对象调用的那个构造方法


作业

已知有3个班级(一班,二班,三班)分别有3人,2人,5人
键盘录入每个班级的学生的成绩
请使用二维数组存储数据
并计算:
每个班级的平均成绩,每个班级中的最高成绩和最低成绩,并输出
这道题主要看二维数组的定义方式,如何实现每个二维数组的长度是不一样的

public class Work1 {
    public static void main(String[] args) {
        //格式二动态初始化二维数组
        double[][] arr = new double[3][];
        //分别初始化其中的一维数组
        arr[0] = new double[3];
        arr[1] = new double[2];
        arr[2] = new double[5];
        //键盘录入成绩
        //遍历数组
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.println("请输入" + (i + 1) + "班第" + (j + 1) + "个同学的成绩:");
                //录入成绩
                arr[i][j] = sc.nextDouble();
            }
        }
        //System.out.println(Arrays.deepToString(arr));
        //double[][] arr2 = {{20, 30, 10}, {100, 90}, {10, 20, 30, 40, 50}};
        getClassAverage(arr);
        getClassMaxScore(arr);
        getClassMinScore(arr);
    }

    //计算每个班级的平均分,实际是计算每个一维数组的平均值
    public static void getClassAverage(double[][] arr) {
        //遍历二维数组
        for (int i = 0; i < arr.length; i++) {
            double sum = 0;
            for (int j = 0; j < arr[i].length; j++) {
                sum += arr[i][j];
            }
            System.out.println((i + 1) + "班的平均分是:" + (sum / arr[i].length));
        }
    }

    public static void getClassMaxScore(double[][] arr) {
        //逐个遍历,然后求最大值
        for (int i = 0; i < arr.length; i++) {
            //设每个一维数组的第一个元素是最大值
            double max = arr[i][0];
            for (int j = 0; j < arr[i].length; j++) {
                if (arr[i][j] > max) {
                    max = arr[i][j];
                }
            }
            System.out.println((i + 1) + "班的最高分是:" + max);

        }
    }

    public static void getClassMinScore(double[][] arr) {
        //逐个遍历,然后求最小值
        for (int i = 0; i < arr.length; i++) {
            //设每个一维数组的第一个元素是最小值
            double min = arr[i][0];
            for (int j = 0; j < arr[i].length; j++) {
                if (arr[i][j] < min) {
                    min = arr[i][j];
                }
            }
            System.out.println((i + 1) + "班的最低分是:" + min);

        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值