Java语言学习笔记06-面向对象基础篇

一、类与对象

一、引入需求

当我们需要处理一种输出,这种输出在结构上有相似之处,但具体的值又经常变化。

例如,我们想要记录一个人的一些特点和行为。

假如我们用定义变量的办法一个个定义变量,会很麻烦。

A人比如是卷发,会唱歌,B人比如是直发,会跳舞;

那我们就需要定义至少两个变量:头发类型和才艺类型。

随着需求的增加,定义变量的个数会剧增,而且如果要进行修改,也很不方便,要从茫茫变量海中找到对应人的对应变量做出对应的修改。

管理起来毫无章法可言。

如果我们尝试用已有的知识解决问题呢?

若单独变量解决:不利于数据的管理,多个变量之间可能体现的是同一个整体的信息,相当于把一只猫的信息拆解了。

而若用数组来处理:(1)数据类型体现不出来(2)只能通过下标获取信息,造成变量名字和内容的对应关系不明确。

因此,Java语言抽象出类与对象的概念,方便我们处理上述的情况。

二、类与对象介绍

1、对象

世界上有很多事物,我们可以将其看作一个对象。

每一个对象包含很多属性(可以理解为特点)和方法(可以理解为行为)。

例如一只具体的小狗,其毛发和颜色就是它的属性,而其跑和叫的行为就是它所拥有的方法。

2、类

将一类对象所拥有的属性和方法提取出来,就成了一个类。

例如,一只特定的小猫是一个对象,但我们可以从中抽象出所有猫都具有的共同属性和方法来得到“猫类”。

类是一种数据类型

举例如下:

class Cat{
    String name;//属性,也叫成员变量 或 字段
    int age;
    String color;
}

以上代码就是一个猫类的定义。

而类对应的对象的创建和一维数组的创建类似,也有声明的同时创建和先声明再创建两种方式:

Cat cat1 = new Cat();//同时声明与创建
cat1.age = 18;//通过 对象名.属性 的方式来调用对象的成员变量

或

Cat cat2;
cat2 = new Cat();//先声明,再创建。但是需要注意,只有new了才会在内存中真正开辟空间。

需要注意的是,在以上例子中,cat1只是指向内存空间的对象名,或者说对象引用,而真正的对象是那块内存空间。

就好比老王只是个名字,隔壁那个邻居才是真的人。

3、对象在内存中的存在形式(重要,待补充!)

4、属性

属性也叫成员变量,或者字段(field)。

属性是类的一个组成部分,一般是基本数据类型,也可以是引用类型如对象或数组

class Cat{
    String name;//属性,也叫成员变量 或 字段
    int age;
    String color;
}

属性的定义语法和变量是一样的。具体来说如下:

访问修饰符 属性类型 属性名;

属性前面可以加上访问修饰符,这在后面的笔记中会展开。

简单来说,访问修饰符就是控制属性的可访问范围,有public、protected、default、private四种,代表了该属性能够被访问到的范围。

属性的定义类型可以是任何类型,包括基本数据类型和引用类型。

属性在没有被赋值的情况下也有默认值,规则同数组。

访问属性的方式为:

对象名.属性名

5、类和对象的内存分配机制(重点)

Person p1 = new Person();
p1.age = 10
p1.name = "";
Person p2 = p1;//p1赋给了p2,或p2指向了p1
System.out.println(p2.age);

在以上的例子中,为了方便讲解,我们以#号表示不同行数的代码,如用#1代表第一行代码。

当JVM执行#1时,我们知道new会在内存中开辟一片新的空间

此时,#1语句会向内存发出加载Person类信息的指令,这条指令只会在第一次new一个Person类的时候被执行唯一一次,其中包含Person类的属性信息和方法信息。

此时,new方法会在 中按照 类的定义 为p1分配空间,由于此时还未给p1的属性赋值,因此堆空间中p1的属性全为默认值。分配空间之后,将该空间的 地址 返回给 栈 里面的p1。

接下来执行#2,通过p1找到堆中内存空间的地址,再从堆中找到存放age的空间,将其赋值为10。

接下来执行#3,因为"小明"是字符串常量,对于常量会 在方法区的常量池 里面开辟空间存储常量本身和一个地址,这个地址会返回给堆中存放name的空间。

也就是说,属性对于常量的存储,是存储了 “常量结构” 在常量池中的地址。这个所谓的常量结构是我自己编的一个名词,并不是术语。常量结构=常量本身+常量地址。

执行#4,将p1所指向的(堆)地址赋值给p2。

总结一下:

栈:一般存放基本数据类型(局部变量)

堆:存放对象(Cat cat,数组等)

方法区:常量池(常量,如字符串),类加载信息。

三、成员方法

1、基本介绍

上面提到,类中除了属性以外,还可以有一些行为。此时我们就需要定义一些成员方法(简称方法)。

一个快速入门案例:

class Person{
	String name;
	int age;
	public void speak(){
		System.out.println("xxx");
	}
	public void cal02(int n){
		...
	}
	public int getSum(int num1, int num2){
		int res = num1 + num2;
		return res;//返回res的值
	}
}

以上述例子中的speak()方法为例子,介绍一下成员方法。

方法和属性类似,都拥有访问修饰符。

speak方法前的访问修饰符public表示该方法是公开的。

void表示该方法没有返回值(与之对应的,下面的getSum方法的返回值类型为int)。

speak是方法名,()是形参列表,可以指定传入形参的数据类型和量(如getSum方法所示)。

{}中的是方法体,也就是方法要执行的代码。

2、方法定义

public 返回数据类型 方法名(形参列表){//方法体
	语句;
	return 返回值;
}
//return语句不是必须的,但若返回数据类型不是void则必须要有。

3、方法使用

使用方法是为了方便我们进行复用,而且可以封装细节。

具体使用方法如下:

Person p1 = new Person();
p1.speak();//调用方法
int returnRes = p1.getSum(10, 20);

调用方法的时候,会去对象所对应的类的定义中寻找相应方法的定义。

方法的调用机制待补充!

方法使用的细节:
  1. 修饰符的作用是控制方法的使用范围,可选,有四种,后面会展开。如果不写则是默认访问。

  2. 一个方法最多返回一个返回值。若要返回多个同类型值可以考虑返回数组。注意return的类型和返回数据类型要一致或者相互兼容。

  3. 返回类型可以是任意类型,包括基本类型和引用类型。

  4. 方法名遵守驼峰命名法,并且最好见名知义,开发中则按照规范来。

  5. 参数列表可以有0个或多个参数,中间用逗号隔开。方法定义时的参数叫形式参数,简称形参;方法调用时的参数称为实际参数,简称实参。

  6. 注意方法内可以调用别的方法,但不能再定义方法,即方法不能嵌套定义。

方法调用的细节:
  1. 同一个类中方法调用:直接调用即可。即,假如在类的定义中用到方法,直接调用就好。

  2. 跨类中A类调用B类方法:需要通过对象名调用,即需要先创建一个B类对象。

  3. 跨类方法调用与访问修饰符有关系,后面再细说。

方法传参机制:
  1. 对于基本数据类型默认是按值传递,相当于拷贝了一个备份(类似c语言),实参将值复制传给形参之后形参自己在方法内部操作,不会影响到实参。

  2. 对于引用类型,默认是引用传递,即按地址传递,这样形参的变化也会影响到实参。

4、方法的递归调用

递归就是方法总结调用自己,每次调用时传入不同的变量。

类似c语言中计算斐波那契数列函数那样。

重要规则:

1、执行一个方法时就会创建一个新的受保护的独立空间(栈空间),相当于函数压入执行栈中。

2、方法的局部变量是独立的,不会相互影响

3、如果方法中使用的是引用类型变量如数组就会共享该引用类型的数据

4、递归必须向退出递归的条件逼近,否则就是无限递归,会造成栈溢出死机。

5、当一个方法执行完毕或者遇到return就会返回。遵循“谁调用就将结果返还给谁”的原则,同时当方法执行完毕或者返回时,该方法也就执行完了。

5、方法重载(OverLoad)

Java语言允许一个类中有多个同名的方法存在,但要求形参列表不一致

重载的好处是:减轻了起名和记名的麻烦。

重载的细节:

  1. 方法名必须相同

  2. 形参列表中形参类型/个数/顺序/至少有一样不同,参数名则无要求,即int a1, int a2和int n1, int n2算是重复定义而不是重载(因为参数名是任意的)

  3. 返回类型也无要求,即void和int的返回类型,若形参列表没有上述差别,则依然算是重复定义而不是重载

  4. 如果有两个重载方法,除了一个形参类型之外都相同,第一个的类型可以兼容第二个,那么也可以编译通过,使用时若遇到低精度的默认用第二个,因为不必自动类型转换就可以执行了,JVM也会“偷懒”

6、可变参数

Java允许将同一个类中多个同名同功能但参数个数不同的方法封装成一个方法。

基本语法:

访问修饰符 返回类型 方法名(数据类型... 形参名){
}

//例子:
public int sum(int... nums){

}
//int... 表示接受的是可变参数,类型是int,即可以接收多个int(0-多)
//使用可变参数时可以当做数组来使用,即nums可以当做数组

使用的细节:

  1. 可变参数的实参可以是数组

  2. 可变参数的本质就是数组

  3. 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后

  4. 一个形参列表只能有一个可变参数

7、作用域

在Java编程中,主要涉及到的变量就是属性(成员变量)和局部变量。

其中,局部变量一般指的是在成员方法中定义的变量。

而与之对应的属性(即成员变量),我们也可以称之为全局变量。

之所以如此称呼,是因为两者的作用域不一样。

所谓作用域,就是变量所能被使用的范围。超出作用域之外,这个变量就失去了效力,无法被使用了。

作为全局变量,属性可以在整个类体内被使用。

而作为局部变量,则只能在定义它的代码块中被使用(也就是在定义它的一对大括号{}之间使用)

全局变量和局部变量还有一个重要的区别是,全局变量有默认值,但局部变量没有。因此,局部变量必须先赋值后使用。

使用细节:

  1. 属性(全局变量)和局部变量可以重名,访问时遵循就近原则。

  2. 在同一个作用域中,例如同一个成员方法中,则两个局部变量不能重名。

  3. 属性生命周期较长,在对象存续期间都存在;局部变量生命周期较短,只有执行到它的代码块的时候才会创建,执行完就会死亡,即在一次方法调用过程中存续。

  4. 全局变量可以加修饰符,局部变量不可以加修饰符。

  5. 全局变量可以被本类使用或被其他类使用(通过对象调用)

    局部变量则只能在本类对应方法中使用。

8、构造方法(构造器)

构造方法又叫构造器,是类的一种特殊的方法,它的主要作用是完成对新对象的属性的初始化。

基本语法:

修饰符 方法名(形参列表){
	方法体;
}

说明:
(1)构造器的修饰符可以默认
(2)构造器没有返回值,也没有返回类型
(3)方法名和类名字必须一样
(4)参数列表和成员方法规则相同
(5)构造器的调用是由系统完成的,不能自己去调用!
(6)调用构造器的时候对象已经存在了,构造器只是对于初始化而言

入门案例:

Person p1 = new Person("smith", 80);
相当于创建对象的同时就指定其属性的值。
后面部分即为已经定义过构造器的类,系统会自动调用Person类中定义了的构造器。

使用细节:

  1. 一个类可以定义多个构造器,即构造器重载(因为构造器本质也是一个方法)

  2. 构造器不会创建对象!

  3. 若程序员没有定义构造方法则系统会给类自动生成一个默认无参构造方法,也叫默认构造方法,如Person(){},但一般不会显示出来。

  4. 一旦定义了自己的构造器,默认的构造器就被覆盖了,就不能再使用默认的无参构造器了,除非再显式地定义一下如:Person(){}(我们生成对象的时候new Person()其实就是调用了这个默认构造器)

对象创建的流程分析,待补充!

堆中的才是真正的对象,对象名只是对象引用!

1、加载Person类信息(Person.class),只会加载一次

2、再堆中分配空间(地址)

3、完成对象初始化(先默认初始化,再显式初始化,最后再进行构造器初始化)

9、this

引入目的:

有的时候,我们希望在构造器里面,让传入的形参和类中已有的属性同名,这样方便我们辨识。

然而,若直接将形参改为属性名,会发现其实我们是在构造器这个方法之中创造了一个新的局部变量,只是和属性同名而已。

而根据上述的作用域理论,这个形参的作用域只是构造器内部,对它进行的修改并不会影响到属性。

因此,JVM引入this来指代当前对象。

例如,this.name代表当前对象的属性。

如此一来,我们就能完成诸如:

this.name = name;

这样的操作了,等号左边代表该对象的属性,等号右边代表构造器传进来的形参。

this相当于是对象在堆的存储空间中的一片存储了本对象地址(指向本对象)的空间。

哪个对象调用,this就代表哪个对象。

使用细节:

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

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

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

4、访问构造器语法:this(参数列表);注意只能在构造器中使用(即只能在构造器中访问另一个构造器且此时该语句必须是构造器中的第一条语句)

5、this不能在类定义的外部使用,只能在类定义的方法中使用

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值