- 面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。(Object Oriented Programming)
- 在OOP中,不必关心对象的具体实现,只要能够满足用户的需求即可。
- 在OOP中,将数据放在第一位,然后再考虑操作数据的算法。
- 封装(encapsulation):隐藏数据,不必了解具体实现如何操纵数据。
- 对象中的数据:实例域。操纵数据的过程:方法。
- 实现封装的关键在于:绝不能让类中的方法直接访问其他类的实例域。
- 程序仅通过对象的方法与对象数据进行交互。
- OOP的另一原则,可以通过扩展一个类来建立另外一个新的类:继承。
- 对象的三个主要特性:行为、状态 和 标识。
- 行为:可以对对象施加什么方法。
- 状态:被施加方法时,如何响应。(必须通过调用方法,才可能发生状态改变)
- 标识:辨别同行为同状态的不同对象。(作为一个类的实例,每个对象的标识永远是不同的)
- 识别类的简单规则:在分析问题的过程中寻找名词,而方法对应着动词。
- 在创建类的时候,哪些名词和动词是重要的完全取决于个人的开发经验。
- 类之间的关系:依赖、聚合 和 继承。
- 依赖(use-a):如果一个类A的方法操纵另一个类B的对象,那么A依赖于B。尽可能将相互依赖的类减至最少。(使得耦合度最小)
- 聚合(has-a):类A的对象包含类B的对象。
- 继承(is-a):表示特殊与一般的关系。
- UML(Unified Modeling Language)绘制类图。
- 对象变量:一个对象变量并没有实际包含一个对象,而仅仅引用了一个对象。可以将Java的对象变量看作C++的对象指针。
- 局部变量不会自动地初始化为null,而必须通过调用new或者将它们设置为null进行初始化。
- 所有的Java对象都存储在堆中。
- Java中,若使用一个未初始化的指针,运行系统将产生一个运行时错误,而不是生成一个随机的结果。
- 在Java中,必须使用clone方法获得对象的完整拷贝。
- LocalDate类:日历表示法的类。(Date类:用来表示时间点。)将时间和日历分开是一种很好的OOP设计,通常,最好使用不同的类表示不同的概念。
- 更改器方法(mutator method) 与 访问器方法(access method)。在Java中,访问器方法与更改器方法在语法上没有明显的区别。
- Java.time.LocalDate:
- static LocalDate now()
- static LocalDate of( int year , int month, int day )
- int getYear()
- int getMonthValue()
- int getDayOfMonth()
- DayofWeek getDayOfWeek()
- LocalDate plusDays( int n )
- LocalDate minusDays( int n )
- 示例程序(构造一个简单的日历,当前的日期用*号标识)
package coreJava_chap4;
import java.time.*;
/*
*@lastEdited 2020-7-21
*@author 迷途小书童
*/
public class Test4_1 {
public static void main( String args[] ) {
LocalDate thisDate = LocalDate.now();
int thisYear = thisDate.getYear();
int thisMonth = thisDate.getMonthValue();
int today = thisDate.getDayOfMonth();
LocalDate curDate = LocalDate.of( thisYear, thisMonth, 1 );
int day = curDate.getDayOfWeek().getValue();
System.out.println("Mon Tue Wed Thu Fri Sat Sun ");
for( int i = 1; i < day; i++ )
System.out.print(" ");
while( curDate.getMonthValue() == thisMonth ) {
System.out.printf("%3d", curDate.getDayOfMonth());
if( curDate.getDayOfMonth() == today ) System.out.print("*");
else System.out.print(" ");
curDate = curDate.plusDays(1);
if( curDate.getDayOfWeek().getValue() == 1 )
System.out.println();
}
if( curDate.getDayOfWeek().getValue() != 1 ) System.out.println();
}
}
- 主力类:(workhorse class)。通常,这些类没有main方法,却有自己的实例域和实例方法。
- 文件名必须与public类的名字相匹配。
- 在一个源文件中,只能有一个公有类,但可以有任意数目的非公有类。
- 构造器:与类同名 至少一个 参数不限 无返回值 总是伴随着new操作一起调用。
- 不要在构造器中定义与实例域重名的局部变量。
- 关键字this表示隐式(implict)参数。
- (访问器)如果需要返回一个可变对象的引用,应首先对它进行克隆。否则就可能通过这个引用改变对象的私有状态。
- 一个方法可以访问所属类的所有对象的私有数据,而不仅限于访问隐式参数的私有特性。
- 私有方法。(辅助方法)若用其他方式代替私有方法的实现,私有方法可以放心的删去。
- 若实例域定义为final,那么构建对象的时必须初始化这样的域。final实例域一般应用于基本类型和不可变的类。
- 对于被final定义的对象示例域,对象是可变的,但是对象引用不可变。
- 静态域与静态方法:关键字static表示该域或者方法是属于类的,而不是属于任何独立的对象。
- 静态方法:无隐式参数,不使用任何对象。两种情况下使用静态方法:1.不需访问对象状态 2.只需访问静态域
- 静态方法的另一常见用途:工厂方法。工厂方法相比于构造器的优势:1.构造器必须与类名同名 ,构造含义更清晰 2.可以返回子类的对象示例。
- Java中,总是采用按值调用。(call by value)。所以,1.一个方法不能修改一个基本数据类型的参数 2.一个方法可以改变对象参数的状态 3.一个方法不能让对象参数引用一个新的对象。
- 重载。方法的签名:方法名+参数类型。
- 默认域初始化:如果在构造器中没有显示地给域赋值,那么就会被自动赋值为默认值(0,false, null)
- 如果没有编写构造器,那么系统会提供一个无参数的构造器。
- 显式域初始化:可以在类定义中,直接将一个值赋给任何域(直接定义赋值初始化),也可以调用方法对域进行初始化。
- 构造器可以利用this指针调用另一个构造器。
- 初始化数据域的三种机制:1.构造器 2.声明中赋值 3.初始化块(非必须,不常见)
- 调用构造器的具体处理步骤:1.所有数据初始化成默认值 2.依次处理 域初始化语句 、 初始化块 3.构造器语句
- 如果对类的静态域进行的初始化比较复杂,那么可以使用静态的初始化块。
//静态的初始化块示例
static
{
//Java.util.Random
Random generator = new Random();
nextId = generator.nextInt(10000);
}
- 对象析构域finalize方法:
- Java不支持析构器
- 可以为任一个类添加finalize方法,finalize方法将在垃圾回收器清除对象之前调用。但不要依赖于使用finalize,因为不能够具体确定什么时候会调用这个finalize方法。
- 如果某个资源需要在使用完毕后立刻被关闭,那么就需要由人工来管理。对象用完时,可以应用一个close方法来完成相应的清理操作。
- Java允许使用包(package)将类组织起来。将自己的代码与别人提供的代码库分开管理。
- 使用包的主要原因是确保类名的唯一性。同类名但是放置于不同的包,不会发生冲突。从编译器的角度出发,嵌套的包之间无任何关系。
- 所有标准的Java包都处于 java 和 javax 包层次中。
- 一个类可以使用所属包中的所有类,以及其他包中的公有类。
- 只能用*导入一个包。
- import还可以导入静态方法和静态域的功能,程序中使用可以省略包名。但是如果命名发生冲突,那么包名就不可以省略。
- 编译器不检查目录结构,如果包与目录不匹配,虚拟机就找不到类。
- 禁止加载用户自定义的、包名以"java."开头的类。
- 包作用域:1.public可以被任意的类使用。 2.private只能被定义它们的类使用(本类使用) 3.没有指定public或者private的,可以被同包中所有方法访问。
- 注释的插入:
- 类注释:必须放在import语句之后,类定义之前
- 方法注释:所描述的方法之前
- 域注释:只需对公有域(通常是静态常量)建立文档
- 通用注释
- 包与概述注释
- 类设计技巧:
- 一定要保证数据私有。
- 一定要对数据初始化。
- 不要在类中使用过多的基本类型(如果某些基本类型存在关联,则用一个类将它们管理起来)。
- 不是所有的域都需要独立的域访问器和域修改器。
- 将职责过多的类进行分解。
- 类名和方法名要体现它们的职责。
- 优先使用不可变的类(若多个线程试图同时更新一个对象,就会发生并发更改,结果不可预料)
- 示例程序4-2:创建Employee类员工对象,每个员工加薪10%,打印每个员工的信息。
package coreJava_chap4;
import java.time.LocalDate;
import static java.lang.System.*;
/*
*@lastEdited 2020-7-24
*@author 迷途小书童
*/
public class Test4_2 {
public static void main( String args[] ) {
Employee[] staff = new Employee[3];
staff[0] = new Employee( "Jack", 3000, 2002, 11, 10 );
staff[1] = new Employee( "Dick", 5000, 2012, 2, 24 );
staff[2] = new Employee( "Wade", 8000, 2005, 3, 18 );
for( Employee e : staff )
e.raiseSalary(10);
for( Employee e : staff )
out.println(e);
}
}
class Employee {
private String name;
private double salary;
private LocalDate hireDay;
Employee( String name, double salary, int year, int month, int day ){
this.name = name;
this.salary = salary;
hireDay = LocalDate.of( year, month, day );
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public LocalDate getHireDay()
{
return hireDay;
}
public void raiseSalary( double byPercent )
{
double add = salary * byPercent /100;
salary += add;
}
public String toString()
{
String res = "";
res = res + "name: " + name + ", salary: " + salary + ", hireDay: "+ hireDay.toString();
return res;
}
}
- 示例程序:(设置静态与非静态的初始化块,并用不同的构造器构造三个员工对象,打印信息)
package coreJava_chap4;
import java.util.*;
import static java.lang.System.*;
/*
*@lastEdited 2020-7-24
*@author 迷途小书童
*/
public class Test4_5 {
public static void main(String args[] ) {
Employee[] staff = new Employee[3];
staff[0] = new Employee("Jack",8000);
staff[1] = new Employee( 5000 );
staff[2] = new Employee();
for( Employee e : staff ) {
out.println( e );
}
}
}
class Employee{
private static int nextId;
private String name = "";
private int id;
private double salary;
//静态域初始化
static
{
Random generator = new Random();
nextId = generator.nextInt(1000);
}
//块初始化
{
id = nextId;
nextId++;
}
public Employee(String n, double s){
name = n;
salary = s;
}
public Employee( double s ){
this( "Employee#" + nextId, s );
}
public Employee() {
}
public static int getNextId() {
return nextId;
}
public String toString() {
return "name: " + name + ", id: " + id + ", salary: " + salary;
}
}