Java教程
Java标识符与关键字
Java变量
Java数据类型
Java运算符
Java控制语句
Java方法
Java面向对象
Java对象的创建和使用
Java封装
Java中static和this
Java继承
Java方法覆盖和多态
Java super
Java基础练习题

Java实例变量是一个引用

在以上内容学习的过程当中,其实大家已经接触过实例变量是引用的情况,不知道吧!例如在Student学生类当中有一个属性“String name;”,这个属性/实例变量name描述的是学生的姓名,name变量的数据类型是String类型,String类型不属于基本数据类型的范畴,也就是说String类型属于引用数据类型,换句话说String类型应该对应一个String.class文件才对,String是一个类,和我们自己定义的类没什么区别,是这样吗?一起来看看JDK的java源代码:

图9-25:jdk java源代码位置

图9-26:String类源代码位置

图9-27:String类源代码

通过查看源代码得知,其实String是一个class,和我们定义的类没有区别,它和基本数据类型还是不一样的(int i = 10,i变量是基本数据类型,i变量中存储的就是10),也就是说String name = “zhangsan”,实际上name变量中存储的并不是”zhangsan”这个字符串,因为name是一个引用,那name中必然存储的是”zhangsan”字符串对象的内存地址。因为之前我们说过引用的概念,什么是引用:引用就是一个变量,只不过该变量中存储的是java对象的内存地址。也就是说,以前所讲内容中使用内存图描述字符串的时候都是有偏差的。我们来修正一下,请看代码:

public class Student {
	int no;
	String name;
	int age;
	boolean sex;
	public Student(int _no,String _name,int _age,boolean _sex){
		no = _no;
		name = _name;
		age = _age;
		sex = _sex;
	}
}
public class StudentTest {
	public static void main(String[] args) {
		Student s1 = new Student(110 , "zhangsan" , 20 , true);
		System.out.println("学号:" + s1.no);
		System.out.println("姓名:" + s1.name);
		System.out.println("年龄:" + s1.age);
		System.out.println("性别:" + (s1.sex ? "男" : "女"));
	}
}

以上程序的运行结果请看下图:

图9-28:运行结果

将以上内存结构图画出来,请看:

图9-29:修正字符串对象的内存

通过上图可以看到,Student对象当中的name这个“属性/实例变量”是一个引用,保存的不是”zhangsan”字符串,而是字符串对象的内存地址。(按照实际来说,字符串”zhangsan”是在方法区的字符串常量池当中,这个后期再继续进行修正)。接下来,我们再来看看当属性是其他类型引用的时候,请看代码:

public class Date {
	int year; 
	int month;
	int day; 
	public Date(){
	}
	public Date(int year1 , int month1 , int day1){
		year = year1;
		month = month1;
		day = day1;
	}
}
public class Vip {
	int id;
	String name;
	Date birth;
	public Vip(){
	}
	public Vip(int _id,String _name,Date _birth){
		id = _id;
		name = _name;
		birth = _birth;
	}
}
public class VipTest {
	public static void main(String[] args) {
		Date d = new Date(1983 , 5 , 6);
		Vip v = new Vip(123 , "jack" , d);
		System.out.println("编号=" + v.id);
		System.out.println("姓名=" + v.name);
		System.out.println("生日=" + v.birth.year + "年" + v.birth.month + "月" + v.birth.day + "日");
	}
}

运行结果如下图所示:

图9-30:运行结果

以上程序main方法的内存结构图如下所示:

图9-31:Date d = new Date(1983 , 5 , 6);

图9-32:Vip v = new Vip(123 , "jack" , d);

通过以上内容的学习大家掌握当对象的属性是一个引用的时候内存图是怎样的了吗?其实只要记住一点,任何“引用”当中存储一定是对象的内存地址,“引用”不一定只是以局部变量的形式存在,例如以上程序,其中Vip类当中的birth属性就是一个“引用”,它是一个实例变量。当一个对象的属性是引用的时候应该如何访问这个引用所指向的对象呢?这里其实有一个规律,大家记住就行:类当中有什么就可以“.”什么,例如:Vip类中有birth属性,那么就可以v.birth,那么v.birth是Date类型,Date类当中有year属性,那么就可以v.birth.year,你懂了吗?