弄清楚类与对象的本质与基本特征,是进一步学习面向对象编程语言的基本要求。面向对象程序设计与面向过程程序设计在思惟上存在着很大差异,改变一种思惟方式并非一件容易的事情。html
程序由对象组成,对象包含对用户公开的特定功能部分,和隐藏在其内部的实现部分。从设计层面讲,咱们只关心对象可否知足要求,而无需过多关注其功能的具体实现。面对规模较小的问题时,面向过程的开发方式是比较理想的,但面对解决规模较大的问题时,面向对象的程序设计每每更加合适。java
对象是对客观事物的抽象,类是对对象的抽象,是构建对象的模板。由类构造(construct)对象的过程称为建立类的实例(instance)或类的实例化。编程
封装是将数据和行为组合在一个包中,并对使用者隐藏数据的实现方式。对象中的数据称为实例域(instance field)或属性、成员变量,操纵数据的过程称为方法(method)。对象通常有一组特定的实例域值,这些值的集合就是对象当前的状态。封装的关键在于不让类中的方法直接的访问其余类的实例域,程序仅经过对象的方法与对象数据进行交互。封装可以让咱们经过简单的使用一个类的接口便可完成至关复杂的任务,而无需了解具体的细节实现。oracle
传统的面向过程的程序设计,必须从顶部的 main
入口函数开始编写程序。面向对象程序设计没有所谓的顶部,咱们要从设计类开始,而后再往每一个类中添加方法。那么咱们该具体定义什么样的类?定义多少个?每一个类又该具有哪些方法呢?这里有一个简单的规则能够参考 —— “找名词与动词”原则。编程语言
咱们须要在分析问题的过程当中寻找名词和动词,这些名词颇有可能成为类,而方法对应着动词。固然,所谓原则,只是一种经验,在建立类的时候,哪些名词和动词是重要的,彻底取决于我的的开发经验(抽象能力)。ide
最多见的关系有:依赖(use-a)、聚合(has-a)、继承(is-a)。可使用UML(unified modeling language)绘制类图,用来可视化的描述类之间的关系。函数
在 Java 中没有类就没法作任何事情,Java 标准类库中提供了不少类,这里称其为预约义类,如 Math 类。要注意的是:并不是全部类都具备面向对象的特征(如 Math 类),它只封装了功能,不须要也没必要要隐藏数据,因为没有数据,所以也没必要担忧生成以及初始化实例域的相关操做。工具
要使用对象,就必须先构造对象,并指定其初始状态。咱们可使用构造器(constructor)构造新实例,本质上,构造器是一种特殊的方法,用以构造并初始化对象。构造器的名字与类名相同。如需构造一个类的对象,须要在构造器前面加上 new
操做符,如new Date()
。一般,但愿对象能够屡次使用,所以,须要将对象存放在一个变量中,不过要注意,一个对象变量并无实际包含一个对象,而仅仅是引用一个对象。单元测试
访问器与修改器 咱们把只访问对象而不修改对象状态的方法称为 访问器方法
(accessor method)。若是方法会对对象自己进行修改,咱们称这样的方法称为 更改器方法
(mutator method)。学习
要想建立一个完成的程序,应该将若干类组合在一块儿,其中只有一个类有 main 方法。其它类( workhorse class)没有 main 方法,却有本身的实例域和实例方法,这些类每每须要咱们本身设计和定义。
一个源文件中,最多只能有一个公有类(访问级别为public),但能够有任意数目的非公有类。尽管一个源文件能够包含多个类,但仍是建议将每个类存在一个单独的源文件中。 不提倡用public
标记实例域(即对象的属性),public
数据域容许程序中的任何方法对其进行读取和修改。当实例域设置为 private
后,若是须要对其进行读取和修改,能够经过定义公有的域访问器或修改器来实现。这里要注意:不要编写返回引用可变对象
的访问器方法,如:
class TestClass{ private Date theDate; public getDate(){ return theDate; // Bad } }
上面的访问器返回的是对实例属性 theDate
的引用,这致使在后续能够随意修改当前实例的 theDate
属性,好比执行x.getDate().setTime(y)
,破坏了封装性!若是要返回一个可变对象的引用,应该首先对他进行克隆,以下:
class TestClass{ private Date theDate; public getDate(){ return (Date) theDate.clone(); // Ok } }
构造器
构造器与类同名,当实例化某个类时,构造器会被执行,以便将实例域初始化为所需的状态。构造器老是伴随着 new
操做符的调用被执行,不能对一个已经存在的对象调用构造器来重置实例域。
new
操做一块儿调用基于类的访问权限
方法能够访问所属类的全部对象的私有数据。[*]
在实现一个类时,应将全部的数据域都设置为私有的。多数时候咱们把方法设计为公有的,但有时咱们但愿将一个方法划分红若干个独立的辅助方法,一般这些辅助方法不该该设计成为公有接口的一部分,最好将其标记为 private
。只要方法是私有的,类的设计者就能够确信:他不会被外部的其余类操做调用,能够将其删去,若是是公有的,就不能将其删除,由于其余的代码可能依赖它。
final 实例域
在构建对象时必须对声明的 final 实例域进行初始化,就是说必须确保在构造器执行以后,这个域的值被设置,而且在后面的操做中,不可以再对其进行修改。final
修饰符大都用于基本类型,或不可变类的域。
静态域和静态方法,是属于类且不属于对象的变量和函数。
经过 static
修饰符,能够标注一个域为静态的,静态域属于类,而不属于任何独立的对象,可是每一个对象都会有一份这个静态域的拷贝。静态方法是一种不能对对象施加操做的方法,它能够访问自身类的静态域,类的对象也能够调用类的静态方法,但更建议直接使用类名调用静态方法。
使用静态方法的场景 : 一个方法不须要访问对象状态,其所需参数都是经过显式参数提供;一个方法只须要访问类的静态域。
静态方法还有另一种常见用途,做为工厂方法用以构造对象。之所已使用工厂方法,两个缘由:一是没法命名构造器,由于构造器必须与类名相同;二是当时用构造器时没法改变构造的对象类型。
程序入口 main
方法就是一个典型的静态方法,其不对任何对象进行操做。在启动程序时尚未任何一个对象,静态的 main
方法将执行并建立程序所须要的对象。每一个类均可以有一个 main
方法,做为一个小技巧,咱们能够经过这个方法对类进行单元测试。
Java 中的方法参数老是按值调用,也就是说,方法获得的是全部参数的值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。然而,方法参数有两种类型:基本数据类型和对象引用。
若是在构造器中没有显式的为域赋值,那么域会被自动的赋予默认值:数值为 0、布尔之为 false、对象引用为 null。在类没有提供任何构造器的时候,系统会提供一个默认的构造器。
有些类有多个构造器,这种特征叫作重载(overloading)。若是多个方法有相同的名字、不一样的参数,便产生了重载。 Java 中容许重载任何方法,而不只是构造器方法。要完整的描述一个方法,须要指出方法名以及其参数类型,这个描述被称做方法的签名。
经过重载类的构造器方法,能够采用多种形式设置类的实例的初始状态。当存在多个构造器的时候,也能够在构造器内部经过 this 调用另外一个构造器,要注意的是这个调用必须在当前构造器的第一行:
class Test{ Test(int number) { this(number, (String)number); // 位于当前构造器的第一行 } Test(int number, String str) { _number = number; _string = str; } }
初始化块
在一个类的声明中,能够包含多个代码块。只要构造类的对象,这些块就会被执行。例如:
class Test{ private int number; private String name; /** * 初始化块 */ { number = 5; } Test(){ name = 'Kelsen' } public void pring(){ System.out.println(name + "-" + number); } }
执行顺序为,首先运行初始化块,而后再运行构造器的主体部分。这种机制不是必须的,也不常见。一般会直接将初始化代码放在构造器中。
Java 中不支持析构器,它有自动的垃圾回收器,不须要人工进行内存回收。但,若是某个资源须要在使用完毕后马上被关闭,那么就须要人工来管理。对象用完时能够应用一个 close 方法来完成相应的清理操做。
借助于包,能够方便的组织咱们的类代码,并将本身的代码与别人提供的代码库区分管理。标准的 Java 类库分布在多个包中,包括 java.lang、java.util 和 java.net 等。标准的 Java 包具备一个层次结构。如同硬盘文件目录嵌套同样,也可使用嵌套层次组织包。全部的标准 Java 包都处于 java
和 javax
包层次中。从编译器角度看,嵌套的包之间没有任何关系,每个都拥有独立的类集合。
一个类可使用所属包中的全部类,以及其余包中的公有类(pbulic class)。 import
语句是一种引用包含在包中的类的简明描述。package
与 import
语句相似 C++ 中的 namespace
和 using
指令。
import
语句还能够用来导入类的静态方法和静态域。
若是要将一个类放入包中,就必须将包的名字放在源文件的开头,包中定义类的代码以前。如:
package com.kelsem.learnjava; public class Test{ // ... }
若是没有在源文件中放置 package
语句,这个源文件中的类就被放置在一个默认包中。
包做用域
标记为 private
的部分只能被定义他们的类访问,标记为 public
的部分能够被任何类访问;若是没有指定访问级别,这个部分(类/方法/变量)能够被同一个包中的全部方法访问。
类路径
类存储在文件系统的目录中,路径与包名匹配。另外,类文件也能够存储在 JAR 文件中。为了使类可以被多个程序共享,一般把类放到一个目录中,将 JAR 文件放到一个目录中,而后设置类路径。类路径是全部包含类文件的路径的集合,设置类路径时,首选使用 -calsspath 选项设置,不建议经过设置 CLASSPATH 这个环境变量完成该操做。
JDK 包含一个很是有用的工具,叫作 javadoc 。它经过分析咱们的代码文件注释,自动生成 HTML 文档。每次修源码后,经过运行 javadoc 就能够轻松更新代码文档。Javadoc 功能包括:Javadoc搜索,支持生成HTML5输出,支持模块系统中的文档注释,以及简化的Doclet API。详细使用说明可参考 https://docs.oracle.com/en/java/javase/11/javadoc/javadoc.html
必定要保证数据私有 务必确保封装性不被破坏。
必定要对数据初始化 Java 不会对局部变量进行初始化,但会对对象的实例域进行初始化。最好不要依赖于系统默认值,而是显式的对实例域进行初始化。
不要在类中使用过多的基本类型 经过定义一个新的类,来代替多个相关的基本类型的使用。
不是全部的域都须要独立的域访问器和域更改器
将职责过多的类进行分解 若是明显的能够将一个复杂的类分解为两个更简单的类,就应该将其分解。
类名和方法名要可以体现他们的职责 对于方法名,建议:访问器以小写 get
开头,修改器以小写 set
开头;对于类名,建议类名是采用一个名词(Order)、前面有形容词修饰的名词(RushOrder)或动名词(ing后缀)修饰名词(BillingAddress)。
优先使用不可变的类 要尽量让类是不可变的,固然,也并非全部类都应当是不可变的。