一、面对对象程序设计概述
1.类
类是构造对象的模板。由类构造对象的过程称为创建类的实例。
封装(即隐藏数据):从形式上看,封装不过是将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式。
实例域:对象中的数据。
方法:操作数据的过程。
实现封装的关键在于绝对不能让类中的方法直接的访问其他类的实例。程序仅通过对象的方法与对象的数据进行交互。封装给对象给予了“黑盒”特性,这是提高重用性与可靠性的关键。
可以通过扩展一个类来建立另外一个新的类。Java中,所有的继承Object类。
2.对象
对象的三个主要特性:对象的行为、对象的状态、对象标识。
3.类之间的关系
依赖(“uses-a"):如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。
聚合(”has-a"):聚合关系意味着类A的对象包含类B的对象。
继承(“is-a"):是一种用于表示特殊与一般的关系。一般而言,如果类A扩展类B,类A不但包含从类B继承的方法,还会拥有一些额外的功能。
二、使用预定义类
1.对象与对象变量
要想使用对象,就必须首先构造对象,并指定其初始状态。然后,对对象应用方法。
在Java中,使用构造器构造新实例。构造器是一种特殊的方法,用来构造并初始化对象。构造器的名字应该与类名相同。
想要构造一个Date对象,需要在构造器前面加上new操作符,如 new Date()。
可以将对象传递给一个方法: System.out.println(new Date())。
也可以将一个方法应用与刚刚创建的对象:String s= new Date().toString()。
通常,希望构造的对象可以多次使用,因此需要将对象存放在一个变量中:Date birthday=new Date()。
一个对象变量并没有实际包含一个对象,而仅仅引用了一个对象。(任何对象变量的值都是对存储在另一个地方的一个对象的引用)。
局部变量不会自动地初始化为null,而必须通过调用new或将它们设置为null进行初始化。
2.LocalDate类
不要使用构造器来构造LocalDate对象,实际上,应当使用静态工厂方法代表你调用构造器:LocalDate.now()。
一旦有了一个LocalDate对象,可以用方法getYear,getMonthValue,getDayOfMonth得到年、月、日。
注意LocalDate类与Date类的区别。
3.更改器方法与访问器方法
访问器方法:只访问对象而不修改对象的方法。
更改器方法:不仅访问对象而且修改对象的方法。
三、用户自定义类
在一个源文件中,只能有一个公有类,但可以有任意数目的非公有类。
1.构造器
构造器总是伴随着new操作符的执行被调用,而不能对一个已经存在的对象调用构造器来达到重新设置实例域的目的。
构造器与类同名
每个类可以有一个以上的构造器
构造器可以有0个、1个或多个参数
构造器没有返回值
构造器总是伴随着new操作一起调用
请注意:不要在构造器中定义与实例域重名的局部变量
2.隐式参数与显式参数
显式参数是明显地列在方法声明中,隐式参数没有出现在方法声明中,在每一个方法中this表示隐式参数。
3.封装的优点
在有些时候,需要获得或设置实例域的值,因此,需要提供下面三项内容:
一个私有的数据域
一个公有的域访问器方法
一个公有的域更改器方法
封装的优点:
1.可以改变内部实现,除了该类的方法之外,不会影响其他代码。
2.更改器方法可以执行错误检查,然而直接对域进行赋值将不会进行这些处理。例如:setSalary方法可以检查薪金是否小于0。
注意:不要编写返回引用可变对象的访问器方法
4.基于类的访问权限
方法可以访问所属类的私有特性,而不仅限于访问隐式参数的私有特性。
5.final实例域
可以将实例域定义为final。构建对象时必须初始化这样的域。也就是说,必须确保在每一个构造器执行之后,这个域的值被设置,并且在后面的操作中,不能够对他进行修改。 即没有setName方法。
final修饰符大都应用于基本类型域,或不可变类的域(如果类中的每个方法都不会改变其对象,这种类就是不可变类。如String)
对于可变的类,使用final修饰符可能会对读者造成混乱,如:
private final StringBuilder a;
在构造器中会初始化为
a=new StringBuilder();
final关键字只是表示存储在a变量中的对象引用不会再指示其他StringBuilder对象,不过这个对象可以更改。如:
a.append(LocalDate.now()+":Gikd star!")
四、静态域与静态方法
1.静态域(类域)
如果将域定义为static,则每个类只有一个这样的静态域,而对于实例域则每个对象都有一份拷贝。即每个对象拥有自己的实例域,但共享同一个静态域。即使没有对象,静态域也存在,它属于类,而不属于任何独立的对象。
2.静态常量
静态变量使用得比较少,静态常量却使用得比较多。例如在Math 类中定义一个PI,另一个使用比较多的静态常量是System.out。
3.静态方法
静态方法是一种不能向对象实施操作的方法。
静态方法不能访问对象的实例域,只能访问自身类中的静态域。
可以认为静态方法是没有this参数的方法
可以使用对象调用静态方法,但建议使用类名.方法名的方式代替对象引用.方法名的方式调用方法。
下面两种情况下使用静态方法:
一个方法不需要访问对象状态,其所需参数都是通过显式参数提供(例如:Math.pow)。
一个方法只需要访问类的静态域(例如:Employee.getNextId)。
4.工厂方法
静态方法还有另外一种常见的用途,类似LocalDate和NumberFormat的类使用静态工厂方法来构造对象。
为什么考虑用工厂方法替代构造方法?可参考下方
考虑使用静态工厂方法替代构造方法 - 风一样的码农 - 博客园
5.main方法
main方法不对任何对象进行操作。事实上,在启动程序时还没有任何一个对象。静态的main方法将执行并创建程序所需要的对象。
五、方法参数
Java 程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。
总结Java中方法参数的使用情况:
一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)。
一个方法可以改变一个对象参数的状态。
一个方法不能让对象参数引用一个新的对象。
六、对象构造
1.重载
如果多个方法有相同的名字、不同的参数,便产生了重载。
Java允许重载任何方法,而不只是构造器方法。
要完整的描述一个方法,需要指出方法名以及参数类型。这叫做方法的签名。如indexOf(int,int)是签名
返回类型不是方法签名的一部分,也就是说,不能有两个名字相同、参数类型也相同却返回不同类型值的方法。
2.默认域初始化
如果在构造器中没有显式地给域赋予初值,那么就会被自动地赋为默认值,数值为0、布尔值为false、对象引用为null(这是域与局部变量地主要不同点,必须明确地初始化方法中的局部变量)
3.无参数的构造器
如果在编写一个类时没有编写构造器,那么系统就会提供一个无参数构造器。这个构造器将所有的实例域设置为默认值。
如果类中提供了至少一个构造器,但是没有提供无参数的构造器,则在构造对象时如果没有提供参数就会被视为不合法。
即仅当类没有提供任何构造器的时候,系统才会提供一个默认的构造器。
4.显示域初始化
可以在类定义中,直接将一个值赋给任何域,在执行构造器之前,先执行赋值操作。当一个类的所有构造器都希望把相同的值赋予某个特定的实例域时,使用这种方法特别有用。
初始值不一定是常量值,可以调用方法对域进行初始化。
5.调用另一个构造器
如果构造器的第一个语句形如this(...),这个构造器将调用同一个类的另一个构造器。
采用这种方式使用this关键字非常有用,这样对公共的构造器代码部分之编写一次。
6.初始化块
Java 中三种初始化域的方法: 1.在构造器中设置 2.在声明中赋值 3.初始化块
只要构造类的对象,初始化块就会被执行。首先运行初始化块,然后才运行构造器的主体部分。
建议将初始化块放在域定义之后。
在类第一次加载的时候,将会进行静态域的初始化。所有的静态初始化语句以及静态初始化块都将依照类定义的顺序执行。
7.对象构析与finalize方法
可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清除对象之前调用。在实际应用中,不要依赖于使用finalize方法回收任何短缺的资源。
如果某个资源需要在使用完毕后立刻被关闭,那么就需要人工来管理。对象用完时可以应用一个close方法来完成相应的清理操作。
七、类设计技巧
一定要保证数据私有
一定要对数据初始化
不要在类中使用过多的基本类型
不是所有的域都需要独立的域访问器和域更改器
将职责过多的类进行分解
类名和方法名要能够体现它们的职责
优先使用不可变的类