Java 类与对象
在一个面向对象的系统中,对象是对现实世界中事物的抽象,是Java程序的基本封装单位,是类的实例;类是对象的抽象,是数据和操作的封装体;属性是事物静态特征的抽象,在程序中使用数据成员加以描述;操作是事物动态特征的抽象,在程序中使用成员方法来实现。
类与对象概念
对象
客观世界的事物映射为对象,对象是面向对象程序设计中用来描述客观事物的基本单位。
类是对象的抽象和归纳,对象是类的实例。
对象的特征:
- 对象标识:即对象的名字,是用户和系统识别它的唯一标志。(外部和内部)
- 属性:用来描述对象的静态特征的一组数据。
- 方法:对对象动态特征(行为)的描述,也称为服务或操作。
类
类是一个独立的程序单位,是具有相同属性和方法的一组对象的集合。
在定义对象之前应该先定义类
描述一个类需要指明三个方面的内容:
- 类标识:类的一个有别于其他类的名字。
- 属性说明:用来描述相同对象的静态特征。
- 方法说明:用来描述相同对象的动态特征。
example: person类:
1 | Class Person //class指出这是一个类,Person是类标识 |
- 类与对象的关系:
==对象是对事物的抽象,而类是对对象的抽象和归纳,给出了属于该类的全部对象的抽象定义,对象是符合这种定义的一个实体==。在面向对象的程序设计中,对象被称作类的一个实例,而类是对象的模板。
类的定义
类修饰符
无修饰符:
如果一个类前无修饰符,则这个类只能被同一个包里的类使用。Java规定,同一个程序文件中的所有类都在同一个包内。也就是说,==无修饰符的类可以被同一个程序文件中的类使用==,但是不能在其他程序文件中的类(即其他包中的类)使用。
public修饰符:
如果一个类的修饰符是public,则这个类是公共类。公共类既可供它所在包中的其他类使用,也可以供其他包中的类使用,在程序中可以使用import引用其他包中的public类。Java规定,在一个程序文件中,只能定义一个public类,否则编译的时候系统会报错。
final修饰符:
用final修饰的类被成为最终类,最终类不能被任何其他类所继承。final类可以将它的内容、属性和功能固定下来,与它的类名形成稳定的映射关系,从而保证引用这个类所实现的功能是正确无误的。将类定义为final类可以用来完成某种标准功能,也可以提高程序的可读性和安全性。
abstract修饰符:
用abstract修饰符修饰的类称为抽象类。抽象类刻画了研究对象的公有行为特征,并通过继承机制将这些特征传送给它的派生类。抽象类的作用是将许多有关的类组织在一起,提供一个公共的基类,为派生具体类奠定基础。当一个类中出现一个或多个用abstract修饰符定义的方法时,必须将这个类定义为抽像类。
可以同时使用两个修饰符来修饰一个类(修饰符之间用空格分开,写在class之前,修饰符的顺序对类的性质没有任何影响。类不能被修饰为abstract final[^1]。
声明类的一般格式
类的声明部分用于描述类的名称以及类的其他属性(类的访问权限、与其他类的关系等)。声明类的语法如下:
1 | [public] [abstract | final] class <className> [extends superClass-Name] [implements interfaceNameList]{...} |
其中:
- “[]”代表可选项,“<>”表示必选项,“|”表示多选一。
- public、abstract或final:指定类的访问权限及其属性,用于说明定义类的相关特征。
- class:Java语言的关键字,表明这是一个类的定义。
- className:指定类的名称(合法的java标识符)
- extends superClassName:指定所定义的类继承于哪一个父类。当使用extends关键字时,父类名称为必选参数
- implements interfaceNameList:指定该类实现哪些接口。当使用implements关键字时,父类名称为必选参数
- {…}:花括号中的内容时类体的定义。类体提供了类的对象在生命周期中需要的代码,具体包括:
- 构造和初始化新对象的构造方法。
- 表示类及其对象状态的变量,即数据成员
- 实现类及其对象的方法,即成员方法
- 进行对象消除的finalize方法。
数据成员[^2]
一、数据成员的声明
一般情况下,声明一个数据成员时必须给出这个数据成员的标识符并指明它所属的数据类型,声明数据成员的语法如下:
1 | [public | protected | private] [static] [final] [transient] [volatile] <type><variableName> |
其中:
- public、protected、private:指定变量的访问权限。
- static:指定数据成员为静态数据成员,也称为类变量(class variable)。它被保存在内存区的公共存储单元中,而非某个对象的内存区中,因此,一个类的任何对象访问它的时候,存取到的都是相同的数值。如果省略该关键字,表示数据成员为实例变量(instance variab)。
- final:指定数据成员为常量。
- transient;声明数据成员为一个暂时性变量,它告知JVM该变量不属于对象的持久状态,从而不能被持久存储。如果省略该关键字(默认情况下),则类中所有变量都是对象持久状态的一部分,当对象被保存到外存时,这些变量必须同时被保存。
- volatile:指定数据成员在被多个并发线程共享时,系统将采取更优化的控制方法提高线程并发执行的效率。
- type:指定数据成员的数据类型。
- variableName:指定数据成员的名称。
二、静态初始化器
静态数据成员的初始化可以有用户在定义时进行,也可以由静态初始化器[^3]来完成。
eg:在类ClassPractice的定义中,用静态初始化器对静态数据成员进行初始化:
1 | class ClassPractice{ |
三、用final修饰的最终数据成员
如果一个类的数据成员用final修饰符修饰,则这个数据成员就被限定为最终数据成员。最终数据成员可以在声明时进行初始化,也可以通过构造方法赋值,但不能在程序的其他部分赋值,他的值在程序的整个执行过程中时不能改变的。
成员方法
成员方法描述对象所具有的功能或操作,反映对象的行为,是具有某种相对独立功能的程序模块。一个类或对象可以有多个成员方法,对象通过执行它的成员方法对传来的消息做出响应,完成特定的功能。(按来源可分为类库成员方法和用户自定义的成员方法)
一、声明成员方法的格式
类的成员方法由方法声明和方法体两部分组成,声明成员方法的语法如下:
1 | [accessLevel] [static] [final | abstract] [native] [synchronized] <return_type><name> ([<argument_list>]) [throws <exception_list>]{ |
其中:
accessLevel:确定方法的被访问权限,可选值为public、protected和private
static:将成员方法指定为静态方法,它是属于整个类的类方法,不用static修饰符限定的方法是属于某个具体类的对象的方法。static方法使用特点如下:
(1)static犯法是属于整个类的,它在内存中的代码段将随着类的定义二被分配和装载。而非static的方法是属于某个对象的方法,当这个对象创建时,在对象的内存中拥有的这个方法的专用代码段。
(2)引用静态方法时,可以使用与对象关联的引用变量名作为前缀,也可以使用类名作为前缀。
(3)static方法只能访问静态数据成员,不能访问非静态数据成员,但非static方法可以访问静态数据成员。
(4)static方法只能访问static方法,不能访问非static方法,但非static方法可以访问static方法。
(5)static方法是不能被覆盖,即这个类的子类不能由相同名及相同参数的方法。
(5)main方法是静态方法。Java的每个Application程序中,都必须有且只能有一个main方方法,它是Application程序运行的入口。
final:指明该成员方法为最终方法不能被重写[^4]。
abstract:指名该方法是抽象成员方法。
native:指明该方法时本地成员方法,即该成员用其他语言实现。用此类方法的目的时将C、C++等语言嵌入到Java语言中。
synchronized:控制多个并发线程对共享数据的访问。
return_type:确定方法的返回之类型,如果方法没有返回之,则可以使用关键字void标识。
name:指定成员方法的名称。
argument_list:形式参数列表,成员方法可以分为带参数和不带参数的两种。
throws
:列出该方法将要抛出的一系列异常。 block:方法体,描述该方法所要完成的功能,是方法的实现部分。
public class ClassPractice2{ public static void main(String[] args){ int a=2,b=3; int f=add(a,b); System.out.println("f="+f); } static int add(int x,int y) { int z,d; z=x+y; return z; } } <!--5-->
其中:className指定一个已经定义的类,objectName指定对象名称(对象名必须是合法的Java标识符)。在声明对象是,只是在内存中为其分配了一个引用空间,并置初始值为null,表示不指向任何存储空间。
建立对象
在声明对象时,只确定了对象的名称和它所属的类,并没有为对象分配存储空间,此时对象还不是类的实例。只有通过建立对象,才为对象分配内存,使该对象称为类的实例,这个过程称为对象的实例化,使用关键字new来完成,它的语法如下:
1 | <objectName>=new <someClass> ([argument_list]) |
其中:bojectName指定已经声明的对象名;someClass指定需要调用的构造方法名,即类名;argument_list指定构造方法的入口参数。
初始化对象
初始化对象是指由一个类生成对象时,为这个对象去欸的那个初始状态的过程,初始化对象由三种实现方法:
一、用默认初始化原则赋初值
数据成员类型 | 默认取值 | |
1 | Byte | 0 |
2 | Short | 0 |
3 | Int | 0 |
4 | Long | 0 |
5 | Char | "\u0000" |
6 | Float | 0 |
7 | Double | 0 |
8 | Boolean | False |
9 | 所有引用类型 | Null |
二、用赋值语句赋处置。
三、由Java提供的构造方法来完成它[^5]。每当使用new关键字创建一个对象,为新建对象开辟了内存空间之后,Java系统将自动调用构造方法初始化这个新建对象。,构造方法是类的一种特殊方法,它的特殊性体现在以下几个方面:
- 构造方法的方法名与类名相同;
- 构造方法是类的方法,它能够简化对象数据成员的初始化操作;
- 不能地构造方法指定类型,它有隐含的返回之,该值由系统内部使用;
- 构造方法一般不能由编程认源显示地直接调用,在创建一个类对象的同时,系统会自动调用该类的构造方法将新对象年糕初始化;
- 构造方法可以重载,即可以定义多个具有不同参数的构造方法;
- 构造方法可以继承,即子类可以继承父类的构造方法;
- 如果用户在一个自定义类中为定义该类的构造方法,系统将为这个类定义一个缺省的空构造方法。这个空构造方法没有形式参数,没有任何具体语法,不能完成任何操作,但在创建一个类的新对象时,系统要调用该类的构造方法将新对象初始化。
使用对象
当一个对象被创建之后,这个对象就拥有了自己的数据成员和成员方法,可以通过与之关联的引用变量名来引用对象的成员。引用方法如下:objectReference.variableName
;
其中:objdctReference指定调用成员变量的对象名称(引用);variableName指定需要调用的数据成员的名称。对象成员方法的引用方式如下:
1 | objectReference.methodName([argument_list]) |
其中objectReference指定调用成员变量的对象名称,methodName指定需要调用的成员方法的名称,argument_list指定需要调用的成员方法的参数列表。
对象的消除
在Java中程序员创建的对象可以不必删除,因为Java系统提供的垃圾回收机制可以自动判断对象是否还在使用,并能够自动销毁不再使用的对象,回收对象所占用的资源。
Object类提供了finalize()方法,自定义的Java类可以覆盖finalize()方法,并在这个方法中进行释放对象所占资源的操作。当垃圾回收器要释放无用对象的存储空间时,将先调用该对象的finalize()方法。
封装机制
封装是面向对像的一个重要特征,一般地,封装将客户端不应看到信息包裹起来,使内部的执行对外部看来是一种不透明的黑箱,客户端不需要了解内部资源就能够达到目的。
封装
封装也称为数据隐藏,是指将对象的数据与操作数据的方法相结合,通过方法将对象的数据与显示细节保护起来,只保留一些对外接口,以便与外部发生联系。封装具有如下特征:
(1)在类的定义中设置访问对象属性(数据成员)及方法(成员方法)的权限,限制该类对象及其他类的对象的使用范围
(2)提供一个接口来描述其他对象的使用方法。
(3)其他对象不能直接修改对象所拥有的属性和方法
封装反映了事物的相对独立性,在变成上的作用是使对象以外的部分不能随意存取对象的内部数据(属性),从而有效地避免了外部错误和对它的影响。
访问控制
访问控制是通过在类的定义中使用权限修饰符实现的,以达到,保护类的变量和方法的目的。Java支持四种不同的访问权限:private、public、protected和default。
同一个类 | 同一个包 | 不同包的子类 | 任何场合 | |
---|---|---|---|---|
private | √ | |||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
default | √ | √ |
package和import
一、package
包的创建就是将原程序文件中的接口与类纳入指定的包中,创建包可以通过类和接口的源文件使用package语句实现。声明package语句的语法如下:package pk1[.pk2]…
,其中符号“.”代表目录分隔符,pkn为包。
创建一个包就是在当前文件夹下床架一个子文件夹,粗放这个包中包含的所有类的.class文件。Java编译器把包对应于文件系统的目录进行管理,因此包可以嵌套使用。
二、import
将类组织成包的目的是为了更好地利用包中的类,通常,一个类只能引用与它在同一个包中的类,如果要使用其他包中的public类,可以通过两种方式实现:
(1)使用长名导入包中的类,这种方法是在想要导入的每个类名前面加上完整的包名。
(2)使用import语句导入包中的类,语句格式为:
import pkg1[.pkg2]<类名|*>
其中pkg1[.pkg2]
表示包的层次,与package语句相同,它对应于文件的目录,类名指明所要导入的类,“*”可用来导入多个类。
[^1]: abstract类自身没有对象,需要派生子类后再创建对象,而final类不能派生子类,所以不存在用abstract final两个修饰符
[^2]: 类中用来表述研究对象静态特征的变量称为数据成员,也称为成员变量或变量
[^3]: 静态初始化器是由关键字static引导的一对花括号括起来的语法快,其作用是在它所属的类加载到内存时,由系统调用执行,初始化类的静态数据成员。
[^4]: 如果类某个方法被final修饰符所限定,则该类的子类就不能覆盖父类的方法,即不能重新定义与此方法同名的自己的方法,而仅能使用从父类继承来的方法。
[^5]: 构造方法是一个类的方法中方法名与类名相同的类方法。