1、数据类型有哪些种类?它们有什么区别?
2、变量赋值的过程发生了什么?
3、对象何时被创建?
数据类型
数据类型分为两种:基本类型和引用类型,其中String、Integer等就是我们常用的引用类型。
浅谈栈和堆
- 因为栈和堆并不是本篇博客的重点,在这里只稍微提及一下今天需要用到的知识点。当我们在Java中如下图声明a和b两个变量时,栈中会生成两个引用。由于a是基本类型int的变量,所以声明a时不创建对象,a仅仅指向栈中8这个值;b是包装类String(引用类型)的变量,所以声明b时,b指向的是栈中的一个地址,通过这个地址电脑才能够找到我们创建的“ok”字符串对象。
- 当我们对两个变量进行赋值操作时,一个对象只把栈中的值赋给另一个对象。所以说当我们对两个引用类型的变量之间进行赋值操作时,系统并不会在堆中自动新建一个对象,而是让它们的地址都指向同一个对象。
对比一下这几种修改参数的方法
- 首先我们需要创建一个Student类
public class Student {
public String name;
public int age;
public Student(){
}
public Student(String name,int age){
this.name=name;
this.age=age;
}
}
- 然后创建一个ChangeDemo类,下面我们尝试用三种方法去修改Student cxd中的age,看看会有什么结果
public class ChangeDemo {
public void change_1(int age){
age=age+1;
}
public void change_2(Student stu){
stu.age=stu.age+1;
}
public void change_3(Student stu){
stu=new Student(stu.name,stu.age+1);
}
public void test(){
//创建学生的初始对象
Student cxd=new Student("cxd",20);
//下面这三行代码分别单独测试,测试某一条时记得把其他两条注释掉!
change_1(cxd.age);
change_2(cxd);
change_3(cxd);
System.out.println(cxd.name+"的年龄是"+cxd.age);
}
public static void main(String[]args){
ChangeDemo cd=new ChangeDemo();
cd.test();
}
}
- 观察三个方法的不同之处,对比它们的运行结果,仔细思考它们运行时分别都发生了什么?
语句解读: - 我们传入方法change_1的参数是cxd.age,在调用这个方法的时候系统已经自动执行了一条
int age=cxd.age;
的语句。这个时候相当于我们已经在栈中声明了一个int类型的变量age,这个age的值等于cxd.age。此时age和cxd.age是互相独立的,修改age并不会影响cxd.age。
- 我们传入change_2的参数是cxd,这是一个Student类的变量,属于引用变量类型。在调用这个方法的时候系统同样已经自动执行了一条
Student stu=cxd;
的语句,这一条语句同样在栈中声明了一个和cxd拥有相同地址的变量stu。注意,因为此时cxd和stu的地址均指向同一个对象,所以此时我们对stu进行修改时,就会修改stu地址指向的那个对象的值。最后我们输出cxd.age,当然就是输出已经被修改之后的值了。
- 方法change_3和方法change_2传入的参数是一样的,所以第一个步骤都是相同的。语句
stu=new Student(stu.name,stu.age+1);
创建了一个新的Student对象,stu被更新为指向这个新对象的地址。此时对新的Student对象进行改变,原来的Student对象仍然不受影响。
- 小总结:当我们使用普通方法进行传参时,我们传递的只是栈中的内容。
String对象何时被创建?
- 我们在任意一个类的主函数下试着运行下面这段代码,观察结果,比较不同,同样的,思考这些过程究竟发生了什么?
public static void main(String[]args){
String a="ab";
String b="ab";
String c="abc";
String d="ab"+"c";
String e=new String("abc");
String f=a+"c";
String g=a+"c";
System.out.println(a==b);
System.out.println(c==d);
System.out.println(c==e);
System.out.println(c==f);
System.out.println(f==g);
}
-
输出如下图所示:
-
在这里先解释一个小概念:我们去比较两个String类是否相等时用到的有符号“==”和方法“.equals()”,前者判断的是两个变量在栈中的地址是不是相同的(也就是比较它们两个是不是指向同一个对象),后者判断的是两个字符串代表的值是否相同。(也就是说两个字符串可能内容相同,但是是两个不同的对象)
-
在刚刚这一串代码中,我们的String c,d,e,f,g表示的都是“abc”,但是在用“==”判断它们是否相等时,却出现了不一样的答案,下面博主来逐一解释。
-
a==b首先我们要明白
String a="ab";
这一条语句执行了什么内容?这条语句的意思是,在声明变量a的时候,先在堆中寻找是否已经有一个现成的“ab”对象,如果没有的话才创建一个“ab”对象;如果有的话,就让a指向已经存在的这个对象。所以说,当我们创建了一个String a="ab"后,再创建String b=“ab"时,变量b就会指向由a创建的这个"ab”。此时我们去判断“a==b”,也就是a和b的地址是否相同,答案当然就是true了。 -
c==d前面一个例子我们讲到,String a==“xxx”是一种特殊的创建对象的方式,这里的c和d使用的都是这种创建对象的方法,所以它们指向的也是同一个对象。
-
c==e当我们使用new方法去创建对象时,一定会在堆中开辟一个新的对象。所以指向new方法创建的对象的变量当然也就不会和任何一个变量相等。
-
c= =f;f= =g这两句的输出也是false,说明f和g也是创建了新的对象。