在Java中,万物皆对象!
比如定义一个学生类
public class Student {
private int id;
private String name;
private int age;
public Student() {
// TODO Auto-generated constructor stub
super();
}
public Student(int id,String name,int age){
super();
this.id=id;
this.name=name;
this.age=age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
然后就可以创建一个Student对象
Student stu=new Student(1, "A", 11);
细分之后:
1. 右面的“ new Student ”,是以Student类为模板的,在堆空间里创建一个Student对象;
2. 末尾的“ (1, “A”, 11) ”代表着:在对象创建之后,立即调用Student类的构造函数,对新生成的对象进行初始化,并赋值。(如果没构造函数,Java会有一个默认的构造函数的);
3. 左面的“ Student stu ” 创建了一个Student类引用变量,即可以用来指向Student对象的对象引用;
4. “ = ” 操作符使该对象引用变量指向刚才创建的那个Student对象。
Student stu;
stu=new Student(1, "A", 11);
有两个实体:一个是对象引用变量,一个是对象本身。
在java中,都是通过引用来操纵对象的,这也是两者的区别。
对象和引用的区别:
关联性:
1. 当对象的引用变量指向对象时,两者就互相联系起来,改变引用的属性,就会改变对象的属性;
2. 如果同一个对象被多个引用变量引用的话,则这些引用变量将共同影响这个对象本身;
3. 在java中,都是通过引用来操纵对象的。
差异性:
1. 一个对象可以被不同的引用变量来操纵,同时一个引用变量也可以指向不同的对象,但是同一时刻下只能指向一个对象。
2. 从存储空间上来看,对象和引用也是相互独立的,对象一般存储在堆中,而引用存储在堆栈中(存储速度而更快)。
对于Java传参来说,Java只有一种参数传递方式:那就是按值传递,即Java中传递任何东西都是传值。如果传入的参数属于基本数据类型,将得到此基本数据类型的一份拷贝;如果是传递的参数属于引用数据类型,将得到该引用的拷贝。
基本数据类型和引用数据类型的区别
每个变量都代表一个存储值的内存位置。声明一个变量时,就是在告诉编译器这个变量可以存放什么类型的值。对基本类型变量来说,对应内存所存储的值是基本类型值。对引用类型变量来说,对应内存所存储的值是一个引用,是其所引用对象的存储地址。
eg1:基本数据类型传参
public static void TestRefOne(){
int a=10;
System.out.println("start: "+a);
ChangeData(a);
System.out.println("end: "+a);
}
private static void ChangeData(int a) {
System.out.println("ChangeData start: "+a);
a=99;
System.out.println("ChangeData end: "+a);
}
结果:int型变量a在ChangeData函数外部始终未改变
start: 10
ChangeData start: 10
ChangeData end: 99
end: 10
eg2:引用数据类型传参
public static void TestRefTwo(){
Student stu1=new Student(1, "A", 11);
System.out.println(stu1.toString());
ChangeStudent(stu1);
System.out.println(stu1.toString());
}
private static void ChangeStudent(Student stu) {
stu.setAge(22);
}
结果:ChangeStudent函数传入的参数是对Student对象的一个引用,所以在ChangeStudent函数内部通过set方法改变stu的值,将会影响到外部的stu1,因为两者都是引用同一个Student对象。
Student [id=1, name=A, age=11]
Student [id=1, name=A, age=22]
引入全局静态变量sstu
private static Student sstu=null;
public static void TestRefTwo(){
Student stu1=new Student(1, "A", 11);
SetStaticStudent(stu1);
System.out.println(stu1.toString());
ChangeStudent(stu1);
System.out.println(stu1.toString());
SetStaticStudent(stu1);
}
private static void SetStaticStudent(Student stu) {
if(sstu==null){
sstu=stu;
System.out.println("已赋值给静态变量: "+sstu.toString());
}
else{
System.out.println("使用原有的静态变量: "+sstu.toString());
}
}
private static void ChangeStudent(Student stu) {
stu.setAge(22);
}
结果:SetStaticStudent函数第一次将Student对象的引用赋值给sstu,外部的stu1引用变量对Student对象进行了修改,sstu获取到的Student对象也是被修改过后的Student对象。
已赋值给静态变量: Student [id=1, name=A, age=11]
Student [id=1, name=A, age=11]
Student [id=1, name=A, age=22]
使用原有的静态变量: Student [id=1, name=A, age=22]
eg3:List中的对象存放方式
public static void TestObjectRefList(){
Student stu1=new Student(1, "A", 11);
Student stu2=new Student(2, "S", 22);
Student stu3=new Student(3, "D", 33);
List<Student> stulist=new ArrayList<Student>();
stulist.add(stu1);
stulist.add(stu2);
stulist.add(stu3);
System.out.println(stulist.toString());
ChangeStudentList(stulist);
System.out.println(stu1.toString());
System.out.println(stu2.toString());
System.out.println(stu3.toString());
System.out.println(stulist.toString());
}
private static void ChangeStudentList(List<Student> stulist) {
for (Student student : stulist) {
student.setAge(99);
}
}
结果:List是中存放的对象数据,都是引用数据类型
[Student [id=1, name=A, age=11], Student [id=2, name=S, age=22], Student [id=3, name=D, age=33]]
Student [id=1, name=A, age=99]
Student [id=2, name=S, age=99]
Student [id=3, name=D, age=99]
[Student [id=1, name=A, age=99], Student [id=2, name=S, age=99], Student [id=3, name=D, age=99]]