黑马程序员——面向对象9:对象的初始化&方法的调用
2014-10-07 23:10
274 查看
------- android培训、java培训、期待与您交流! ----------
这一篇我们来详细描述一下,创建一个对象和对象调用方法时,在内存中都发生了什么,也算是对之前学习的内容的一个总结。
代码1:
当主函数运行到“Person p = new Person()”语句时,
第一步:在栈内存中为主函数开辟一块空间,并先执行赋值符左侧的语句,在栈内存中创建一个Person类类型变量p;
第二步:在继续执行右侧的语句之前,将Person类加载进内存,更具体说,就是当执行“new Person()”时,虚拟机将“Person.class”(字节码)文件加载进内存;
第三步,加载Person类的同时,在方法区中为该类开辟一块空间(所谓开辟,其实就是将这片内存区域清零,也就是默认初始化,下同),与此同时在此创建这个类的所有静态成员和方法(注意,静态方法和非静态方法是分在两个空间存储的),然后对静态成员变量(该例中为country)进行默认初始化(引用数据类型变量赋null,boolean型变量赋false,其他基本数据类型变量赋0,下同),最后进行显示初始化;
第四步:如果有的话执行静态代码块;
第五步:在堆内存为Person对象开辟了一块空间,并为这个空间分配一个地址值,接着在此创建该对象所有的非静态成员变量(该例中为name和age)并进行默认初始化,然后进行显示初始化;
第六步:如果有的话执行对象的构造代码块;
第七步:执行相对应的构造函数;
第八步:最后将上述内存的地址值赋给栈内存中的变量p,p就指向了堆内存中的Person对象。
2. 方法的调用
当主函数运行“p.setName(“Jack”)”语句时,在栈内存为setName方法开辟一块空间,并在其内部创建局部变量name,而且这块内存空间一开辟就存在了对本类对象的引用——this。实际上这个this的值就是对象在堆内存中的地址值,那么this也就指向了堆内存中调用setName方法的本类对象。在调用setName方法的同时将字符串“Jack”作为实际参数传入setName方法中,这个值接着赋给了方法中的局部变量name,然后通过赋值语句将“Jack”赋给了堆内存中Person对象(this关键字的作用)的成员变量——name。
以上就是非静态方法的调用过程在内存中的体现。如果是调用静态方法,比如showCountry方法,那么与调用非静态方法的相同点是:都要在栈内存为方法开辟一块空间;区别在于:因为没有对象产生,所以不涉及堆内存,也不需要this关键字的指向作用;只是栈内存与方法区中的变量之间的互相访问。
小知识点1:
大家都知道静态方法只能调用静态方法,比如下述代码,
代码2:
这一篇我们来详细描述一下,创建一个对象和对象调用方法时,在内存中都发生了什么,也算是对之前学习的内容的一个总结。
代码1:
class Person { private String name; private int age; private static String country = "CN"; { System.out.println("name = "+this.name+",age = "+this.age); } Person(String name, int age) { this.name = name; this.age = age; } public void setName(String name) { this.name = name; } public void speak() { System.out.println("name="+this.name+",age="+this.age); } public static void showCountry() { System.out.println("country = "+country); } }<strong style="text-decoration: underline;"> </strong>class PersonDemo { public static void main(String[] args) { Person p = new Person("Tom", 33); p.setName(“Jack”); } }1. 对象的初始化过程
当主函数运行到“Person p = new Person()”语句时,
第一步:在栈内存中为主函数开辟一块空间,并先执行赋值符左侧的语句,在栈内存中创建一个Person类类型变量p;
第二步:在继续执行右侧的语句之前,将Person类加载进内存,更具体说,就是当执行“new Person()”时,虚拟机将“Person.class”(字节码)文件加载进内存;
第三步,加载Person类的同时,在方法区中为该类开辟一块空间(所谓开辟,其实就是将这片内存区域清零,也就是默认初始化,下同),与此同时在此创建这个类的所有静态成员和方法(注意,静态方法和非静态方法是分在两个空间存储的),然后对静态成员变量(该例中为country)进行默认初始化(引用数据类型变量赋null,boolean型变量赋false,其他基本数据类型变量赋0,下同),最后进行显示初始化;
第四步:如果有的话执行静态代码块;
第五步:在堆内存为Person对象开辟了一块空间,并为这个空间分配一个地址值,接着在此创建该对象所有的非静态成员变量(该例中为name和age)并进行默认初始化,然后进行显示初始化;
第六步:如果有的话执行对象的构造代码块;
第七步:执行相对应的构造函数;
第八步:最后将上述内存的地址值赋给栈内存中的变量p,p就指向了堆内存中的Person对象。
2. 方法的调用
当主函数运行“p.setName(“Jack”)”语句时,在栈内存为setName方法开辟一块空间,并在其内部创建局部变量name,而且这块内存空间一开辟就存在了对本类对象的引用——this。实际上这个this的值就是对象在堆内存中的地址值,那么this也就指向了堆内存中调用setName方法的本类对象。在调用setName方法的同时将字符串“Jack”作为实际参数传入setName方法中,这个值接着赋给了方法中的局部变量name,然后通过赋值语句将“Jack”赋给了堆内存中Person对象(this关键字的作用)的成员变量——name。
以上就是非静态方法的调用过程在内存中的体现。如果是调用静态方法,比如showCountry方法,那么与调用非静态方法的相同点是:都要在栈内存为方法开辟一块空间;区别在于:因为没有对象产生,所以不涉及堆内存,也不需要this关键字的指向作用;只是栈内存与方法区中的变量之间的互相访问。
小知识点1:
大家都知道静态方法只能调用静态方法,比如下述代码,
代码2:
class Demo { public static void method() { System.out.println(“method run”); } public static void function() { System.out.println(“function run”); method(); } }上述代码中,function方法内部调用了method方法,这就和非静态方法互相调用相同时放方法名前面省略了this一样,静态方法相互调用时方法名前省略了类名,所以完整写法是“Person.method()”。这同样也适用于静态成员变量。实际上,大家要记住,所有方法(无论是否静态)的执行都是需要调用者,静态方法的调用者是类,非静态方法是对象,主函数是虚拟机。
相关文章推荐
- 黑马程序员_Java基础_面向对象(Static的使用、对象初始化和调用成员过程、单例设计模式)
- 黑马程序员——Java基础---面向对象(对象的初始化、对象调用成员、单例设计模式)(4)
- Java对象初始化步骤&&子类继承父类后变量与方法调用情况
- 黑马程序员 笔记(六)——面向对象(static关键字、静态、main函数、、帮助文档、对象的调用和初始化、单例)
- 黑马程序员--java中父类和子类都有构造方法时,子类对象的初始化过程
- java 程序加载过程---3--类中申明同时申明类的静态对象 创建类的实例 访问类的静态变量 调用类的静态方法 使用反射方法 初始化类的子类对象 直接使用java.exe 调用某个类
- JAVA基础知识再学习(2)对象的初始化过程 & 对象的调用过程
- 图解Java对象初始化过程以及方法调用
- Java中对象方法的调用过程&动态绑定(Dynamic Binding)
- 黑马程序员_<<面向对象(对象,封装,satic,构造函数,代码块,this)---01>>
- 黑马程序员------毕老师视频笔记第六天------面向对象(对象初始化过程)
- 图解Java对象初始化过程以及方法调用
- 黑马程序员 Java基础<一>---> 面向对象与类之概述(匿名对象、封装、构造函数、this、静态等)
- 黑马程序员-OC中对象方法的声明与调用(多个参数)
- vector<char> 容器初始化 string 对象 两种方法
- 黑马程序员—Java面向对象(类和对象、封装、构造方法、this关键字、static关键字)
- 黑马程序员——java第六天:面向对象(静态、帮助文档、对象初始化过程、单例)
- 图解Java对象初始化过程以及方法调用
- 图解Java对象初始化过程以及方法调用
- 黑马程序员——面向对象4:对象的初始化