基础复习第六天 面向对象(一) 类和对象

本文详细介绍了面向对象编程的基本概念,包括面向过程与面向对象的区别、类和对象的定义及其关系。通过桌球游戏的例子展示了面向过程和面向对象的不同思维方式。接着讨论了面向对象的优缺点,强调了其在维护、复用和扩展方面的优势。文章还深入探讨了类的成员变量和方法,以及对象的创建和内存解析,提供了成员变量和局部变量的比较,并介绍了可变参数、方法重载和对象数组等重要概念。
摘要由CSDN通过智能技术生成

面向对象和面向过程的思想概述

什么是面向过程?什么又是面向对象?

面向过程——步骤化

  • 面向过程就是分析出实现需求所需要的步骤,通过函数(方法)一步一步实现这些步骤,接着依次调用即可

面向对象——行为化(概念相对抽象,可结合下面的例子理解)

  • 面向对象是把整个需求按照特点、功能划分,将这些存在共性的部分封装成类(类实例化后才是对象),创建了对象不是为了完成某一个步骤,而是描述某个事物在解决问题的步骤中的行为

能举个例子谈谈你对面向过程和面向对象的理解吗?

例如我们设计一个桌球游戏(略过开球,只考虑中间过程)

A:面向过程方式思考:

把下述的步骤通过函数一步一步实现,这个需求就完成了。(只为演示概念,不细究逻辑问题)。

① palyer1 击球 —— ② 实现画面击球效果 —— ③ 判断是否进球及有效 —— ④ palyer2击球

⑤ 实现画面击球效果 —— ⑥ 判断是否进球及有效 —— ⑦ 返回步骤 1—— ⑧ 输出游戏结果

B:面向对象方式思考:

经过观察我们可以看到,其实在上面的流程中存在很多共性的地方,所以我们将这些共性部分全集中起来,做成一个通用的结构

  1. 玩家系统:包括 palyer1 和 palyer2

  1. 击球效果系统:负责展示给用户游戏时的画面

  1. 规则系统:判断是否犯规,输赢等

我们将繁琐的步骤,通过行为、功能,模块化,这就是面向对象,我们甚至可以利用该程序,分别快速实现8球和斯诺克的不同游戏(只需要修改规则、地图和球色即可,玩家系统,击球效果系统都是一致的)

面向过程和面向对象的优缺点

A:面向过程

优点:性能上它是优于面向对象的,因为类在调用的时候需要实例化,开销过大。

缺点:不易维护、复用、扩展

用途:单片机、嵌入式开发、Linux/Unix等对性能要求较高的地方

B:面向对象

优点:易维护、易复用、易扩展,由于面向对象有封装继承多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护

缺点:一般来说性能比面向过程低

面向对象的两个要素:类和对象

什么是类?

  • :是一类具有相同特性的事物的抽象描述,是一组相关属性行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。

现实中,描述一类事物:

  • 属性:就是该事物的状态信息。

  • 行为:就是该事物能够做什么。

举例:小猫。

属性:名字、体重、年龄、颜色。 行为:走、跑、叫。

什么是对象?

  • 对象:是一类事物的具体体现。对象是类的一个实例(对象并不是找个女朋友),必然具备该类事物的属性行为

现实中,一类事物的一个实例:一只小猫 。

举例:一只小猫。

属性:tom、5kg、2 years、yellow。 行为:溜墙根走、蹦跶的跑、喵喵叫。

类与对象的关系。

  • 类是对一类事物的描述,是抽象的

  • 对象是一类事物的实例,是具体的

  • 类是对象的模板,对象是类的实体

类的定义和对象的创建

事物与类的对比

现实世界的一类事物:

属性:事物的状态信息。 行为:事物能够做什么。

Java中用class描述事物也是如此:

成员变量:对应事物的属性 成员方法:对应事物的行为

类的定义格式:

public class ClassName{
//成员变量
//成员方法
}
  • 定义类:就是定义类的成员,包括成员变量成员方法

  • 成员变量:和以前定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外

  • 成员方法:和以前写的main方法格式类似。只不过功能和形式更丰富了。在类中,方法外。

类的定义格式举例:

public class Person {
      //成员变量
      String name;//姓名
    int age;//年龄
    boolean isMarried;
    
    public void walk(){
        System.out.println("人走路...");
    }
    public String display(){
        return "名字是:" + name + ",年龄是:" + age + ",Married:" + isMarried;
    }
}

对象的创建

创建对象:

new 类名();//也称为匿名对象
//给创建的对象命名
//或者说,把创建的对象用一个引用数据类型的变量保存起来
类名 对象名 = new 类名();

那么,对象名中存储的是什么呢?答:对象在内存中的内存地址。

class Student{
    
}
public class TestStudent{
    //Java程序的入口
    public static void main(String[] args){
        System.out.println(new Student());//Student@7852e922

        Student stu = new Student();
        System.out.println(stu);//Student@4e25154f
        
        int[] arr = new int[5];
        System.out.println(arr);//[I@70dea4e
    }
}
//Student和TestStudent没有位置要求,谁在上面谁在下面都可以
//但是如果TestStudent类的main中使用了Student类,那么要求编译时,这个Student已经写好了,不写是不行的
//如果两个类都在一个.java源文件中,只能有一个类是public关键字修饰的

对象的内存解析

类中成员变量的使用

成员变量的分类

实例变量:没有static关键字修饰的变量,也叫对象属性,属于某个对象的,通过对象来使用

类变量:有static修饰关键字修饰的变量,也叫类变量,属于整个类的,不是属于某个实例

成员变量的声明

 【修饰符】 class 类名{
    【修饰符】 数据类型  属性名;    //属性有默认值
    【修饰符】 数据类型  属性名 = 值; //属性有初始值
}

说明:属性的类型可以是Java的任意类型,包括基本数据类型、引用数据类型(类、接口、数组等)

如何在该类外面访问该类的成员变量?

  1. 静态成员变量(类变量)的访问方式:

  1. 类名.静态成员变量名   //推荐

  1. 对象名.静态成员变量名  //不推荐

  1. 实例成员变量(实例变量)的访问方式:

  1. 对象名.实例变量名  //只有这一种访问方式

例如:

public class TestChinese {
    public static void main(String[] args) {
        //类名.静态成员变量
        System.out.println(Chinese.country);
        //错误,普通成员变量必须通过对象.进行访问
        // System.out.println(Chinese.name);
        
        Chinese c1 = new Chinese();
        //对象名.普通成员变量
        System.out.println(c1.name);
        //静态的成员变量也可以通过对象.进行访问
        //对象名.普通成员变量
        System.out.println(c1.country);
        System.out.println(c1.gender);
    }
}
class Chinese{
    static String country;
    String name;
    char gender = '男';
}

成员变量的特点

    • 成员变量都有默认初始化值

数据类型分类

默认初始化值

基本数据类型(4种)

整型(byte,short,int,long)

0

浮点型(float,double)

0.0

字符型(char)

'\u0000'

布尔型(boolean)

false

引用数据类型(3种)

数组,类,接口

null

    • 类变量的值是所有对象共享的,而实例变量的值是每个对象独立的

类中成员方法的使用

    • 方法的概念

方法也叫函数,是一个独立功能的定义,是一个类中最基本的功能单元。

把一个功能封装为方法的目的是,可以实现代码重用,从而简少代码量。

    • 使用方法的原则

  • 必须先声明后使用

类,变量,方法等都要先声明后使用

  • 不调用不执行,调用一次执行一次。

    • 成员方法的分类

成员方法分为两类:

实例方法:没有static修饰的方法,必须通过实例对象来调用。

静态方法:有static修饰的方法,也叫类方法,可以直接由类名来调用。

    • 成员方法的声明

  1. 方法声明的位置必须在类中方法外(方法中不能再声明方法,但可以调用方法。)

  1. 语法格式:

【修饰符】 返回值类型 方法名(【参数列表:参数类型1 参数名1,参数类型2 参数名, ...... 】){
        方法体;
        【return 返回值;】
}
  • 修饰符: 修饰符后面一一介绍,例如:public,static等都是修饰符

  • 返回值类型: 表示方法运行的结果的数据类型,方法执行后将结果返回到调用者

  • 基本数据类型

  • 引用数据类型

  • 无返回值类型:void

  • 方法名:给方法起一个名字,见名知意,能准确代表该方法功能的名字。遵循标识符的命名规则和规范。

  • 参数列表:方法内部需要用到其他方法中的数据,需要通过参数传递的形式将数据传递过来,可以是基本数据类型、引用数据类型、也可以没有参数,什么都不写

  • 方法体:特定功能代码

  • return:结束方法,并将方法的结果返回去,

  • 如果返回值类型不是void,方法体中必须保证一定有(return 返回值;)语句,并且要求该返回值结果的类型与声明的返回值类型一致或兼容。

  • 如果返回值类型为void时,return 后面不用跟返回值(return;),甚至也可以没有return语句。

  • return语句后面就不能再写其他代码了,否则会报错:Unreachable code

声明位置示例:

类{
    方法1(){
        
    }
    方法2(){
        
    }
}

错误示例:

类{
    方法1(){
        方法2(){  //位置错误
        
           }
    }
}
    • 如何在该类外面访问该类的成员方法?

  1. 实例方法:

对象名.方法名(实参列表);//只能通过这一种方式调用实例方法。

  1. 静态方法:

类名.类方法(【实参列表】)  //推荐
对象名.类方法(【实参列表】) //不推荐

总结:

  • 形参:在定义方法时方法名后面括号中声明的变量称为形式参数(简称形参)即形参出现在方法定义时。

  • 实参:调用方法时方法名后面括号中的使用的值/变量/表达式称为实际参数(简称实参)即实参出现在方法调用时。

总结:

(1)调用时,需要传“实参”,实参的个数、类型、顺序顺序要与形参列表一一对应

如果方法没有形参,就不需要也不能传实参。

(2)调用时,如果方法有返回值,可以接受或处理返回值结果,当然也可以不接收,那么此时返回值就丢失了。

如果方法的返回值类型是void,不需要也不能接收和处理返回值结果。

    • 方法调用及内存分析

方法不调用不执行,调用一次执行一次,每次调用会在栈中有一个入栈动作,即给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值,当方法执行结束后,会释放该内存,称为出栈,如果方法有返回值,就会把结果返回调用处,如果没有返回值,就直接结束,回到调用处继续执行下一条指令。

栈结构:先进后出,后进先出。

示例一:

public class TestCount {
    public static void main(String[] args) {
        int a = 4;
        int b = 2;
        int m = CountTools.max(a, b));
    }
}
class CountTools{
    static int max(int a, int b) {
        return a > b ? a : b;
    }
}

示例二:

public class TestCircle {
    public static void main(String[] args) {
        Circle c1 = new Circle();
        c1.radius = 1.2;
        int area1 = c1.area();
        
        Circle c2 = new Circle();
        c2.radius = 2.5;
        int area2 = c2.area();
    }
}
class Circle{
    double radius;
    public double area() {
        return Math.PI * radius * radius;
    }
}
    • 方法的参数传递机制

方法的参数传递机制:实参给形参赋值

  • 方法的形参是基本数据类型时,形参值的改变不会影响实参;

  • 方法的形参是引用数据类型时,形参地址值的改变不会影响实参,但是形参地址值里面的数据的改变会影响实参,例如,修改数组元素的值,或修改对象的属性值。

public class MethodTest {
    //方法的形参是基本数据类型时,形参值的改变不会影响实参
//    public static void swap(int a, int b) {
//        int temp = a;
//        a = b;
//        b = temp;
//    }

    public static void main(String[] args) {
//        int x = 1;
//        int y = 2;
//        System.out.println("调用前:" + "x:" + x + "y:" + y);
//        swap(x, y);//调用完之后,x与y的值不变
//        System.out.println("调用后:" + "x:" + x + "y:" + y);
//方法的形参是引用数据类型时,形参地址值的改变不会影响实参,但是形参地址值里面的数据的改变会影响实参,例如,修改数组元素的值,或修改对象的属性值。
        MyData m = new MyData();
        m.num = 1;
        System.out.println("调用前:" + m.num);
        change(m);//调用完之后,m对象的num属性值就变为2
        System.out.println("调用前:" + m.num);
    }

    public static void change(MyData my) {
        my.num *= 2;
    }
}

class MyData {
    int num;
}

怎么在本类中访问本类的成员变量和成员方法

  1. 在实例方法中:可以直接使用成员变量和成员方法,不需要通过“对象名."和"类名."

  1. 在静态方法中:只能直接调用静态成员变量和静态成员方法;非静态成员方法只能通过"对象名.方法名(实参列表)",非静态成员变量只能通过"对象名.属性名"调用。

/**
 * 在本类中访问本类的成员变量和成员方法:
 * 1.在实例方法中:可以直接使用成员变量和成员方法,不需要通过“对象名."和"类名."
 * 2.在静态方法中:
 * 只能直接调用静态成员变量和静态成员方法;非静态成员方法只能通过"对象名.方法名(实参列表)",非静态成员变量只能通过"对象名.属性名"调用。
 */
class ClassTest1 {
    /**
     * 变量的使用应该注意什么?
     * 2.1先声明后使用
     * 如果没有声明,会报“找不到符号”错误
     * 2.2在使用之前必须初始化
     *如果没有初始化,会报“未初始化”错误
     * 2.3变量有作用域
     * 如果超过作用域,也会报“找不到符号”错误
     * 2.4在同一个作用域中不能重名
     */
    int age;
    static int number;//static关键字修饰的变量是静态成员变量

    public void eat() {
        age = 0;
        number = 1;
        run();
        water();
    }

    public void water() {
        age = 1;
        number = 5;
        run();
        eat();
    }

    public static void run() {
        //编译报错:Non-static field 'age' cannot be referenced from a static context
        //非静态字段'age'不能从静态上下文中引用
        //age = 0;//实例成员变量
        number = 0;//静态成员变量
        //编译报错:Non-static method 'eat()' cannot be referenced from a static context
        //非静态方法eat()不能从静态上下文中引用
       // eat();//非静态方法
        jump();//静态方法
        System.out.println("你在跑步吗?");
        ClassTest1 a = new ClassTest1();
        a.eat();
        a.age = 0;
    }

    public static void jump() {
        System.out.println("你在跳吗?");
        //编译报错:Non-static method 'eat()' cannot be referenced from a static context
        // eat();//非静态方法eat()不能从静态上下文中引用
        //编译报错:Non-static field 'age' cannot be referenced from a static context
        //age = 0;//编译失败
        number = 1;
    }

}

成员变量和局部变量的区别

变量的分类
  • 成员变量

  • 静态变量(有static关键字修饰的变量)

  • 实例变量(没有static关键字修饰的变量)

  • 局部变量

相同点
  1. 定义变量的格式:数据类型 变量名 = 变量值;

  1. 先声明,后使用

  1. 变量都有其对应的作用域

不同点(6种)
  1. 声明位置和方式不同

(1)静态变量:在类中方法外,并且有static关键字修饰的变量

(2)实例变量:在类中方法外,没有static关键字修饰的变量

(3)局部变量:在方法体{}中或方法的形参列表、代码块中、构造器形参、构造器内

  1. 在内存中存储的位置不同

(1)静态变量:方法区

(2)实例变量:堆

(3)局部变量:栈

  1. 生命周期不同

(1)静态变量:和类的生命周期一样,因为它的值是该类所有对象共享的,早于对象的创建而存在。(2)实例变量:和对象的生命周期一样,随着对象的创建而存在,随着对象被GC回收而消亡, 而且每一个对象的实例变量是独立的。

(3)局部变量:和方法调用的生命周期一样,每一次方法被调用而存在,随着方法执行的结束而消亡, 而且每一次方法调用都是独立。

  1. 作用域不同

(1)静态变量和实例变量:不谈作用域在本类中,唯一的限制,静态方法或静态代码块中不能直接使用非静态的,其他都可以直接使用。在其他类中,能不能使用看修饰符(public,protected,private等)(2)局部变量:有作用域出了作用域就不能使用,不能使用权限修饰符修饰。

  1. 修饰符的不同

(1)静态变量:很多public,protected,private,final,volatile等,一定有的是static

(2)实例变量:public,protected,private,final,volatile,transient等,一定没有的是static

(3)局部变量:final,不能使用权限修饰符修饰。

权限修饰符(4种):public、protected、缺省、private

常量修饰符final:修饰的变量是常量,其值不能修改。

volatile:和多线程有关

transient:是否序列化,和IO有关

  1. 默认值

(1)静态变量:有默认值

(2)实例变量:有默认值

(3)局部变量:没有默认值,必须初始化后才能使用。其中的形参比较特殊,靠实参给它初始化。

可变参数的使用

JDK1.5之后,如果我们定义一个方法时,此时某个形参的类型可以确定,但是形参的个数不确定,那么我们可以使用可变参数。

格式:

【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型... 形参名){  }

可变参数的使用要求:

  • 一个方法最多只能有一个可变参数。

  • 如果一个方法包含可变参数,那么可变参数必须是形参列表的最后一个。

【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型[] 形参名){  }

只是后面这种定义,在调用时必须传递数组,而前者更灵活,既可以传递数组,又可以直接传递数组的元素,这样更灵活了。

方法的重载

  • 方法的重载:指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关。

  • 参数列表:①数据类型不同②参数个数不同③数据类型顺序不同。

  • 重载方法调用:JVM通过方法的参数列表,调用不同的方法。

对象数组

数组是用来存储一组数据的容器,一组基本数据类型的数据可以用数组装,那么一组对象也可以使用数组来装。

即数组的元素可以是基本数据类型,也可以是引用数据类型。

当元素是引用数据类型时,我们称为对象数组。

注意:对象数组,首先要创建数组对象本身,即确定数组的长度,然后再创建每一个元素对象,如果不创建,数组的元素的默认值就是null,所以很容易出现空指针异常NullPointerException。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值