Java学习点滴——对象实例化
基于《Java编程思想》第四版
构造与析构
在C++中通过构造函数和析构函数来保证:对象在使用前被正确初始化,在使用后被正确回收。Java中同样存在构造函数,但是没有析构函数。之所以没有析构函数是因为对象实际的存储期由GC决定,程序员无法明确析构函数何时会被执行。
GC会在回收对象前执行Object的protected void finalize()方法,子类可以通过重写finalize()方法来清理资源。但是因为GC回收对象时间的不确定性,加上finalize()本身可能引入的问题,所以并不赞成使用该方法。不过Java还提供下面的格式,保证在finally里的语句必然在函数正常返回或者抛异常返回前执行,因此可以将资源的回收放在该语句块中。
try{
}finally{
}
对象初始化
在C++中,类对象实例化时,是不会初始化对象空间的,完全依靠构造函数将成员变量设置为正确的初值,但是在Java中,当得到对象的空间后会先全部清零,再开始初始化对应成员变量。
C++初始化成员变量有两种方式
- 初始化列表
- 构造函数内赋值
Java则有三种方式
- 变量定义处赋值
- 初始化语句块:分为静态初始化语句块和非静态初始化语句块,静态初始化语句块只能包含静态成员变量,非静态初始化语句块可以包含静态成员变量和非静态成员变量
- 构造函数内赋值
通过下面的代码来加深印象
class MyType{
MyType(String msg){
System.out.println(msg);
}
}
class Base{
MyType b1;
static MyType b2 = new MyType("Base static member use =");
MyType b3 = new MyType("Base non-static member use =");
MyType b4;
static MyType b5;
{
b4 = new MyType("Base non-static member in {}");
b5 = new MyType("Base static member in {}");
}
static MyType b6;
static {
b6 = new MyType("Base static member in static {}");
}
Base(){
b1 = new MyType("Base non-static member in Base()");
System.out.println("Base()");
}
}
class Derived extends Base{
MyType d1;
static MyType d2 = new MyType("Derived static member use =");
MyType d3 = new MyType("Derived non-static member use =");
MyType d4;
static MyType d5;
{
d4 = new MyType("Derived non-static member in {}");
d5 = new MyType("Derived static member in {}");
}
static MyType d6;
static {
d6 = new MyType("Derived static member in static {}");
}
Derived(){
d1 = new MyType("Derived non-static member in Derived()");
System.out.println("Derived()");
}
}
public class Main {
public static void main(String[] args) {
Derived d1 = new Derived();
System.out.println("----");
Derived d2 = new Derived();
}
}
代码的输出顺序如下,将分析也包含在输出中了
// 初始化子类时,会先初始化父类,此时先初始化静态成员变量。顺序:定义时赋值>初始化语句块。
Base static member use =
Base static member in static {}
// 父类的静态成员初始化结束后,开始初始化子类的静态成员变量。顺序:定义时赋值>初始化语句块。
Derived static member use =
Derived static member in static {}
// 以上对静态成员表初始化只在第一次加载class时执行的,后续都不会再执行了。
// 开始初始化父类的非静态成员变量。顺序:定义时赋值>初始化语句块>构造函数
Base non-static member use =
Base non-static member in {}
Base static member in {} // 此处的静态成员变量赋值会在每次类实例化对象时,执行
Base non-static member in Base()
Base()
// 开始初始化子类的非静态成员变量。顺序:定义时赋值>初始化语句块>构造函数
Derived non-static member use =
Derived non-static member in {}
Derived static member in {}
Derived non-static member in Derived()
Derived()
----
// 第二次实例化对象时,只会执行非静态成员变量的定义赋值、非静态初始化语句以及构造函数内赋值
Base non-static member use =
Base non-static member in {}
Base static member in {}
Base non-static member in Base()
Base()
Derived non-static member use =
Derived non-static member in {}
Derived static member in {}
Derived non-static member in Derived()
Derived()
总体顺序就是
- 在首次加载class时,执行静态成变量的定义赋值和静态初始化语句块内的赋值。
- 在每次实例化对象时,执行非静态成员变量的定义赋值、非静态初始化语句块内的赋值、构造函数内的赋值。
如果不实例化对象,而是直接访问静态成员变量,那么只会执行父类静态成变量的定义赋值和静态初始化语句块内的赋值
public class Main {
public static void main(String[] args) {
System.out.println( Derived.b5 );
}
}
/// 输出如下
Base static member use =
Base static member in static {}
null
因为子类可能使用到父类的东西,所以总是先初始化父类再初始化子类。同样的初始化方法和类型(static或者non-static)的成员变量的初始化顺序与其定义顺序一致。这些和C++都是一样的。加载class的细节应该是被隐藏在Java解释器里了,通过字节码看不到完整的流程,这和C++就不一样了。
Java学习点滴——对象实例化的更多相关文章
- Java学习之对象实例化
一个对象实例化过程:Person p = new Person();1,JVM会读取指定的路径下的Person.class文件,并加载进内存,并会先加载Person的父类(如果有直接的父类的情况下). ...
- Java学习——面对对象的思想入门
本文是看过<head first Java>之后的一点感悟,写点东西帮忙以后回忆,Java目前在我的工作中用到还不多,而我又对面对对象的编程非常的感兴趣.曾经在MFC平台上写过 ...
- Java学习点滴——初识Java
基于<Java编程思想>第四版 前言 "程序就是算法加数据结构",而算法就是控制语句加操作符,编写一个程序就是使用控制语句加操作符去操作数据结构,因此我从Java的控制 ...
- Java 学习:对象和类
对象和类 从认识的角度考虑是先有对象后有类.对象,是具体的事物.类,是抽象的,是对对象的抽象. 从代码运行角度考虑是先有类后又对象.类是对象的模板. 对象:对象是类的一个实例,有状态和行为. 类:类是 ...
- Java学习点滴——Integer缓存
前言 一切从下面这段代码开始 public static void test(String[] agrs){ Integer a = 1; Integer b = 2; System.out.prin ...
- Java学习点滴——泛型
基于<Java编程思想>第四版 前言 虽然Java的泛型在语法上和C++相比是类似的,但在实现上两者是全然不同的. 语法 Java只需要一个<>就可定义泛型.在<> ...
- Java学习点滴——Class和反射
基于<Java编程思想>第四版 前言 我们要操作一个类实例对象时,一般都要先知道这个类有哪些方法或者成员变量.反射就是在我们不知道这个类有哪些方法或成员变量时,使用特定方式得到类的这些信息 ...
- Java学习笔记--对象克隆
转自:Edward_qing_Lee 的专栏 http://blog.csdn.net/edward_qing_lee/article/details/8249102 一.java 方法参数 理解: ...
- JAVA学习一 对象数组
对象数组 今天在写一个代码,才发现自己对于对象数组的理解是不够的,那么就讲讲自己现在的理解. 对于数组中的每一个元素都是一个针对对象的引用 他会指向你的具体的一个堆上的对象,它本身知识一个地址值,与其 ...
随机推荐
- SQL Android
SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少. 一般有以下几个关键步骤: 1.创建数据库 2.创建表 3.操作:增删改查 4.关闭数据库 5.删除表(非必选) SQLite ...
- TensorFlow从1到2(九)迁移学习
迁移学习基本概念 迁移学习是这两年比较火的一个话题,主要原因是在当前的机器学习中,样本数据的获取是成本最高的一块.而迁移学习可以有效的把原有的学习经验(对于模型就是模型本身及其训练好的权重值)带入到新 ...
- RazorPage 小测试,作下记录
@page@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf@{}@functions{ public AppInfo item { ...
- 轻量级.Net Core服务注册工具CodeDi发布啦
为什么做这么一个工具 因为我们的系统往往时面向接口编程的,所以在开发Asp .net core项目的时候,一定会有大量大接口及其对应的实现要在ConfigureService注册到ServiceCol ...
- HTML 练习显示隐藏
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- ArcGIS API for JavaScript 入门教程[6] 再讲数据——Map类之可操作图层
[回顾]上篇交代了Map是各种图层(不管是实际上的图层还是由图层构成的对象)的容器,是数据的容器,并不作显示(由视图类绘制).并重点讲解了由图层构成的复杂图层——高程属性ground和底图属性base ...
- Flutter 即学即用系列博客——01 环境搭建
前言 工欲善其事,必先利其器 所以第一篇我们来说说 Flutter 环境的搭建. 笔者这边使用的是 MAC 电脑,因此以 MAC 电脑的环境搭建为例. Windows 或者 Linux 也是类似的操作 ...
- psql 关于主键自增的问题
在psql中往往我们需要设置一个自增的主键id字段,psql中不像SQL Server那样点选 打钩傻瓜式就能设置好的,是需要创建序列的:CREATE SEQUENCE,关键字SEQUENCE. 我们 ...
- 数组for循环查找范围
数组for循环查找范围,如果是判读是否在键值之间,如$array[$i],那么接邻的元素不能用$array[$i+1]或者$array[$i-1]只能用$array[$i++]
- 关于Layer ui的加载层位置居中问题
最近在项目中一直使用layerui的相应的提示框以及它的加载层,然而就在今天遇到了一个神奇的问题,我使用 var index = layer.load(0, {shade: false}); 结果一直 ...