Java之路:对象的声明和使用

一、对象的声明

下面定义了由类产生对象的基本形式:

类名 对象名 = new 类名();

创建属于某类的对象,需要通过下面两个步骤实现:

⑴ 声明指向“由类所创建的对象”的变量。
⑵ 利用new创建新的对象,并指派给先前所创建的变量。

class Person {	定义一个Person类
	private String name;
	private int age;
	public void talk(); 
}
Person p = new Person();	
// 也可以用下面这个方法
Person p1;		// 先声明Person类对象p1
p1 = new Person();	// 再用new关键字实例化Person的对象p1

对象只有在实例化之后才能被使用,而实例化对象的关键字就是new。

对象实例化过程如下:
在这里插入图片描述
从图中可以看出,当语句执行到Person p1的时候,只是在“栈内存”中声明了一个Person对象p1的引用,但是这个时候p1并没有在“堆内存”中开辟空间。

对象的“引用”本质上就是一个对象在堆内存的地址,所不同的是,在Java中,用户无法向C/C++那样直接操作这个地址。

本质上,“new Person()”就是使用new关键字,来调用构造方法Person(),创建一个真实的对象,并把这个对象在“堆内存”中的占据的内存首地址赋予p1,这时p1才能称为一个实例化的对象。

二、对象的使用

如果要访问对象里的某个成员变量或方法,可以通过下面的语法来实现:

对象名称.属性名     //访问属性
对象名称.方法名()     //访问方法

例如,想访问Person类中的name和age属性,可用如下方法来访问:

p1.name;   //访问Person类中的name属性
p1.age;    //访问Person类中的age属性

因此若想将Person类的对象p中的属性name赋值为“张三”,年龄赋值为25,则可采用下面的写法:

p1.name = "张三" ;
p1.age = 25 ;

如果想调用Person中的talk()方法,可以采用下面的写法:

p1.talk();   //调用Person类中的talk()方法

三、匿名对象

匿名对象是指就是没有名字的对象。
实际上,根据前面的分析,对于一个对象实例化的操作来讲,对象真正有用的部分是在堆内存里面,而栈内存只是保存了一个对象的引用名称(严格来讲是对象在堆内存的地址)。
所以,所谓的匿名对象就是指,只开辟了堆内存空间,而没有栈内存指向的对象。

public class NoNameObject {
	public void say() {
      System.out.println("面朝大海,春暖花开!");
    }
    public static void main(String[]args) {
      new NoNameObject().say();	// 这是匿名对象,没有被其他对象所引用
    }
}

【结果】
在这里插入图片描述
由于“new NoNameObject()”创建的是匿名对象,所以就用“NoNameObject()”整体来作为新构造匿名对象的引用,它访问类中的方法,就如同普通对象一下,使用点操作符(.):

NoNameObject().say();

匿名对象有如下两个特点:

⑴ 匿名对象是没有被其他对象所引用,即没有栈内存指向
⑵ 由于匿名对象没有栈内存指向,所以其只能使用一次,之后就变成无法找寻的垃圾对象,故此会被垃圾回收器收回。


当创建一个对象后,Java虚拟机(JVM)就会给这个对象分配一个自身的引用——this。由于this是和对象本身相关联的,所以this只能在类中的非静态方法中使用。
静态属性及静态方法属于类,它们与具体的对象无关,所以静态属性及静态方法是没有this的。

public class StaticThis {
	static int i;
	public static void init() {
		this.i = 10;	// 错误,this只能在非静态方法中使用
	}
	public static int f() {
		init();
		i++;
		return i;
	}
	public void print() {
		System.out.println(this.f());	// 虽然这样访问静态方法不会报错,但是不推荐使用
		System.out.println(StaticThis.f());	// 因为静态方法与静态属性是属于类的,所以直接用类名访问比较好
	}
	public static void main(String[] args) {
		StaticThis st = new StaticThis();
		st.print();
	}
}

同一个类定义下的不同对象,每个对象都有自己的this,虽然都叫this,但指向的对象不同。

四、栈内存和堆内存的区别

1、栈

在Java中,栈(stack)是由编译器自动分配和释放的一块内存区域,主要用于存放一些基本类型(如int、 float等)的变量、指令代码、常量及对象句柄(也就是对象的引用地址)。

栈内存的操作方式类似于数据结构中的栈(仅在表尾进行插入或删除操作的线性表)。

栈的优势在于,它的存取速度比较快,仅次于寄存器,栈中的数据还可以共享。
缺点表现在,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。

2、堆

堆(heap)是一个程序运行动态分配的内存区域

在Java中,构建对象时所需要的内存从堆中分配。 这些对象通过new指令“显式”建立,放弃分配方式类似于数据结构中的链表。

堆内存在使用完毕后,是由垃圾回收(Garbage Collection,简称GC)器“隐式”回收的。 在这一点上,是和C/C++是有显著不同的,在C/C++中,堆内存的分配和回收都是显式的,均由用户负责,如果用户申请了堆内存,而在使用后忘记释放,则会产生“内存溢出”问题——可用内存存在,而其他用户却无法使用。

堆的优势是在于动态地分配内存大小,可以“按需分配”,其生存期也不必事先告诉编译器,在使用完毕后,Java的垃圾收集器会自动收走这些不再使用的内存块。
缺点为,由于要在运行时才动态分配内存,相比于栈内存,它的存取速度较慢。

猜你喜欢

转载自blog.csdn.net/qq_43555323/article/details/84780166