Java中的对象和类

OOP将数据放在第一位,然后再考虑操作数据的算法。

较小规模的问题 =》 分解为过程的方法;面对对象适合于解决规模较大的问题。

面向过程的数据经常时全局数据;而面对对象则使得每个方法操作所属对象的数据。

面向对象三大特点:封装性(encapsulation)、继承性、多态性

对象中的数据称为实例域(instance field),操纵数据的过程称为方法(method)。

这些实例域值的集合就是这个对象的当前状态(state)

实现封装的关键:绝对不能让类中的方法直接地访问其他类的实例域;

程序仅通过对象的方法与对象数据进行交互。

在Java中,所有的类都源自于一个“神通广大的超类”,它就是Object。

对象

对象的三个主要特性:

  • 对象的行为是用可调用的方法定义的;
  • 每个对象都保存着描述当前特征的信息,这就是对象的状态;
  • 对象的状态并不能完全描述一个对象,每个对象都有一个唯一的身份id,并且对象的关键特性是相互影响的。

依赖(dependence),即“use-a”关系,是一种最明显的、最常见的关系。
如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类;

应该尽可能地将相互依赖的类减至最少。如果类A不知道B的存在,它就不会关心B的任何改变(这意味着B的改变不会导致A产生任何bug)。用软件工程的术语来说,就是让类之间的耦合度最小。

聚合(aggregation),即“has-a”关系,是一种具体且易于理解的关系。聚合关系意味着类A的对象包含类B的对象。

表达类关系的UML图:

继承(inheritance),即“is-a”关系,是一种用于表示特殊与一般关系的。

采用UML(Unified Modeling Language,统一建模语言)绘制类图,用来描述类之间的关系。类用矩形表示,类之间的额关系使用各种修饰的箭头表示

预定义类

在Java中,没有类就无法做任何事情,。然而,并不是所有的类都具有面向对象特征。在程序中可以使用Math类的方法,只需要知道方法名和参数,不必了解具体实现过程。这就是封装性,但是Math类只实现了封装功能(使用了final,无法继承)

对象和对象变量

在Java程序设计语言中,使用构造器(constructor)构造新实例。

构造器的名字应该与类名相同。

定义了一个对象变量deadline,表示它可以引用Date类型的对象。(Date birthday),需要被初始化。

一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。在Java中,任何对象变量的值都是对存储在另外一个地方的一个对象的引用。

new操作符的返回值也是一个引用。表达式new Date()构造了一个Date类型的对象,并且它的值是对新
创建对象的引用。这个引用存储在对象变量deadline中。

可以显式地将对象变量设置为null,表明这个对象变量目前没有引用任何对象;

Java中创建对象的四种方式

  • new操作符
  • 调用对象clone()方法,对现有实例进行拷贝
  • 调用 Class 对象的 newInstance () 方法
  • IO流序列化,使用readObject()反序列化方法,转换为当前类的对象

无论哪一种方式必须经过的一步 --- 调用构造方法。无论怎样构造函数作为初始化类的意义怎样都不会改变。

局部变量不会自动地初始化为null,而必须通过调用new或将它们设置为null进行初始化。

所有的Java对象都存储在堆中。当一个对象包含另一个对象变量时,这个变量依然包含着指向另一个堆对象的指针。

在Java中,必须使用clone方法获得对象的完整拷贝。

Java类库中的LocalDate类

Date类的实例有一个状态,即特定的时间点。类库设计者决定将保存时间与给时间点命名分开。所以标准Java类库分别包含了两个类:一个是用来表示时间点的Date类;另一个是用来表示大家熟悉的日历表示法的LocalDate类。

更改器方法和访问器方法:只访问对象而不修改对象的方法有时称为访问器方法(accessor method);调用更改器方法后,自身对象的状态会改变。

Java编译器内置了make功能,将与主类相关的类进行编译为字节码文件

构造器

关键字public意味着任何类的任何方法都可以调用这些方法

构造器与其他的方法有一个重要的不同。构造器总是伴随着new操作符的执行被调用,而不能对一个已经存在的对象调用构造器来达到重新设置实例域的目的。

所有的Java对象都是在堆中构造的,构造器总是伴随着new操作符一起使用。

隐式参数和显式参数

所有的Java对象都是在堆中构造的,构造器总是伴随着new操作符一起使用

方法用于操作对象以及存取它们的实例域

方法含有隐式参数和显式参数。隐式参数表示当前调用对象(方法调用的目标或接收者)。

在每一个方法中,关键字 this 表示隐式参数。

在Java中,所有的方法都必须在类的内部定义,是否将某个方法设置为内联是Java虚拟机的任务。

注意:不要编写返回引用可变对象的访问器方法。如果需要返回一个可变对象的引用,应该首先对它进行克隆(clone)。对象clone是指存放在另一个位置上的对象副本。

类的方法可以访问所属类的私有特性(feature),而不仅限于访问隐式参数的私有特性。

私有方法

使用案例: 有时,可能希望将一个计算代码划分成若干个独立的辅助方法。通常,这些辅助方法不应该成为公有接口的一部分,这是由于它们往往与当前的实现机制非常紧密,或者需要一个特别的协议以及一个特别的调用次序。最好将这样的方法设计为private的。

对于私有方法,如果改用其他方法实现相应的操作,则不必保留原有的方法。

final实例域

将实例域定义为final, 为在对象构建之后,这个值不会再被修改,即没有setName方法.

final修饰符大都应用于基本(primitive)类型域,或不可变(immutable)类的域(如果类中的每个方法都不会改变其对象,这种类就是不可变的类。例如,String类就是一个不可变的类)。

final关键字只是表示存储在StringBuilder对象变量中的对象引用不会再指示其他StringBuilder对象.而对象本身是可以更改的,也就是对象的状态是可以更改的。

静态方法与静态域

静态域

如果将域定义为static,每个类中只有一个这样的域。而每一个对象对于所有的实例域却都有自己的一份拷贝

在绝大多数的面向对象程序设计语言中,静态域被称为类域。

静态常量

静态变量使用得比较少,但静态常量却使用得比较多。

例如,在Math类中定义了一个PI静态常量, public static final 关键字。

另一个多次使用的静态常量是 System.out

由于每个类对象都可以对公有域进行修改,所以,最好不要将域设计为public。然而,公有常量(即final域)却没问题

静态方法

静态方法是一种不能向对象实施操作的方法,也可以认为静态方法是没有this参数的方法。

静态方法不能访问实例域,因为它不能操作对象。但是,静态方法可以访问自身类中的静态域。

注意:可以使用对象调用静态方法。例如,如果harry是一个Employee对象,可以用harry.getNextId()代替Employee.getNextId()。不过,这种方式很容易造成混淆,其原因是getNextId方法计算的结果与harry毫无关系。我们建议使用类名,而不是对象来调用静态方法。

工厂方法

静态方法还有另外一种常见的用途。类似LocalDate和NumberFormat的类使用静态工厂方法(factory method)来构造对象。

构造方法 or 静态工厂方法:
优点:
静态工厂方法相较于构造器的第一大优势在于它们有名称;
静态工厂方法相较于构造器的第二大优势在于不必在每次调用的时候都重新创建对象;
静态工厂方法相较于构造器的第三大优势在于可以返回原始类型的任何子类型的对象(里氏原则);
缺点:
静态工厂的主要缺点在于类必须含有公有或者受保护的构造器,负责无法被子类化;
静态工厂方法目前提供的帮助文档很少。

构造方法和静态工厂方法

main方法

每个类都可以有一个main方法,用于执行当前类,可以用于单元测试。

如果在更大大应用程序中,那么该类的方法永远不会被执行。

方法参数

按值调用(call by value)表示方法接收的是调用者提供的值。而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。

一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。

Java程序设计语言总是采用按值调用

方法得到的是对象引用的拷贝,对象引用及其他的拷贝同时引用同一个对象。Java程序设计语言对对象采用的不是引用调用,实际上,对象引用是按值传递的。

对象构造

重载

注释:Java允许重载任何方法,而不只是构造器方法。因此,要完整地描述一个方法,需要指出方法名以及参数类型。这叫做方法的签名(signature)。返回类型不是方法签名的一部分。

默认域初始化

如果在构造器中没有显式地给域赋予初值,那么就会被自动地赋为默认值。最好显式赋值。

无参数的构造器

如果在编写一个类时没有编写构造器,那么系统就会提供一个无参数构造器;

重载空构造器,可以将所有域赋予默认值。

显式域初始化

在类定义中,直接将一个值赋给任何域;当一个类的所有构造器都希望把相同的值赋予某个特定的实例域时,这种方式特别有用。

将id域使用静态方法进行初始化,实现id自增。

参数名

老手:有些程序员在每个参数前面加上一个前缀“a”

调用另一个构造器

关键字this引用方法的隐式参数,这个关键字还有另外一个含义。

如果构造器的第一个语句形如this(...),这个构造器将调用同一个类的另一个构造器。

采用这种方式使用this关键字非常有用,这样对公共的构造器代码部分只编写一次;

初始化块

在一个类的声明中,可以包含多个代码块。只要构造类的对象,这些块就会被执行。

运行初始化块 和 执行构造器主体部分 取决于 代码顺序

调用构造器的具体处理步骤!!!:

  1. 所有数据域被初始化为默认值(0、false或null)。
  2. 按照在类声明中出现的次序,依次执行所有域初始化语句和初始化块。
  3. 如果构造器第一行调用了第二个构造器,则执行第二个构造器主体。
  4. 执行这个构造器的主体。

使用一个静态的初始化块来对静态域进行初始化。

对象析构与finalize方法

Java有自动的垃圾回收器,不需要人工回收内存,所以Java不支持析构器。

当然,某些对象使用了内存之外的其他资源,例如,文件或使用了系统资源的另一个对象的句柄。在这种情况下,当资源不再需要时,将其回收和再利用将显得十分重要。

可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清除对象之前调用。在实际应用中,不要依赖于使用finalize方法回收任何短缺的资源。

如果某个资源需要在使用完毕后立刻被关闭,那么就需要由人工来管理。对象用完时,可以应用一个close方法来完成相应的清理操作。

对象析构与finalize方法

Java有自动的垃圾回收器,不需要人工回收内存,所以Java不支持析构器。

当然,某些对象使用了内存之外的其他资源,例如,文件或使用了系统资源的另一个对象的句柄。在这种情况下,当资源不再需要时,将其回收和再利用将显得十分重要。

可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清除对象之前调用。在实际应用中,不要依赖于使用finalize方法回收任何短缺的资源。

如果某个资源需要在使用完毕后立刻被关闭,那么就需要由人工来管理。对象用完时,可以应用一个close方法来完成相应的清理操作。

静态导入

import语句不仅可以导入类,还增加了导入静态方法和静态域的功能。

import static *;

将类放入包中

如果没有在源文件中放置package语句,这个源文件中的类就被放置在一个默认包(defaulf package)中。默认包是一个没有名字的包。

编译器对文件(带有文件分隔符和扩展名.java的文件)进行操作。而Java解释器加载类(带有.分隔符)

包作用域

标记为public的部分可以被任意的类使用;标记为private的部分只能被定义它们的类使用。

如果没有指定public或private,这个部分(类、方法或变量)可以被同一个包中的所有方法访问。

类路径

类文件也可以存储在JAR(Java归档)文件中。

在一个JAR文件中,可以包含多个压缩形式的类文件和子目录,这样既可以节省又可以改善性能。

JAR文件使用ZIP格式组织文件和子目录。可以使用所有ZIP实用程序查看内部的rt.jar以及其他的JAR文件。

为了使类能够被多个程序共享,需要做到下面几点:
1)把类放到一个目录中,例如/home/user/classdir。需要注意,这个目录是包树状结构的基目录。如果希望将com.horstmann.corejava.Employee类添加到其中,这个Employee.class类文件就必须位于子目
录/home/user/classdir/com/horstmann/corejava中。
2)将JAR文件放在一个目录中,例如:/home/user/archives。
3)设置类路径(class path)。类路径是所有包含类文件的路径的集合。

在archives目录中的所有JAR文件(但不包括.class文件)都包含在类路径中。

由于运行时库文件(rt.jar和在jre/lib与jre/lib/ext目录下的一些其他的JAR文件)会被自动地搜索,所以不必将它们显式地列在类路径中。

note: javac编译器总是在当前的目录中查找文件,但Java虚拟机仅在类路径中有“.”目录的时候才查看当前目录。

类路径所列出的目录和归档文件是搜寻类的起始点

设置类路径

最好采用-classpath(或-cp)选项指定类路径;

也可以通过设置CLASSPATH环境变量完成这个操作。其详细情况依赖于所使用的shell。

文档注释

JDK包含一个很有用的工具,叫做javadoc,它可以由源文件生成一个HTML文档

在源代码中添加以专用的定界符/**开始的注释,这种方式可以将代码与注释保存在一个地方。如果将文档存入一个独立的文件中,就有可能会随着时间的推移,出现代码和注释不一致的问题。

注释应该放置在所描述特性的前面。注释以/** 开始,并以 */ 结束。每个 /**... */文档注释在标记之后紧跟着自由格式文本(free-form text)。

javadoc实用程序(utility)从下面几个特性中抽取信息:

  • 标记由@开始,如@author或@param。
  • 自由格式文本的第一句应该是一个概要性的句子,用作概要页。
  • 在自由格式文本中,可以使用HTML修饰符

如果文档中有到其他文件的链接,例如,图像文件(用户界面的组件的图表或图像等),就应该将这些文件放到子目录doc-files中。

类注释

类注释必须放在import语句之后,类定义之前。

没有必要在每一行前面都加一个 * 号。

方法注释

每一个方法注释必须放在所描述的方法之前。

@param 标记对当前方法的参数部分添加一个条目,可占据多行。

@return 对当前方法添加返回部分。

还有标记将添加一个注释,用于表示这个方法有可能抛出异常。

域注释

只需要对公有域(通常指的是静态常量)建立文档。

通用注释

注释标记 含义
@author(类文档) 作者条目
@version(类文档) 当前版本的描述
@since (以下可以出现在所有文档注释中) 对引入特性的版本描述
@deprecated 标记将对类、方法或变量添加一个不再使用的注释
@see 和 @link 用超级链接,链接到javadoc文档的相关部分或外部文档

包与概述注释

要想产生包注释,就需要在每一个包目录中添加一个单独的文件:

  • 提供一个以package.html命名的HTML文件。在标记...之间的所有文本都会被抽取出来。
  • 提供一个以package-info.java命名的Java文件。这个文件必须包含一个初始的以/** 和 */界定的Javadoc注释,跟随在一个包语句之后。它不应该包含更多的代码或注释。

注释的抽取

类设计技巧

1、一定要保证数据私有;

2、一定要对数据初始化;

3、不要在类中使用过多的基本类型

4、不是所有的域都需要独立的域访问器和域更改器

5、将职责过多的类进行分解

6、类名和方法名要能够体现它们的职责
命名类名的良好习惯是采用一个名词(Order)、前面有形容词修饰的名词(RushOrder)或动名词(有“-ing”后缀)修饰名词(例如,BillingAddress)。对于方法来说,习惯是访问器方法用小写get开(getSalary),更改器方法用小写的set开头(setSalary)。

7、优先使用不可变的类
LocalDate类以及java.time包中的其他类是不可变的——没有方法能修改对象的状态。如果类是不可变的,就可以安全地在多个线程间共享其对象。

原文地址:https://www.cnblogs.com/hnxbp/p/15027150.html