学习面向对象内容的三条主线:
- Java 类及类的成员:属性、方法、构造器、代码块、内部类
- 面向对象的特征:封装、继承、多态、(抽象)
- 其他关键字的使用:
this
、super
、package
、import
、static
、final
、interface
、abstract
等
面向对象编程概述
程序设计的思路
面向对象,是软件开发中的一类编程风格、开发范式。除了面向对象,还有面向过程、指令式编程和函数式编程。在所有的编程范式中,我们接触最多的还是面向过程和面向对象两种。
- 面向过程的程序设计思想(Process-Oriented Programming),简称 POP
- 关注的焦点是过程,过程就是操作数据的步骤。如果某个过程的实现代码重复出现,那么就可以 把这个过程抽取为一个函数。这样就可以大大简化冗余代码,便于维护
- 典型的语言:C
- 代码结构:以函数为组织单位
- 是一种“执行者思维”,适合解决简单问题。扩展能力差、后期维护难度较大。
- 面向对象的程序设计思想(Object Oriented Programming),简称 OOP
- 关注的焦点是类:在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽 象出来,用类来表示
- 典型的语言:Java、C#、C++、Python、Ruby、PHP 等
- 代码结构:以类为组织单位。每种事物都具备自己的属性和行为/功能。
- 是一种“设计者思维”,适合解决复杂问题。代码扩展性强、可维护性高。
由实际问题考虑如何设计程序
思考 1:如何开车?
面向过程思想思考问题时,我们首先思考“怎么按步骤实现?”并将步骤对应成方法,一步一步,最终完 成。这个适合简单任务,不需要过多协作的情况。针对如何开车,可以列出步骤:
- 点火启动
- 踩离合、挂档
- 松离合、踩油门
- 行进
面向过程适合简单、不需要协作的事务,重点关注如何执行。
思考 2:如何造车?
造车太复杂,需要很多协作才能完成。此时我们思考的是“车怎么设计?”,而不是“怎么按特定步骤造车”的问题。这就是思维方式的转变,前者就是面向对象思想。所以,面向对象(Oriented-Object)思想更契合人的思维模式。
用面向对象思想思考“如何设计车”
自然地,我们就会从“车由什么组成”开始思考。发现,车由如下结构组成:
我们找轮胎厂完成制造轮胎的步骤,发动机厂完成制造发动机的步骤,…;这样,大家可以同时进行车的制造,最终进行组装,大大提高了效率。但是,具体到轮胎厂的一个流水线操作,仍然是有步骤的,还是离不开面向过程思维!
因此,面向对象可以帮助我们从宏观上把握、从整体上分析整个系统。但是,具体到实现部分的微观操作(就是一个个方法),仍然需要面向过程的思路去处理。
注意:我们千万不要把面向过程和面向对象对立起来。他们是相辅相成的。面向对象离不开面向过程!
当需求单一,或者简单时,我们一步步去操作没问题,并且效率也挺高。
可随着需求的更改,功能的增多,发现需要面对每一个步骤很麻烦了,这时就开始思索,能不能把这些步骤和功能进行封装,封装时根据不同的功能,进行不同的封装,功能类似的封装在一起。这样结构就清晰了很多。用的时候,找到对应的类就可以了。这就是面向对象的思想。
Java 语言的基本元素:类和对象
类(Class)和对象(Object)是面向对象的核心概念
- 类:具有相同特征的事物的抽象描述,是抽象的、概念上的定义
- 对象:实际存在的该类事物的每个个体 ,是具体的,因而也称为实例(instance)
类的成员
Java 中,类是“一等公民”
类是一组相关属性和行为的集合
- 属性:该类事物的状态信息。对应类中的成员变量(属性、Field)
- 行为:该类事物要做什么操作,或者基于事物的状态能做什么。对应类中的成员方法(函数、Method)
面向对象完成功能的三步骤
步骤 1:类的定义
格式:
[修饰符] class 类名 {
属性声明;
方法声明;
}
// 举例
public class Person {
// 声明属性 age
int age;
// 声明方法 eat()
public void eat() {
System.out.println("人吃饭");
}
}
步骤 2:对象的创建
创建对象,使用关键字:new
格式:
// 方式 1: 给创建的对象命名
// 把创建的对象用一个引用数据类型的变量保存起来,这样就可以反复使用这个对象了
类名 对象名 = new 类名();
// 方式 2: 匿名对象
new 类名();
步骤 3:对象调用属性或方法
对象是类的一个实例,必然具备该类事物的属性和行为。
使用”对象名.属性”或”对象名.方法” 的方式访问对象成员(包括属性和方法)
// 命名对象
Person per = new Person();
per.age = 18
System.out.println(per.age);
// 匿名对象
(new Person()).eat();
匿名对象(anonymous object):
- 如果一个对象只需要进行一次方法调用,那么就可以使用匿名对象。
- 我们经常将匿名对象作为实参传递给一个方法调用。
对象的内存解析
我们主要关心的是运行时数据区部分(Runtime Data Area),其中:
- 堆(Heap):此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在 Java 虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。不需要时需要 GC 回收。
- 栈(Stack):是指虚拟机栈。虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各 种基本数据类型(
byte
、short
、int
、long
、float
、double
、char
、boolean
)、对象引用(reference 类型,它不等同于对象本身,是对象在堆内存的首地址)。方法执行完,自动释放。 - 方法区(Method Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的 代码等数据。
说明:
- 凡是
new
出来的结构(对象、数组)都放在堆空间中 - 对象的属性存放在堆空间中
- 创建一个类的多个对象(比如
p1
、p2
),则每个对象都拥有当前类的一套“副本”(即属性)。当通过一个对象修改其属性时,不会影响其它对象此属性的值 - 当声明一个新的变量使用现有的对象进行赋值时(比如
p3 = p1
),此时并没有在堆空间中创建新的对象。而是两个变量共同指向了堆空间中同一个对象。当通过一个对象修改属性时,会影响另外一个对象对此属性的调用。
面试题:对象名中存储的是什么呢?
答:对象地址
public class StudentTest {
public static void main(String[] args){
System.out.println(new Student()); // Student@7852e922
Student stu = new Student();
System.out.println(stu); // Student@4e25154f
int[] arr = new int[5];
System.out.println(arr); // [I@70dea4e
}
}
直接打印对象名和数组名都是显示“类型@对象的 hashCode 值”,所以说类、数组都是引用数据类型,引用数据类型的变量中存储的是对象的地址,或者说指向堆中对象的首地址。
类的成员之一:成员变量(field)
格式:
[修饰符1] class 类名 {
[修饰符2] 数据类型 成员变量名 [= 初始化值];
}
说明:
- 位置要求:必须在类中,方法外
- 修饰符 2:
- 权限修饰符:
private
、缺省、protected
、public
- 其他修饰符:
static
、final
- 权限修饰符:
- 数据类型:任何基本数据类型或任何引用数据类型
- 成员变量名:属于标识符,符合命名规则和规范即可
- 初始化值:根据情况,可以显式赋值;也可以不赋值,使用默认值
成员变量 VS. 局部变量
- 在方法体外,类体内声明的变量称为成员变量
- 在方法体内部等位置声明的变量称为局部变量
相同点:
- 变量声明的格式相同:
数据类型 变量名 = 初始化值;
- 变量必须先声明、后初始化、再使用
- 变量都有其对应的作用域,只在其作用域内是有效的
不同点:
- 声明位置和方式
- 成员变量:在类中方法外
- 局部变量:在方法体中或方法的形参列表、代码块中
- 在内存中存储的位置
- 成员变量:堆
- 局部变量:栈
- 生命周期
- 成员变量:和对象的生命周期一样,随着对象的创建而存在,随着对象被 GC 回收而消亡,而且每一个对象的实例变量是独立的
- 局部变量:和方法调用的生命周期一样,每一次方法被调用而在存在,随着方法执行的结束而消亡,而且每一次方法调用都是独立
- 作用域
- 成员变量:通过对象就可以使用,本类中直接调用,其他类中“对象.实例变量”
- 局部变量:出了作用域就不能使用
- 修饰符
- 成员变量:
public
、protected
、private
、final
、volatile
、transient
等 - 局部变量:
final
- 成员变量:
- 默认值
- 成员变量:有默认值,为各个类型的“零值”
- 局部变量:没有,必须手动初始化。其中的形参比较特殊,靠实参给它初始化。
类的成员之二:方法(method)
方法的理解
- 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
- 将功能封装为方法的目的是可以实现代码重用,减少冗余,简化代码
- Java 里的方法不能独立存在,所有的方法必须定义在类里
举例:
Math.random()
的random()
方法Math.sqrt(x)
的sqrt(x)
方法System.out.println(x)
的println(x)
方法new Scanner(System.in).nextInt()
的nextInt()
方法Arrays
类中的binarySearch()
方法、sort()
方法、equals()
方法
如何声明方法
格式:
[修饰符] 返回值类型 方法名([形参列表]) [throws 异常列表] {
// 方法体的功能代码
}
一个完整的方法 = 方法头 + 方法体
- 方法头:
[修饰符] 返回值类型 方法名([形参列表]) [throws 异常列表]
,也称为方法签名。通常调用方法时只需要关注方法头就可以,从方法头可以看出这个方法的功能和调用格式。 - 方法体:方法被调用后要执行的代码。对于调用者来说,不了解方法体如何实现的,并不影响方法的使用。
方法头可能包含 5 个部分:
- 修饰符:可选的。方法的修饰符有很多,例如:
public
、protected
、private
、static
、abstract
、native
、final
、synchronized
等,后面会一一学习。- 其中,权限修饰符有
public
、protected
、private
。在讲封装性之前,我们先默认使用pulbic
修饰方法。 - 其中,根据是否有
static
,可以将方法分为静态方法和非静态方法。其中静态方法又称为类方法,非静态方法又称为实例方法。
- 其中,权限修饰符有
- 返回值类型:表示方法运行的结果的数据类型,方法执行后将结果返回到调用者。
- 无返回值,则声明为
void
- 有返回值,则声明出返回值类型(可以是任意类型)。与方法体中“
return 返回值
”搭配使用
- 无返回值,则声明为
- 方法名:属于标识符,命名时遵循标识符命名规则和规范,“见名知意”
- 形参列表:表示完成方法体功能时需要外部提供的数据列表。可以包含任意个参数(0 个,1 个或多个)
- 无论是否有参数,
()
不能省略 - 如果有参数,每一个参数都要指定数据类型和参数名,多个参数之间使用逗号分隔,例如:
- 一个参数:
(数据类型 参数名)
- 二个参数:
(数据类型1 参数1, 数据类型2 参数2)
- 一个参数:
- 参数的类型可以是任意类型(基本数据类型、引用数据类型)
- 无论是否有参数,
throws
异常列表:可选
方法体必须由 {}
括起来,在 {}
中编写完成方法功能的代码
关于方法体中 return
语句的说明:
return
语句的作用是结束方法的执行,并将方法的结果返回去- 如果返回值类型不是
void
,方法体中必须保证所有分支一定有return 返回值;
语句,并且要求该返回值结果的类型与声明的返回值类型一致或兼容。除非抛异常,可以不用return
- 如果返回值类型为
void
时,方法体中可以没有return
语句,如果要用return
语句提前结束方法的执行,那么return
后面不能跟返回值,直接写return;
就可以。 return
语句后面就不能再写其他代码了,否则会报错:Unreachable code
如何调用实例方法
方法通过方法名被调用,且只有被调用才会执行。
格式:
对象.方法名([实参列表])
使用的注意点
- 必须先声明后使用,且方法必须定义在类的内部
- 调用一次就执行一次,不调用不执行
- 方法中可以调用类中的方法或属性,不可以在方法内部定义方法
return
在方法中的作用:
- 结束一个方法
- 结束一个方法的同时,可以返回数据给方法的调用者
注意点:在 return
关键字的直接后面不能声明执行语句,报错:Unreachable code
方法调用内存分析
- 方法没有被调用的时候,都在方法区中的字节码文件(
.class
)中存储。 - 方法被调用的时候,在栈空间运行方法的逻辑。方法每调用一次就会在栈中有一个入栈动作,即给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值。
- 当方法执行结束后,会释放该内存,称为出栈,如果方法有返回值,就会把结果返回调用处,如果没有返回值,就直接结束,回到调用处继续执行下一条指令。
- 栈结构:先进后出,后进先出。
方法的重载(overload)
方法重载:在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可。
参数列表不同:参数个数或参数类型不同
重载的特点:与修饰符、返回值类型无关,只看参数列表,且参数列表必须不同(参数个数或参数类型)。调用时,根据方法参数列表的不同来区别。
重载方法调用:JVM 通过方法的参数列表,调用匹配的方法。先找个数、类型最匹配的,再找个数和类型可以兼容的,如果同时多个方法可以兼容将会报错
可变个数的形参
在 JDK 5.0 中提供了 Varargs(variable number of arguments) 机制。即当定义一个方法时,形参的类型可以确定,但是形参的个数不确定,那么可以考虑使用可变个数的形参。
格式:
方法名(参数的类型名... 参数名)
// JDK 5.0 以前:采用数组形参来定义方法,传入多个同一类型变量
public static void test(int a, String[] books);
// JDK 5.0: 采用可变个数形参来定义方法,传入多个同一类型变量
public static void test(int a , String... books);
- 可变参数:方法参数部分指定类型的参数个数是可变多个:0 个,1 个或多个
- 可变个数形参的方法与同名的方法之间,彼此构成重载
- 可变参数方法的使用与方法参数部分使用数组是一致的,二者不能同时声明,否则报错(可变参数是数组的语法糖)
- 方法的参数部分有可变形参,需要放在形参声明的最后
- 在一个方法的形参中,最多只能声明一个可变个数的形参(可以理解为没有两个“最后”)
方法的参数传递机制
- 形参(formal parameter):在定义方法时,方法名后面括号
()
中声明的变量称为形式参数,简称形参 - 实参(actual parameter):在调用方法时,方法名后面括号
()
中的使用的值/变量/表达式称为实际 参数,简称实参
参数传递机制:值传递
Java 里方法的参数传递和赋值操作一样,方式只有一种:值传递 。即:将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
- 基本数据类型:数据值就是值本身
- 引用数据类型:数据值是堆中引用对象的地址(指针)
递归(recursion)方法
方法自己调用自己的现象就称为递归
递归的分类:直接递归、间接递归
直接递归
方法自身调用自己
public void methodA() {
methodA();
}
间接递归
方法间循环调用
public static void A() {
B();
}
public static void B() {
C();
}
public static void C() {
A();
}
说明:
- 递归方法包含了一种隐式的循环
- 递归方法会重复执行某段代码,但这种重复执行无须循环控制
- 递归一定要向已知方向递归,否则这种递归就变成了无限递归,停不下来,类似于死循环。最终发生栈内存溢出
- 递归调用会占用大量的系统栈,内存耗用多,在递归调用层次多时速度要比循环慢的多,所以在使用递归时要慎重
- 在要求高性能的情况下尽量避免使用递归,递归调用既花时间又耗内存。考虑使用循环迭代
对象数组
数组的元素可以是基本数据类型,也可以是引用数据类型。当元素是引用类型中的类时,我们称为对象数组。
注意点:对象数组,首先要创建数组对象本身,即确定数组的长度,然后再创建每一个元素对象,如果不创建,数组的元素的默认值就是 null
,很容易出现空指针异常:NullPointerException
关键字:package
、import
package
(包)
package
,称为包,用于指明该文件中定义的类、接口等结构所在的包。
格式:
package 顶层包名.子包名;
举例:pack1/pack2/PackageTest.java
package pack1.pack2; // 指定类 PackageTest 属于包 pack1.pack2
public class PackageTest {
public void display() {
System.out.println("in display() method");
}
}
说明:
- 一个源文件只能有一个声明包的
package
语句 package
语句作为 Java 源文件的第一条语句出现。若缺省该语句,则指定为无名包- 包名,属于标识符,满足标识符命名的规则和规范(全部小写)、见名知意
- 包通常使用所在公司域名的倒置:
com.atguigu.xxx
- 取包名时不要使用
java.xx
- 包通常使用所在公司域名的倒置:
- 包对应于文件系统的目录,
package
语句中用 “.
” 来指明包(目录)的层次,每.
一次就表示一层文件目录 - 同一个包下可以声明多个结构(类、接口),但是不能定义同名的结构。不同的包下可以定义同名的结构
包的作用:
- 可以包含类和子包,划分项目层次,便于管理
- 帮助管理大型软件系统:将功能相近的类划分到同一个包中。比如:MVC 的设计模式
- 解决类命名冲突的问题
- 控制访问权限
JDK 中主要的包介绍
java.lang
:包含一些 Java 语言的核心类,如String
、Math
、Integer
、System
、Thread
等,提供常用功能java.net
:包含执行与网络相关的操作的类和接口java.io
:包含能提供多种输入/输出功能的类java.util
:包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数java.text
:包含了一些 Java 格式化相关的类java.sql
:包含了 Java 进行 JDBC 数据库编程的相关类/接口java.awt
:包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)
import
(导入)
为了使用定义在其它包中的 Java 类,需用 import
语句来显式引入指定包下所需要的类。相当于 import
语句告诉编译器到哪里去寻找这个类
格式:
import 包名.类名;
举例:
import pack1.pack2.Test;
// import pack1.pack2.*; // 表示引入 pack1.pack2 包中的所有结构
public class PackTest {
public static void main(String args[]) {
Test t = new Test(); // Test类在 pack1.pack2 包中定义
t.display();
}
}
import static
普通的导入声明从包中导入类,从而允许在没有包限定的情况下使用类;而静态导入声明从类中导入静态成员,从而允许在没有类限定的情况下使用静态成员。
// 仅使用 import
import java.lang.Math;
// 使用类名.静态成员调用
double r = Math.cos(Math.PI * theta);
// 使用 import static 语法导入 Math 类的静态变量和静态方法之后,代码就更简洁了:
import static java.lang.Math.*;
// 直接调用静态成员
double r = cos(PI * theta);
注意事项:
import
语句,声明在包的声明和类的声明之间- 如果需要导入多个类或接口,那么就并列显式多个
import
语句即可 - 如果使用
a.*
导入结构,表示可以导入a
包下的所有有权限访问的结构。举例:可以使用java.util.*
的方式,一次性导入util
包下所有有权限访问的类或接口。 - 如果导入的类或接口是
java.lang
包下的,或者是当前包下的,则可以省略此import
语句。 - 如果已经导入
a
包下的类,那么如果需要使用a
包的子包下的类的话,仍然需要导入。 - 如果在代码中使用不同包下的同名的类,那么就需要使用类的全类名的方式指明调用的是哪个类。
import static
组合的使用:导入指定类或接口下的静态的属性或方法
面向对象特征一:封装性(Encapsulation)
为什么需要封装
我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部的结构吗?有必要碰电动机吗?
客观世界里每一个事物的内部信息都隐藏在其内部,外界无法直接操作和修改,只能通过指定的方式进行访问和修改。
随着我们系统越来越复杂,类会越来越多,那么类之间的访问边界必须把握好,面向对象的开发原则要 遵循“高内聚、低耦合”。
高内聚、低耦合是软件工程中的概念,也是 UNIX 操作系统设计的经典原则。
内聚,指一个模块内各个元素彼此结合的紧密程度;耦合,指一个软件结构内不同模块之间互连程度的度量。内聚意味着重用和独立,耦合意味着多米诺效应牵一发动全身。
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅暴露少量的方法给外部使用,尽量方便外部调用。
何为封装性
所谓封装,就是把客观事物封装成抽象概念的类,并且类可以把自己的数据和方法只向可信的类或者对象开放,向没必要开放的类或者对象隐藏信息。
通俗的讲,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
Java 如何实现数据封装
实现封装就是控制类或成员的可见性范围。这就需要依赖访问控制修饰符,也称为权限修饰符来控制。
权限修饰符:public
、protected
、缺省、private
。具体访问范围如下:
修饰符 | 本类内部 | 本包内 | 其他包的子类 | 其他包非子类 |
---|---|---|---|---|
private | √ | × | × | × |
缺省 | √ | √(本包子类非子类都可见) | × | × |
protected | √ | √(本包子类非子类都可见) | √(其他包仅限于子类中可见) | × |
public | √ | √ | √ | √ |
具体修饰的结构:
- 外部类:
public
、缺省 - 成员变量、成员方法、构造器、成员内部类:
public
、protected
、缺省、private
封装性的体现
成员变量私有化
私有化类的成员变量,提供公共的 getter 和 setter 方法,对外暴露获取和修改属性的功能。
public class Person {
// 1. 使用 private 修饰成员变量
private int age;
// 2. 提供 setter/getter 方法,可以访问成员变量
// 如果不提供 setter,则代表成员变量只读
public void setAge(int a) {
if (a >= 0 && a < 200) {
age = a;
}
}
public int getAge() {
return age;
}
}
成员变量封装的好处:
- 让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里面加入控制逻辑,限制对成员 变量的不合理访问。还可以进行数据检查,从而有利于保证对象信息的完整性。
- 便于修改,提高代码的可维护性。主要说的是隐藏的部分,在内部修改了,如果其对外可以的访问方式不变的话,外部根本感觉不到它的修改。例如:Java8 → Java9,
String
从char[]
转为byte[]
内部实现,而对外的方法不变,我们使用者根本感觉不到它内部的修改。
注意:
- 开发中,一般成员实例变量都习惯使用
private
修饰,再提供相应的public
权限的 getter/setter 方法访问。 - 对于
final
的实例变量,不提供 setter 方法(代表只读)。 - 对于
static final
的成员变量,习惯上使用public
修饰。
方法私有化
只暴露想让外部调用的方法,内部自己用的方法隐藏
类的成员之三:构造器(Constructor)
构造器(Constructor),也称为构造方法,在类实例化为对象(new
)时自动调用,常用于对成员变量进行初始化赋值
格式:
[修饰符] class 类名 {
[修饰符] 构造器名() {
// 实例初始化代码
}
[修饰符] 构造器名(参数列表) {
// 实例初始化代码
}
}
说明:
- 构造器名必须与它所在的类名必须相同
- 它没有返回值,所以不需要返回值类型,也不需要
void
- 构造器的修饰符只能是权限修饰符,不能被其他任何修饰。比如,不能被
static
、final
、synchronized
、abstract
、native
修饰,不能有return
语句
举例:
public class Student {
public String name;
public int age;
// 无参构造
public Student() {}
// 函数重载:有参构造
public Student(String n, int a) {
name = n;
age = a;
}
}
public class TestStudent {
public static void main(String[] args) {
// 调用无参构造创建学生对象
Student s1 = new Student();
// 调用有参构造创建学生对象
Student s2 = new Student("张三", 23);
}
}
使用说明:
- 当我们没有显式的声明类中的构造器时,系统会默认提供一个无参的构造器并且该构造器的修饰符默认与类的修饰符相同
- 当我们显式的定义类的构造器以后,系统就不再提供默认的无参的构造器了
- 在类中,至少会存在一个构造器
- 构造器是可以重载的
阶段性知识补充
类中属性赋值过程
在类的属性中,可以有哪些位置给属性赋值?
- 默认初始化
- 显式初始化
- 构造器中初始化
- 通过”对象.属性”或”对象.方法”的方式,给属性赋值
这些位置执行的先后顺序是怎样?
- 顺序:1 - 2 - 3 - 4
- 说明:
- 1、2、3:在对象创建过程中,只执行一次
- 4:在对象创建后执行的,可以根据需求多次执行
JavaBean
JavaBean 是一种 Java 语言写成的可重用组件。
好比你做了一个扳手,这个扳手会在很多地方被拿去用。这个扳手也提供多种功能(你可以拿这个扳手扳、锤、撬等),而这个扳手就是一个组件。
所谓 JavaBean,是指符合如下标准的 Java 类:
- 类是公共的
- 有一个无参的公共的构造器
- 属性是私有的,且有对应的公共 getter、setter 方法
用户可以使用 JavaBean 将功能、处理、值、数据库访问和其他任何可以用 Java 代码创造的对象进行打包,并且其他的开发者可以通过内部的 JSP 页面、Servlet、其他 JavaBean、applet 程序或者应用来使用这些对象。用户可以认为 JavaBean 提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变
《Think in Java》中提到,JavaBean 最初是为 Java GUI 的可视化编程实现的。你拖动 IDE 构建工具创建一个 GUI 组件(如多选框),其实是工具给你创建 Java 类,并提供将类的属性暴露出来给你修改调整,将事件监听器暴露出来。
UML 类图
UML(Unified Modeling Language,统一建模语言),用来描述软件模型和架构的图形化语言。
常用的 UML 工具软件有 PowerDesinger、Rose 和 Enterprise Architect。
UML 工具软件不仅可以绘制软件开发中所需的各种图表,还可以生成对应的源代码。
在软件开发中,使用 UML 类图可以更加直观地描述类内部结构(类的属性和操作)以及类之间的关系(如关联、依赖、聚合等)
+
表示public
类型-
表示private
类型#
表示protected
类型- 方法的写法:
访问权限 方法名(参数名: 参数类型): 返回值类型
- 构造器:方法加下划线
- 斜体表示抽象方法或类