1.1 类与对象
1.1.1 类与对象的关系
在面向对象中,类和对象是最基本、最重要的组成单元。类实际上是表示一个客观世界某类群体的一些基本特征抽象。对象就是表示一个个具体的东西。例如,在显示生活中,人就可以表示一个类,因为人本省属于一种广义的概念,并不是一个具体的。而某一个具体的人,就可以称为对象,可以通过各种信息完整的描述这个具体的人,如这个人的姓名、年龄、性别等信息,这些信息在面向对象的概念中就称为属性;当然人是可以吃饭、睡觉的,这些人的行为在类中就称为方法。也就是说如果要使用一个类,就一定有产生对象, 每个对象之间是靠各个属性的不同来进行区分的,而每个对象所具备的操作就是类中规定红啊的方法。类与对象的关系如图:
1.1.2 类的定义
类是由属性和方法组成的。属性中定义类一个个的具体信息,实际上一个属性就是一个变量,而方法是一些操作的行为,但是在程序设计中,定义类也是要按照具体的语法要求完成的,语法如下:
class 类名称{
数据类型 属性;
public 返回值的数据类型 方法名称(参数1, 参数2){
程序语句;
return 表达式;
}
}
下面根据以上的格式定义一个Person类:
class Person{
String name;
int age;
public void tell(){
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
在上面程序中,Person类定义了name和age两个属性,分别表示人的姓名和年龄,然后定义一个tell方法,此方法的功能就是打印这两个属性的内容。
此处的方法并没有加上static关键字,这是因为此时定义的方法将由对象调用,而不像之前那样与主方法定义在一个类中且由主方法直接调用。
类的定义可以用图表示出来:
1.第一层表示类的名称,类的名称要求开头是字母大写。
2.第二层表示属性的的定义,按照“访问权限 属性名称: 属性类型”的格式定义,在本类中因为声明属性处没有写任何的访问权限,所以前面暂时不加任何的符号。
3.第三层表示类中方法的定义,按照“访问权限 方法名称():方法返回值”的格式定义,在本来中方法的声明处加上了public(此为访问权限,表示任何地方都可以访问),所以使用“+”表示。另外,如果方法中有传递参数,则方法定义格式为“访问权限 方法名称(参数名称:参数类型,参数名称:参数类型,…):方法返回值”。
1.1.3 对象的创建及使用
在上面已经创建好了一个Person类,要想使用一个类则必须有对象。对象的创建格式:
类名 对象名称 = null;
对象名称 = new 类名();
用以上格式产生对象分为声明对象和实例化对象两步。
当然可以直接通过类名 对象名称 = new 类名();
创建具体范例:
class ClassDemo01{
public static void main(String[] args) {
Person p = new Person();
}
}
以上程序在主方法中实例化了一个Person对象,对象名为p。与前面的数组开辟空间一样,对象的实例化也是要划分堆、栈空间的,具体的内存分配如图:
所有的对象名称都在栈内存中保存,而对象的具体内容则保存在对应的堆内存之中,必须使用new关键字才能开辟堆内存空间,此时,因为p对象刚刚被实例化,所以对象中的属性内容都是默认值,字符串的默认值为null,整数的默认值为0。
访问对象中的属性或方法:
访问属性:对象名称.属性名
方位方法:对象名称.方法名()
为对象的属性设置内容,同时调用tell方法把内容输出:
class ClassDemo03{
public static void main(String[] args) {
Person p = new Person();
p.name = "张三";
p.age = 12;
p.tell();
}
}
运行结果:
姓名:张三,年龄:12
属性赋值完成之后的内存如图:
对象使用前必须实例化。
1.1.4 创建多个对象
创建两个对象:
class ClassDemo04{
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "张三";
p1.age = 12;
p1.tell();
Person p2 = new Person();
p2.name = "李四";
p2.age = 13;
p2.tell();
}
}
运行结果:
姓名:张三,年龄:12
姓名:李四,年龄:13
程序分别实例化了两个Person对象,那么也就一味着p1和p2对象分别指向各自的堆内存空间,如图:
类属于引用数据类型,而且从数组的使用上也可以发现,引用数据类型就是指一段堆内存空间可以同时被多个栈内存指向。
引用传递的简单范例:
class ClassDemo05{
public static void main(String[] args) {
Person p1 = null;
Person p2 = null;
p1 = new Person();
p2 = p1;
p1.name = "张三";
p1.age = 12;
p2.age = 13;
p1.tell();
p2.tell();
}
}
运行结果:
姓名:张三,年龄:13
姓名:张三,年龄:13
两个对象的输出内容是一样的,实际上所谓的引用传递,就是将一个堆内存空间的使用权给多个栈内存空间,每个栈内存空间都可以修改堆内存的内容,内存如图:
从图中可以发现内存空间的堆、栈指向的变化,程序最后由per2将age的值修改为13,所以最终结果per1中的age属性值也是13。
class ClassDemo06{
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
p1.name = "张三";
p1.age = 12;
p2.name = "李四";
p2.age = 13;
p2 = p1;
p1.tell();
p2.tell();
}
}
运行结果:
姓名:张三,年龄:12
姓名:张三,年龄:12
内存变化图:
关于垃圾空间的释放:
Java本身提供垃圾收集机制(Garbage Collection,GC),会不定期地释放不用的内存空间,只要对象不使用了,就会等待GC释放空间。
一个栈内存空间只能指向一个堆内存空间,如果要想再指向其他的堆内存空间,则必须先断开已有的指向才能分配新的指向。