【JAVA进化论】LV2-1:类&引用变量的简单介绍

一、类的简单介绍、什么是引用变量

前面讲述完基本变量类型,现在说下引用变量类型,这里先简单介绍下java里非常重要的一个概念:

1.1:什么是类?

java是一个面向对象语言,那么什么是对象?类又和对象有什么关系呢?

之前了解了所有的基础类型数据,我们可以用它们来搞个事情,现在,让我们用这些基本类型造只猫。

那么,我们现在需要提炼出来猫所具备的一些属性,比如,每只猫都有自己的生理性别,那么性别就可以是一个属性,每只猫可能还会有一个昵称,每只猫还会有它的年龄,当然,随便什么属性都可以,自己喜欢就好,都可以加进你的设计里,前提是这些属性是客观存在的事实。除了一些属性,猫还会有一些行为,比如吃饭、奔跑、叫、无法归类的迷惑行为等,把属性加上这些行为,一个猫类就被我们抽象出来了:

图1

如上图所示,抽象后的数据结构,被我们称作一个类,类在java中无处不在,类内按照特性分为了两类,上方红色部分,我们称它为类的属性,属性主要用来描述一些客观存在的事实,比如猫确实有年龄,猫确实有生理性别等,而猫会叫,会跑等这些含主观意识构成的特性,我们管它叫类的方法,类方法可以用来描述这个类里所具备的具体功能,比如例子里的猫,具备吃饭的功能,具备跑的功能等,而很多时候,这些功能特性还会依赖自己的属性来决定功能的运行方式,比如猫在奔跑的时候可能会依赖自己的年龄,年龄大的猫奔跑速度可能赶不上年龄小的猫,这个时候奔跑这个功能便会受猫的年龄属性的影响。

这里简单了解下方法在java中的定义方式:类里的方法又叫函数function),它的基本定义结构如下:

图2

上面是一个简单的求两个数之和的方法(函数),它的逻辑是,计算输入的两个参数的和,并将其返回出去。

1.2:什么是对象?

通过对1.1的理解,我们知道了类的基本概念,那么类就跟它的名字一样,属于对一类事物的描述,比如猫,猫是一个种群,因为猫都具备图1中的特性,所以猫这个种群可以用Cat类来描述,但是既然是种群,肯定存在个体差异,比如,你家的猫是母猫,他家的猫是公猫,你家的是白猫,他家的是黑猫,这种个体的差异没有越过类的描述,不管是公还是母,本质上都是一种生理性别(gender),那么如何解决这种细微的个体差异性呢?

这时对象就出来了,我们来看下下面这个图:

图3

如上图所示,利用Cat这个类的信息,对其内部属性赋值,就可以造出各种各样“符合类规则”的猫了,产生的这只猫,就叫做类的对象,每个类都可以产生许多许多个对象,这些对象符合类的基本定义,但是却各不相同。

1.3:利用java实现一个类、认识并理解引用变量

本篇文章旨在简单介绍java类是什么,重点介绍引用变量,主要结合图片理解,可以对类可以有个基本的认识以及更深层次的理解引用变量。

通过前面所有内容的了解,我们利用java代码来实现下Cat:

代码块1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//猫类的定义
public class Cat {

//性别:0雌,1雄
private int gender;
//年龄
private int age;
//毛色:1黑,2白
private int color;
//昵称
private char name;

//构造器:关键方法,用来制造对象,传入的这些属性值得以赋值到对象内部
public Cat(int gender, int age, int color, char name) {
this.gender = gender;
this.age = age;
this.color = color;
this.name = name;
}
//叫
public void cry() {
//猫叫声的实现
System.out.println("喵喵喵~");
}
//吃
public void eat() {
System.out.println("要恰饭的嘛");
}
//无法归类的迷惑行为
public void emm() {
System.out.println("猪肉卷和千层面不存在二选一,我全都要!");
}
public void run() {
if (age > 10) { //假如奔跑速度跟年龄有关,年龄超过10岁,则速度变慢
System.out.println("奔跑速度:10km/h");
} else {
System.out.println("奔跑速度:15km/h");
}
}
}

经过上述代码,我们已经完成了1.1中,有关猫类的抽象。

接下来,我们来完成1.2中的造对象过程,现在新造一个Test类用于测试(注:java所有的程序,都是以一个main方法开始的,这里通过Test类里的main方法来开始测试):

代码块2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {

public static void main(String[] args) {
//下面都是基本类型
int gender = 1;
int age = 5;
int color = 1;
char name = 'A';

//这里将上方赋好值的数据,送入构造器,然后构造器构造出来对应的对象
Cat cat = new Cat(gender, age, color, name);
cat.run(); //利用这个对象,调用它自身的run方法
}
}

例子中通过new构造器来构造一个具体的对象,命名为cat,这个cat是一个变量,这种非基本类型的变量,叫做引用变量,引用变量相比基本类型,较为复杂,它内部其实存储的是一段地址,这段地址指向了具体的对象体,例子里就是通过构造器构造出来的对象本身,而cat.run()就是在利用这个引用变量cat访问具体的对象的run方法,通过代码块1,可以知道在age<=10的时候,输出应该是15km/h,事实上运行一下这段代码确实是这个结果:

1
奔跑速度:15km/h

目前做简单了解就好,后面会仔细讲,这个过程可以用下方流程图简单说明一下:

图4

需要注意的是,与基本变量不同,引用变量不存在默认值,如果一个引用变量不进行赋值操作,那么它的“默认值”是null,即引用变量并没有指向任何对象实体,如果之前有听说过java鼎鼎大名的空指针异常(或称npe异常),那么空指针异常在多数情况下都是因为使用了一个值为null的引用变量去访问某个对象本体导致的。

通过上述的例子会发现,猫的名字是char类型,但是char类型仅能保存一个字符,如果我的猫名字叫“加菲”,对于Cat类,就是一件很棘手的事情了,因为“加菲”是由两个汉字字符组成的词语,那么这时候有没有一种类型可以用来接收它呢?

字符串类型String就是用来做这个的,LV1-2里说过,它并非基本类型,它的声明方式如下:

代码块3
1
2
3
String a; //声明名称为a的String类型变量(由于其非基本类型,因此a属于引用变量,不赋值的情况下默认值为null)
String b = "加菲"; //声明名称为b的String类型变量(初始值为:加菲)
String c = new String("加菲"); //不建议的写法,声明名称为c的String类型变量(初始值为:加菲)

这样,将Cat类改造下,将其内部的name改成String类型:

代码块4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Cat {
private int gender;
private int age;
private int color;
private String name; //改成String类型

public Cat(int gender, int age, int color, String name) { //接收name参数时使用String类型接收
this.gender = gender;
this.age = age;
this.color = color;
this.name = name;
}
...方法省略,参考代码块1...
}

此时的main方法改成如下:

代码块5
1
2
3
4
5
6
7
int gender = 1;
int age = 5;
int color = 1;
String name = "加菲"; //声明一个叫name的字符串,初始化值为”加菲“

Cat cat = new Cat(gender, age, color, name);
cat.run();

由于name也变成了一个引用变量,所以图4就变成了下方的流程:

图5

String为java自带的原生类,而Cat是我们自己定义的类,本质上都是类,未来编写java程序时,会用到很多类似String这样的java现成的类,自己实现一些业务逻辑时,需要创造自己的类,自己的类里也可以使用别的类,类似上述例子中,Cat类就是用了String类,只要是类产生的对象,对应它的变量一定是一个引用变量,引用变量永远是一段访问实际对象时的内存地址,如果一个对象在内存里失去了变量引用,则认为该对象废弃,这时JVM就会将其回收,这就是java的垃圾回收机制,这里不需要知道太多,反正后面都会讲,先了解下即可。