1.面向对象程序设计概述
简述
1)面向对象程序设计简称OOP
2)Java是完全面向对象的
3)OOP程序由对象组成
4)对象包含 对用户公开的特定功能和隐藏实现的部分
5)首先决定如何组织数据,再确定如何操作数据
类
1)类是构造对象的模板和蓝图
2)由类构建(construct)对象的过程成为创建类的实例(instance)
3)封装是与对象的一个重要概念
形式上:
将数据和行为组合到一个包中,对使用者隐藏数据的实现
对象中数据称为实例域
操作数据的过程叫做方法
每一个对象都有特定的实例域值,这些值的集合就是这个对象的当前状态。
只要想对象发送一个信息,他的状态就有可能会改变。
4)实现封装的关键在于绝对不能让类中的方法直接的访问其他类的实例域,仅通过对象的方法和对象数据进行交互。
5)Java中所有的类都源于一个超类-Object
对象
使用OOP需要清楚对象的三个主要特性
- 对象的行为:可以对对象进行的操作和方法
- 对象的状态:进行操作后,对象怎么响应
- 对象的标识:辨别具有相同行为域状态的不同对象
1)对象的行为是用可调用的方法定义的
2)对象的状态是描述当前特征的信息决定的,状态的改变必然是调用方法实现的。否则只能说封装性被破坏
3)对象的状态不能完全描述一个类,每个对象都有一个唯一的身份(identity),即两个所订购的货物完全一样,状态也会存在差异
识别类
1)传统过程化设计是main开始的,在面向对象程序设计时没有所谓的顶部。
所以先要学习的是设计类,再往类中添加方法。
类之间的关系
类之间对常见的关系
- 依赖 uses-a
- 聚合 has-a
- 继承 is-a
1)依赖是最明显常见的。如果一个类的方法操作另一个类的对象,我们就说一个类依赖于另一个类,应该尽可能的减少依赖
2)聚合意味着类A的对象包含B的对象
3)继承是类A扩展类B,类A不但包含从类B中继承的方法,还会拥有一些额外的功能
2.使用预定义类
对象与对象变量
1)要想使用对象,必须构造对象,并制定其初始状态。
2)Java中使用构造器(constructor)构造新实例,构造器是一种特殊方法,用来构造并初始化对象
3)构造器的名字与类名相同
4)构造一个对象需要用到new关键字 如new Date();
5)对象可以多次使用,因此需要将对象存放到变量中 如Date birthday = new Date();
6)对象与对象变量之间的区别
对象变量不是一个对象,让这个变量引用一个已存在的对象/初始化给他。且对象变量不是包含对象,而是引用对象。
7)若将方法应用于一个null对象(没有初始化,没有指定引用),就会产生运行时错误。
java库中的LocalDate类
1)Date类的实例有一个状态,即特定的时间点
Date阳历的固定写法,但是中国的农历表现就不一样,所以保存时间,和时间点命名分开
分为两个类
Date() 表示时间点的类
LocalDate() 表示日历的类
2)plusDays会得到一个新的日期,如果把应用这个方法对象称为当前对象,这个新的日期对象则是距当前对象制定天数的一个新日期。
变更器方法和访问器方法
// newYearsEve并没有增加1000天而是生成了一个新的LocalDate对象,并把新的对象引用给了aThousandDaysLater
LocalDate aThousandDaysLater = newYearsEve.plusDays(1000);
1)只访问对象而不修改对象的方法叫做访问器方法
2)调用方法后 对象的状态变更,就是一个变更器方法
3.用户自定义类
通常只有一个类有main,要创建一个完整的程序。应该将若干类组合在一起。每个类都有自己的实例域和实例方法。
以下例子Employee类
package bean;
import java.time.LocalDate;
public class Employee {
private String name;
private Double salary;
private LocalDate hireDay;
// 包含四个方法 一个构造器
// 首先这里的构造器是与类名相同的,构造器运行,实例域初始化。构造器总是伴随着new操作符的执行被执行的
// 构造器没有返回值
public Employee(String name, Double salary, Integer year, Integer month, Integer day) {
this.name = name;
this.salary = salary;
this.hireDay = LocalDate.of(year,month,day);
}
// 这里的显示参数就是raiseSalary,隐式参数是salary,隐式参数是方法名前的对象之中即employee.raisSalary(100);的employee对象
// 推荐使用this标识隐式参数
public void raisSalary(double byPercent) {
double raise = this.salary * byPercent / 100;
salary += raise;
}
// 只返回实例域值,所以又叫做域访问器
// 获取和设置实例域的值
// 1提供一个私有数据域
// 2一个公有的域访问器方法
// 3一个公有的域更改器方法
// 做到以上几点将可以保障封装不被破坏
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public LocalDate getHireDay() {
return hireDay;
}
public void setHireDay(LocalDate hireDay) {
this.hireDay = hireDay;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
", hireDay=" + hireDay +
'}';
}
}
拥有main方法的类
import bean.Employee;
import java.lang.reflect.Array;
import java.util.Arrays;
public class HelloWorld {
public static void main(String[] args) {
Employee[] staff = new Employee[3];
staff[0] = new Employee("Carl Cracker", 70000.00, 1987, 12, 15);
staff[1] = new Employee("Harry Hacker", 50000.00, 1989, 10, 1);
staff[2] = new Employee("Tony Tester", 40000.00, 1990, 3, 15);
for (Employee employee : staff)
employee.raisSalary(100);
for (Employee employee : staff)
System.out.println("name = "+ employee.getName() + ",salary = " + employee.getSalary() + ",hireDay = " + employee.getHireDay());
}
}
运行结果
name = Carl Cracker,salary = 140000.0,hireDay = 1987-12-15
name = Harry Hacker,salary = 100000.0,hireDay = 1989-10-01
name = Tony Tester,salary = 80000.0,hireDay = 1990-03-15
私有方法
1)公有数据很危险,数据域设为私有
2)私有的实现public->private
3)如果是私有的就不会被其他类调用,即使删除也可以。公有就会被其他类依赖
final实例域
1)如果用了final定义了,那么这个域值被初始化后不能被变更,即没有set方法
4.静态域与静态方法
静态域
1)域定义为static后,每个类中只有一个这样的域,即可以有多个静态的变量,但是不管你New出这个类的多少个对象,所有的对象都共享这一个静态的变量,与多少个对象无关。
它属于类,而不属于任何一个独立的对象
静态常量
即static + final 可以直接类名点静态常量来获的这个常量,如果static 没有了就要通过对象来获取了。之前说过不要将域pulic公开出去,但是static + final 就没有这个问题。
静态方法
1)静态方法是不能向对象实施操作的方法
2)静态方法没有隐式参数
两种情况需要使用静态方法
1)一个方法不需要访问对象状态,其所需参数都是通过显示参数提供
2)一个方法只需要访问类的静态域
5.方法参数
1)按值调用:接收的是调用者提供的值
2)按引用调用:接收的是调用着提供的地址
3)Java总是按值调用
4)当是引用类型的时候可以变更一个对象
5)当是基础数据类型的时候不能修改
6)对象参数不能引用一个新的对象。
6.对象构建
多种编写构造器的机制
- 重载
例子
StringBuilder message = new StringBuilder();
StringBuilder todoList = new StringBuilder("TO do:\n");
以上就是构造器的重载,相同名字,不同参数。就是重载
-
默认域的初始化
构造器没有显示的给域赋初值,会被自动赋值数值0 布尔false 对象null。这是不好的,需要手动的赋值而不能使用默认的初始化 -
无参数的构造器
对象由无参数构造器构造,构造器将把所有的实例域设置为默认值。
在默认情况下系统会提供一个默认的无参构造器,但是如果给出了一个构造器,那么系统将不会默认提供。 -
显示域初始化
通过不同的重载,可以设置多种形式的实例域初始状态。 -
参数名
可以使用this的形式访问实例域即
this.name = name; -
调用另一个构造器
通过this关键字来调用其他的构造器
public Employee(double s){
// calls Employee(String, double)
this("String Value",s)
}
-
初始化块
初始化数据域
1)构造器中设置
2)在声明中赋值
第三种就是初始化块。这并不是一种常见的方式
{
id= nextId;
nextId++
}
因为运行顺序是先运行初始化块,在运行构造器的主体部分。所以也起到了赋值的作用 -
对象析构与finalize方法
java有自动回收机制,所以不支持析构器
当使用内存外的资源,可以为任何一个类添加finalize方法。这个方法是在垃圾回收机制之前调用,但是不能依赖这个方法,因为很难知道这个方法什么时候才能够被调用。
使用Runtime.addShutdownHook添加关闭钩来代替
7.包
Java允许使用包来将类组织起来。借助包可以方便的组织自己的代码,并将自己的代码与别人提供的代码库分开管理。
所有的标准java包都在java和javax包层次中。
使用包的主要原因是确保类包的唯一性。
-
类的导入
一个类可以使用所属包中的所有类,已经其他包中的public类。
两种方式访问另一个包中的public类
1)类前添加完整的包名
java.time.LocalDate today = java.time.LocalDate.now();
2)使用import关键字。 -
静态导入
import 不仅可以导入类,还增加了导入静态方法和静态域的功能
例如
import static java.lang.System.*;
就可以使用System类的所用静态方法和静态域不需要加类名前缀。
out.println(“xxxx”); -
包的作用域
public 可以被其他包调用
private 只可以被定义他的类使用
没有指定public和priavte的可以被同一个包下的所有方法访问。
8.文档注释
不做介绍了
9.类设计技巧
1一定要保证数据的私有
2一定要对数据初始化
3不要再类种使用过多的基础变量
4不是所有的域都需要独立的域访问器和域改变器
5将职责过多的类进行分解
6类名和方法要能够体现他们的职责
7优先使用不可变的类