目录
一、初识面向对象
创建类 -> 实例化对象 -> 完成具体的程序
主方法中对象的声明只是在栈中开辟了一块空间,我们不能真正的使用它,实例化对象在内存的对空间开辟了一块空间,完成了对象相关信息的初始化。声明对象和实例化对象是在内存空间中两块不同的空间完成的。
Java程序是运行在JVM虚拟机之上的,JVM可以理解为Java程序和操作系统之间的桥梁,JVM的存在才能真正的实现平台无关性。java的内存分配管理机制也是基于JVM实现的。
栈主要用来保存局部变量的值,堆用来存放动态产生的数据,例如new出来的实例化的对象,无论是通过基本数据类型声明的变量,还是通过引用类型声明的,他们都是可以出现在栈空间中的,只不过基本数据类型的变量在栈里面直接保存对应的值,引用类型的变量在栈中保存一个只是一个指向堆里面的具体空间的地址,由这个地址我们可以找到该实例在堆空间中的具体对象信息。
初始java内存管理之堆和栈
Java程序是运行在JVM上的,JVM是Java程序和操作系统之间的桥梁,而Java内存分配也都是基于JVM中进行的。
java程序运行过程中会涉及到的两大重要内存区域-堆和栈。
栈:每个方法(Method)在执行时,都会创建一个栈帧,用于存储局部变量表、操作数、动态链接、方法出口信息等。
需要注意,栈中所存储,多用于保存局部信息的值,譬如:方法体中的基本数据类型定义的变量、对象的引用(也称为对象实例)等。当局部作用范围结束时,栈内信息立即自动释放。
当存储内容是由基本数据类型(byte、short、int、long、float、double、Boolean)声明的局部变量时,在栈中存储的是它们对应的时具体数值。
当存储的是局部得对象的引用(定义在方法体中的引用类型的变量),存储的是具体对象在堆中的地址。当然,如果对象的引用没有指向具体的空间,则是null。
堆:用来存放动态产生的数据,比如new出来的对象。当对象使用结束,并确定已无实例引用指向堆空间时。JVM才会依据相关垃圾回收机制进行资源回收,完成堆内资源释放,也就是说,并不是方法结束,方法内涉及到的堆空间就会立即释放,这也是与栈管理不同的地方。
此时,需要注意,创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类拥有各自的成员变量,存储在堆中的不同位置,但是同一个类不同实例的之间共享该类的方法,并不是每创建一个对象就把成员方法复制一次。
二、构造方法
- 构造方法与类同名且没有返回值
- 构造方法的语句格式
- 只能在对象实例化的时候进行调用,与new一起进行调用,不能通过对象名、类名等其他形式调用
- 当没有指定构造方法时,系统会自动添加无参的构造方法
- 当指定构造方法,无论是有参、无参的构造方法,都不会自动添加无参的构造方法
- 一个类中可以有多个构造方法
- 普通方法不能调用构造方法,只能结合对象实例化操作调用构造函数,不能通过方法名访问
- 可以在构造方法中,通过this调用本类中的另一个构造方法,但是,调用动作必须置于方法中的第一行。
-
可以通过this调用本类中带参或者无参构造方法,调用带参构造方法时,需要按顺序传入设定的参数。
-
在一个构造方法内只能调用一个构造方法。
this关键字
- 类的方法中访问成员属性时无须使用 this ,但如果方法里存在局部变量和成员属性同名,但程序又需要在该方法里访问成员属性时,则必须使用 this 进行调用。
- 大部分时候,类的成员方法访问同类中其他成员方法时,this关键字可加可不加,效果相同
- 调用重载的构造方法
Cat.java
public class Cat {
String name;
int month;
public Cat(){
System.out.println("我是无参构造");
}
public Cat(String name){
this();
this.name = name;
System.out.println("我是单参构造");
}
public Cat(String name, int month){
this(name);
this.month = month;
System.out.println("我是双参构造");
}
public void call(){
run(this); // 在方法调用时,作为参数传递,谁调用了call,谁就是this,与run()功能一样
run(); // 是this.run()的简写
}
public Cat call(String name){
this.name = name;
// 在方法调用时,作为返回值传递,若调用后赋值给一个变量,则那个变量与调用call的对象指向同一个内存空间。
return this;
}
public void run(Cat one){
System.out.println("我是带参的,昵称为" + one.name + "的小猫快跑");
}
public void run(){
System.out.println("我是无参的run,昵称为" + this.name + "的小猫快跑");
}
public void create(){
// 类的普通函数,只能结合对象实例化操作调用构造函数,不能通过方法名访问
Cat new_one = new Cat("团子", 30); // 会调用构造函数
System.out.println("我是create,我定义了一个Cat类型的对象,昵称为" + new_one.name + "的小猫快跑");
}
}
CatTest.java
public class CatTest {
public static void main(String[] args){
Cat one, two, three;
System.out.println("==========无参实例化one============");
one = new Cat();
System.out.println("==========单参实例化two============");
two = new Cat("花花");
System.out.println("=========双参实例化three===========");
three = new Cat("花花", 2);
System.out.println("======================");
three.call();
System.out.println("==========one初始化调用的无参构造,故其成员属性均是默认值============");
System.out.println(one.name);
// 因为call返回的是this指针,可以理解为将当前对象的地址赋给了one_copy,即他们指向同一块内存空间
Cat one_copy = one.call("凡凡");
System.out.println("=======因为call返回的是this指针,one_copy 与 one指向同一块内存===============");
System.out.println("one的地址: " + one.hashCode() + ", one_copy的地址: " + one_copy.hashCode() );
System.out.println("=======one_copy 与 one指向同一块内存一个的修改另一个必然改变=================");
System.out.println("one的名字: " + one.name + ", one_copy的名字: " + one_copy.name);
// 因为one_copy 与 one 指向同一块内存,故一方的修改会影响另一个
one_copy.name = "小水";
System.out.println(one.name + " " + one_copy.name);
System.out.println("========类的普通函数,只能结合对象实例化操作调用构造函数,不能通过方法名访问==============");
one.create(); // 因为create内部实例化了对象,所以会调用构造函数
}
}
输出
==========无参实例化one============
我是无参构造
==========单参实例化two============
我是无参构造
我是单参构造
=========双参实例化three===========
我是无参构造
我是单参构造
我是双参构造
======================
我是带参的,昵称为花花的小猫快跑
我是无参的run,昵称为花花的小猫快跑
==========one初始化调用的无参构造,故其成员属性均是默认值============
null
=======因为call返回的是this指针,one_copy 与 one指向同一块内存===============
one的地址: 1528902577, one_copy的地址: 1528902577
=======one_copy 与 one指向同一块内存一个的修改另一个必然改变=================
one的名字: 凡凡, one_copy的名字: 凡凡
小水 小水
========类的普通函数,只能结合对象实例化操作调用构造函数,不能通过方法名访问==============
我是无参构造
我是单参构造
我是双参构造
我是create,我定义了一个Cat类型的对象,昵称为团子的小猫快跑
参考:慕课网-Java工程师课程