Java对象创建过程补遗
一、static修饰的东东是属于这个类的,是所有的该类的实例共享的,因此它们的初始化先于实例对象的初始化。
二、Java中没有静态构造方法,但是有静态代码块。当类中同时存在静态代码块和静态成员变量声明语句时,它们谁先执行?
答:按照类中定义的从上到下顺序,谁在前面谁先执行。
三、当类中同时存在非静态代码块和非静态成员变量声明语句时,它们谁先执行?
答:按照类中定义的从上到下顺序,谁在前面谁先执行。
四、含有赋值的非静态成员变量声明语句,如 int v=4,其实这个语句的执行要分成两步进行。首先创建对象时初始化变量v,此时v=0;然后在构造器中再给v赋值,也就是v=4。
五、非静态初始化块中的赋值语句、实例变量值初始化赋值语句,都比构造器中的赋值语句先执行。
原理如下:不管是非静态初始化块中的赋值语句,还是实例变量值初始化赋值语句,它们在编译器处理后,都会被提取到构造器中,而且在构造器中原有的语句之前。
public class JavaTest
{
//成员变量
int count=20; //非静态初始化代码块
{
count = 12;
System.out.print("占个位置而已");
} //构造器
public JavaTest()
{
System.out.println(count);
} public JavaTest(String name)
{
System.out.println(count);
}
}编译后等价于:
public class JavaTest
{
//成员变量
int count; //非静态初始化代码块
{
System.out.print("占个位置而已");
} //构造器
public JavaTest()
{
count=20;//原来的成员变量赋值
count=12;//原来的初始化代码块赋值
System.out.println(count);
} public JavaTest(String name)
{
count=20;//原来的成员变量赋值
count=12;//原来的初始化代码块赋值
System.out.println(count);
}
}
六、“Java对象是由构造器创建的”这句话是错误的。构造器只是负责对Java对象的实例变量执行初始化而已,就像前面的三、四、五点所提及的。在执行构造器代码之前,该实例对象所占的内存已经被分配下来了,这些内存都默认是空值——对于基本类型的变量,默认的空值就是0、0.0或者false;对于引用类型的变量,默认的控制就是Null。看看下面的代码,分析一下结果是什么:
class base
{
private int i = 2; public Base()
{
这里是1处this.display();
} public void display()
{
System.out.println(i);
}
} class Derived extends base
{
private int i = 22; public Derived()
{
i = 222;
} public void display()
{
System.out.println(i);
}
} public class Test
{
public static void main(String[] args)
{
new Derived();
}
}
问题一:Derived对象的实例中有几个”i“实例变量? 说只有一个的同学,请自己去面壁
问题二:代码中的红色的1处,所指的“this”是谁?是base的实例还是Derived的实例? 答案是 Derived
问题三:代码中的红色1处,“this.display(); ”调用的是哪个类里面的display方法? 答案是 Derived
问题四:执行Test后输出是2?22?还是222? 答案是 0
七、编译器在处理成员变量和方式时是有区别的。当子类和父类存在同名的成员变量时,实际是各自拥有一个名字相同的成员变量;当子类中有个方法和父类签名相同的时候,实际是子类对父类中该方法的重写,这个时候通过子类的实例调用这个名称的方法将始终是子类的方法,哪怕你把子类强制转换成父类。这么说有点迷糊,直接往下看:
class base
{
private int i = 2; public Base()
{
this.display();
} public void display()
{
System.out.println("我是父类"+i);
}
} class Derived extends base
{
private int i = 22; public Derived()
{
i = 222;
} public void display()
{
System.out.println("我是子类"+i);
}
}
情况一:
Base b=new Base()
b.count :肯定是2,因为当前对象是父类的实例
b.display():肯定是调用父类的方法,因为当前是父类的实例
情况二:
Derived d=new Derived();
b.count: 肯定是22,因为当前对象是子类的实例,子类自己有个成员变量叫“i”干嘛拿父类的
b.display():子类的方法
情况三:
Base bd=new Derived();
b.count:肯定是2,因为当前子类是被向上转换了,不得不拿父类的“i”
b.display():还是子类的方法,向上转换不能太过分了,子类已经重写的方法不能再反悔了。要想调用父类的同名方法,还得用这种方式:super.display()
情况四:
Derived d=new Derived();
Base d2b=d;
b.count:肯定是2,因为当前子类是被强制类型转换了,不得不拿父类的“i”
b.display():还是子类的方法,强制类型转换也不能太过分了,子类已经重写的方法不能再反悔了。要想调用父类的同名方法,还得用这种方式:super.display()
八、从内存分配的角度来看,当程序创建一个子类对象时,JVM不仅会为该类中定义的实例变量分配内存,同时也会为其父类中定义的所有实例变量分配内存,即使子类定义了与父类中同名的实例变量。如果子类中定义了与父类同名的成员变量,那么子类中的变量会隐藏父类中定义的变量,但不是完全覆盖,只是不能直接用而已;当把子类转换成父类的时候或者使用”super“关键字,就可以使用父类中的同名成员变量了。
Java对象创建过程补遗的更多相关文章
- java对象创建过程
1.jvm找到class文件路径. 2.jvm载入class文件,静态初始化,创建一个class对象. 3.为即将创建的对象分配内存空间. 4.对分配的空间进行清零,例如:int清除为0,boolea ...
- java对象创建过程简介
这是看书的记录,字有点丑啊还是将就搬上来 -.-,等把后面看了完善图
- Java中对象创建过程
本文介绍的对象创建过程仅限于普通Java对象,不包括数组和Class对象. 1.类加载检查 虚拟机遇到一条new指令时,首先去检查该指令的参数能否在常量池中定位到一个类的符号引用,并且检查这个符号引用 ...
- 深入学习Java对象创建的过程:类的初始化与实例化
在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.在实例化一个对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类构造器完 ...
- Java中类加载过程和对象创建过程
类加载过程: 1, JVM会先去方法区中找有没有相应类的.class存在.如果有,就直接使用:如果没有,则把相关类的.class加载到方法区 2, 在.class加载到方法区时,会分为两部分加载:先加 ...
- java基础---类加载和对象创建过程
类中可以存在的成员: class A{ 静态成员变量: 非静态成员变量: 静态函数: 非静态函数: 构造函数 A(..){...} 静态代码块 static{...} 构造代码块 {...} } 类加 ...
- java类加载、对象创建过程
类加载过程: 1, JVM会先去方法区中找有没有相应类的.class存在.如果有,就直接使用:如果没有,则把相关类的.class加载到方法区 2, 在.class加载到方法区时,会分为两部分加载:先加 ...
- COM对象创建过程
在客户端需要调用COM组件时,通常调用windowAPI函数: STDAPI CoCreateInstance( REFCLSID rclsid, //创建的Com对象的类标识符(CLSID) LPU ...
- Java内存区域与对象创建过程
一.java内存区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区域则 ...
随机推荐
- 解决在 win10 下 vs2017 中创建 MFC 程序拖放文件接收不到 WM_DROPFILES 消息问题
解决方案 这个问题是由于 win10 的安全机制搞的鬼,即使以管理员权限运行也不行,因为它会把 WM_DROPFILES 消息过滤掉,那怎么办呢?只需在窗口初始化 OnInitDialog() 里添加 ...
- python学习笔记:第9天 函数初步
1. 函数的定义及调用 函数:所谓的函数可以看作是对一段代码的封装,也是对一个功能模块的封装,这样方便在下次想用这个功能的时候直接调用这个功能模块,而不用重新去写. 函数的定义:我们使用def关键字来 ...
- 【翻译】理解 LSTM 网络
目录 理解 LSTM 网络 递归神经网络 长期依赖性问题 LSTM 网络 LSTM 的核心想法 逐步解析 LSTM 的流程 长短期记忆的变种 结论 鸣谢 本文翻译自 Christopher Olah ...
- MFC-控件操作及数据交换
对控件进行操作函数如下: 1.ShowWindow() TURE为显示控件,FALSE为隐藏该控件: if(条件) GetDlgItem(ID)->ShowWindow(TRUE);//满足条件 ...
- 20155322 2016-2017-2 《Java程序设计》实验二《Java面向对象程序设计》
20155322 2016-2017-2 <Java程序设计>实验二<Java面向对象程序设计> 实验目的与内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承 ...
- Struts2知识点总结
2 Struts2 1 Struts2 简化Servlet编写 2 Struts2使用步骤 1 添加第三方包 2 在web.xml当中配置核心过滤器 <filter> <filter ...
- c++中的stack实现
通用.类型安全.模板 简直就是巧夺天工的例子
- 模拟IDE上的run过程
看了一下老陈写的模仿JDK动态代理,从中取一部分单独扩展,模拟一下IDE上的run过程(不愧是老陈,去年写的东西我要现在才能理解) 对run过程的猜想 在点击run的过程中应该做了不少事.先编译运行r ...
- 4星|《财经》2018年第15期:电动飞机、无人小飞机、AI无人机
<财经>2018年第15期 总第532期 旬刊 本期主题是AI.有多篇国内AI行业的比较深入的调查报告,比较有意思的有:电动飞机.无人小飞机.AI无人机.欧盟通用数据保护条例.Amazon ...
- vscode中安装使用markdown 插件
linux中好用的IDE vscode是微软推出的一款好用免费的IDE,可以快速部署开发环境,所说配置有些繁琐,但是瑕不掩瑜.它同时支持很多种拓展的编辑器,MarkDown只是其中的一种. 安装 ...