JAVA从入门到放弃(3)类的初始化与清理

J

前面两篇笔记记录的比较草率,因为C语言的功底已经很扎实了,如果不扎实的童鞋可以深入了解一下JAVA的前面的基础知识,这里我们就要开始讨论面向对象的高级特性了,首先要讨论一下类的初始化与清理

向较于JAVA,C语言有一个很致命的问题,就是C语言并不会自动初始化你定义的变量,这样就会造成程序不安全,因此在C++中引入了构造器,这样在新建对象的时候会自动调用构造器对特定的内容进行初始化,但是C++还提供了一个垃圾回收器(析构函数),但是JAVA则免去了析构函数,因为JAVA的内存管理是由JVM自动管理的所以并没有析构函数

那么接下来我们要使用构造器来保证特定项目被初始化了,首先第一个问题就是怎么定义一个构造器

构造器需要和类名相同,因此构造器就不能符合JAVA的对于方法的命名规则,对于不接受任何参数的构造器叫默认构造器,在JAVA文档中称之为无参构造器。现在我们要写一个带参数的构造器

上述代码描述了一个带参数构造器以及给出了带参数构造器的用法,在JAVA中,“初始化”和“创建”是捆绑在一起的,不能分离。利用关键字new可以返回对新建对象的引用(就是第一篇笔记中提到的代替指针的引用)本身构造器并没有任何返回值

当我们知道了如何使用带参构造器。我们需要知道任何程序设计语言都应该具备的一个重要特性就是对名字的运用,也就是说当你对一个类输入不同的参数例如上面的例子new Rock(2,3);这就要采用一个面向对象的特性:重载。下面我写一个重载的例子

这样我们就完成了对构造器方法的重载,我们使用构造器重在,就是为了适应不同的参数,避免创建多个类似的类,就需要用到方法重载。但是我们需要注意一点的是如何区分是否是重载方法:每一个重载方法都必须有一个独一无二的参数列表,甚至于参数的顺序不同都可以说明这是两个重载方法。现在设想一个情况,如果我们给构造器传入一个比实际要求的数据类型小,则实际传入的数据就会被提升,也就是向高等类型转型,但是如果传入的实际类型偏大,则需要强制进行窄化转换才能传入

另外是不能通过返回值来区分是否是重载方法,因为编译器可能无法正确理解语义

那么接下来就有一个问题,如果我对一个类不设置构造器,会出现什么后果。其实如果不设置构造器,那么编译器就会自动为你创建一个构造器,这个时候你可能会问为什么不能没有构造器。因为new会调用构造器,所以当没有构造器时new就无法对这个类进行初始化,也就无法创建对象

既然谈到了类,那么就不得不提到this伪类,所谓this伪类是只能在类内部使用,用在类内方法里表示这个类。可能你就会问了表示这个类有什么用,这里就举个例子来理解一下this伪类的作用

这里只是为了使用this而使用this,其实这里在写程序的时候并不需要使用this关键字,因为编译器会为你自动添加。那么什么时候真正需要使用this呢?当我们需要返回对当前对象的引用的时候需要我们在return上返回this

上面这个例子就说明了我们应该在必要的时候使用this关键字。

当然,有的时候我们可能对于一个类写了多个构造器,我们需要在调用一个构造器的时候调用其它构造器,我们可以在构造器内部调用其他构造器,这样做显然不够优雅,这个时候我们就可以用到上面说到的this伪类,因为this伪类在类中代表这个类

如果当我们的参数和成员变量存在名字冲突的时候this关键字可以很好的帮我们规避问题,用this.i来表示成员变量

了解了this关键字之后,我们就可以比较全面了解一下static(静态)关键字,如果一个方法被设置成了static那么就表明这个方法没有this伪类,因此并不是所有的class都有this,在static方法中我们不能调用非静态方法,但是在非静态类中我们可以调用静态方法。对于static类的static方法我们主要的还是通过类本身直接调用static方法,因为在JAVA中禁止全局变量,而static方法在具体作用上又很像全局变量(只要你在类中置入static方法就可以访问其他static方法和static域),这样一看static类和方法好像不太符合面向对象的设计思想,因此在使用的时候应该酌情使用

接下来我们来聊一聊关于成员初始化的问题,尽管JAVA会在最大程度上保证所有变量再使用前都得到初始化。对于方法的局部变量,JAVA将以编译错误的形式来提醒你变量没有初始化,相较于C语言只给你警告,可能会忽略因为未初始化而导致的各种问题(这里我非常不同意谭浩强书中的观点,警告可以完全忽略,虽然再大部分时候是可以忽略的,不论任何语言,警告一样需要引起重视,仔细分辨)。这样JAVA就解决了C语言中一个很难真正杜绝的问题。如果是非局部变量那么JAVA会默认给对应变量赋值为0

当然我们可也以不使用JAVA默认的默认的初始化方法,我们可以对希望的变量进行指定初始化,比方说下面的代码

自然我们可以使用同样的方法来初始化非基类,但是如果我们在没有初始化之前就使用例如下面代码

上述代码则会恰当的引发JAVA的向前引用警告,因为第一个语句在使用时并没有定义和初始化i,如果将一二句进行颠倒,就不会引发问题

接下来想我们要讨论一下如何使用构造器进行初始化,上文中已经提到了什么是构造器,所谓构造器初始化就是在构造器中进行的初始化

针对上面的过程我想阐述一下i的初始化过程,在int i中首先由JAVA将i初始化为0,然后当类被调用时构造器再将i初始化为7。在类的内部变量定义的先后顺序决定了初始化的顺序,前面提到了JAVA在最大程度上保证变量被初始化,也就是说对于定义变量的初始化在所有代码执行之前,当然这里是将非静态变量和静态变量放在一起笼统的说。关于非静态数据的初始化其实很简单,并不需要过多阐述,下面主要阐述一下静态变量的初始化。

关于静态变量的初始化方法实际上和非静态变量的初始化方法类似,只不过需要在变量前声明static关键字

另外我们需要知道的是static关键字不能作用于局部变量,因为JAVA中 没有全局变量,但是使用static声明过的关键字具有和全局变量类似的效果。至于为什么,因为无论这个变量被创建多少次,它在内存中只占有一份存储空间。自然JAVA也会对static变量进行初始化,如果是标准数据类型就赋值为标准值,如果是引用类型就赋值为NULL。不过需要注意的是非静态变量是在程序执行之前就会初始化,而static变量则会在必要的时候进行初始化,也就是说当static变量所在的区域被访问了才会进行初始化。在整个JAVA中对于数据的初始化顺序是首先初始化静态对象然后初始化非静态对象。构造器即使不声明也属于static方法。注意static方法可以被重载,但是不可以被重写,也就是说static方法没有多态

既然是说初始化,那么就不能忘记JAVA中的一个比较重要的数组的初始化,关于数组的定义有两种方法int[] a1和int a1[]两种方法,上面说的a1属于引用,关于引用相比大家都知道,也就不用我多说了,JAVA为数组的安全提供保证,也就是说为数组提供越界检查,当下标越界时会提示错误,自然这一动作需要更多的资源开销

下面主要说一下数组的初始化

需要注意的是两种初始化方法中最后一个逗号是为了保证维护长列表的方便,当然第一种数组方法只能用在定义处,不能用在别的地方

自然JAVA SE5后还增加了对枚举类型的支持,关于枚举类型的定义如下

何为枚举类型呢,简单的来说就是使用单词的外形,实际内容是数字,我们使用的就是那个外形。上面的单词依次对应0 1 2 3 4,enum经常和switch联合使用

About the author

NOBUG.IN

Add comment

By NOBUG.IN

Your sidebar area is currently empty. Hurry up and add some widgets.