基本概念、面向对象技术
Java 语言的优点
纯面向对象语言
能够直接反应现实生活中的对象。
平台无关性
由于 Java 为解释型语言,编译器会把 Java 代码变成中间代码
,然后在 JVM 上解释执行。
中间代码与平台无关,可以很好地跨平台执行,具有很好的可移植性。
提供了很多内置的类库
简化了开发人员的程序设计工作,同时缩短了项目开发的时间。
对多线程的支持、对网络通讯的支持、垃圾回收器。
提供了对 Web 应用开发的支持
具有较好的安全性和健壮性
- 安全性:防止恶意代码攻击的安全机制,数组边界检测、Bytecode 校验;
- 健壮性:强类型机制、垃圾回收器、异常处理、安全检查机制。
去除 C++ 语言中不好的特性
头文件、指针、结构、单元、运算符重载、虚基类、多重继承,使得程序更加严谨、简洁。
Java 与 C++ 的异同
Java 为解释型语言
C++ 为编译型语言,Java 执行速度更慢,但能跨平台执行。
Java 为纯面向对象语言
所有代码必须在类中实现,所有类型都是类。
不存在全局变量或全局函数。
没有指针的概念
有效防止了 C++ 语言中操作指针可能引起的系统问题,更加安全。
不支持多重继承
引入了接口
的概念,接口也具有多态特性,Java 可以通过实现多个接口来实现与多重继承类似的目的。
提供了垃圾回收器
不需要程序显式地管理内存的分配,Java 语言中虽然没有析构函数,但引入了 finalize() 方法。
当垃圾回收器将要释放无用对象的内存时,会首先调用该对象的 finalized() 方法,开发人员不需要关心对象所占的内存空间何时会被释放。
public static void main(String[] args)
public
权限修饰符,表明任何类或对象都可以访问这个方法。
static
方法中的代码时存储在静态存储区的,只要类被加载后,就可以使用该方法而不需要通过实例化对象来访问。通过类名.main() 直接访问。
void
表明方法没有返回值。
main
JVM 识别的特殊方法名,是程序入口的方法。
String[] args
开发人员在命令行状态下与程序交互的手段。
在 main() 方法执行前输出“Hello World”
由于静态块不管顺序如何,都会在 main() 方法执行之前执行,因此利用静态块可以实现输出“Hello World”的功能。
初始化顺序
静态对象优先于非静态对象
静态对象只初始化一次,非静态对象可能会初始化很多次。
父类优先于子类
按照成员变量的定义顺序
即使变量定义散布于方法定义之中,它们依然在任何方法被调用之前先初始化。
作用域
静态变量
被 static 修饰的成员变量称为静态变量或全局变量,只要一个类被加载,JVM 就会给类的静态变量分配存储空间。
局部变量
作用域与可见性为它所在的花括号内。
成员变量
这些修饰符只能用来修饰成员变量,不能用来修饰局部变量。
只有 public、abstract、final 能用来修饰类。
定义多个类
可以定义多个类,但是最多只能有一个类被 public 修饰。
当用 javac 指令编译 .java 文件时,它会给每一个类生成一个对应的 .class 文件。
构造函数
一种特殊的函数,用来在对象实例化时初始化对象的成员变量:
- 构造函数必须与类的名字相同,并且不能有返回值。
- 每个类可以有多个构造函数。
- 构造函数可以有 0、1 或 1 以上的参数。
- 构造函数总是伴随着 new 操作一起调用,必须由系统调用。
- 构造函数在对象实例化时会被自动调用,且只能运行一次;
- 普通方法是在程序执行到它时被调用,且可以被该对象调用多次。
- 构造函数的主要作用是完成对象的初始化工作。
- 构造函数不能被继承,因此它不能被覆盖,但能够被重载。
- 子类可以通过 super 关键字来显式地调用父类的构造函数。
- 默认构造器的修饰符只跟当前类的修饰符有关。
接口
Java 中一个类只能有一个父类。接口是抽象方法定义的集合,是一种特殊的抽象类。
只包含方法的定义
没有方法的实现。
成员的作用域修饰符都是 public
标识接口
没有任何方法声明,仅仅充当一个标识的作用。
clone() 方法
Java 在处理基本数据类型(int、char等)时,采用按值传递的方式执行,传递的是输入参数的复制。
其他类型都是按引用传递的方式执行,传递的是对象的一个引用。
赋值操作采用引用传递,无法达到对B的修改不会影响到A的目的。Java 提供一个简单有效的 clone() 方法来满足这个需求。
反射机制
反射机制是 Java 中一个非常重要的特性,它允许程序在运行时进行自我检查,同时也允许对其内部的成员进行操作。
非常重要的一个作用:在运行时动态地创建类的对象。
创建对象的方法
- 通过 new 语句实例化一个对象。
- 通过反射机制创建对象。
- 通过 clone() 方法创建一个对象。
- 通过反序列化的方式创建对象。
package
宗旨是把 .java 文件、.class 文件(编译后的文件)、其他 resource 文件有条理地进行一个组织,以供使用。类似于 Linux 文件系统。
作用
- 提供多层命名空间,解决命名冲突;
- 对类按功能进行分类,使项目的组织更加清晰。
实现 C++ 中的函数指针
回调函数:函数先在某处注册,而它将在稍后某个需要的时候被调用。
可以利用接口与类实现函数指针的功能。
面向对象与面向过程的区别
出发点不同
- 面向对象:符合常规思维方式,映射到对象及对象之间的接口上。
- 面向过程:强调过程的抽象画与模块化。
层次逻辑不同
面向对象:用类的层次结构体现类之间的继承和发展;
面向过程:用模块的层次结构概括模块或模块间的关系与功能,把客观世界的问题抽象成计算机可以处理的过程。
数据处理方式与控制程序方式不同
面向对象:原则上对象的修改只能由自身的成员函数完成,通过事件驱动来激活和运行程序;
面向过程:直接通过程序来处理数据,各模块之间存在着控制与被控制、调用与被调用的关系。
分析设计与编码转换方式不同
面向对象:分析、设计、编码采用一致性的模型,实现的是一种无缝连接;
面向过程:分析、设计、编码之间按规则进行转换,实现的是一种有缝连接。
面向对象的特征
抽象
并不打算了解全部问题,只是选择其中的一部分。包括:
- 过程抽象
- 数据抽象
继承
一种联结类的层次模型,子类可以修改或增加新的方法使之更适合特殊的需要。
封装
每个类对自身的数据和方法实行保护,对不可信的操作进行信息隐藏。
多态
允许不同类的对象对同一消息作出响应,很好地解决了应用程序函数同名的问题。
面向对象的优点
较高的开发效率
与人类的思维过程类似,可以通过继承或组合的方式来实现代码的重用,大大地提高了软件的开发效率。
保证软件的鲁棒性
可以重用在相关领域经过长期测试的代码,对软件的鲁棒性起到了良好的促进作用。
保证软件的高可维护性
一些非常成熟的设计模式,使程序在面对需求变更时,只需要修改部分的模块就可以满足需求。
继承的特性
- Java 不支持多重继承。
- 子类只能继承父类的非私有成员变量与方法。
- 同名时,子类将会覆盖父类,而不会继承。
组合与继承的区别
组合和继承是面向对象中两种代码复用的方式。
组合
组合中的整体类对应继承中的子类,是显式的。
继承
继承中的父类对应组合中的局部类,是隐式的。
原则
- 不要单纯地为了实现重用而使用继承,会破坏代码的可维护性;
- 不要仅仅为了实现多态而使用继承,可以通过接口与组合的方式达到相同的目的,具有更好的可扩展性。
在 Java 语言中,能使用组合就尽量不要使用继承。
多态的实现机制
方法的重载(overload)
编译时的多态。
方法的覆盖(override)
运行时的多态。
只有类中的方法才有多态的概念,类中的成员变量没有多态的概念。
重载和覆盖的区别
重载
- 通过不同的方法参数来区分。
- 不能通过方法的访问权限、返回值类型、抛出的异常类型来进行重载。
- private 不能重载。
覆盖
- 有相同的函数名和参数。
- 返回值相同。
- 抛出的异常一致。
- private 不能覆盖。
区别
- 覆盖是子类和父类之间的关系,是
垂直关系
;重载是同一个类中方法之间的关系,是水平关系
。 - 覆盖只能由一对方法产生关系;重载是多个方法之间的关系。
- 覆盖要求参数列表相同;重载要求参数列表不同。
抽象类与接口的异同
相同点
- 都不能被实例化。
- 只有实现了接口或抽象类中的方法才能被实例化。
不同点
- 接口只有定义,其方法不能在接口中实现;抽象类的方法可以在抽象类中被实现。
- 接口需要实现,一个类可以实现多个接口;抽象类只能被继承,一个类只能继承一个抽象类。
- 接口强调特定功能的实现,是“has -a”关系;抽象类强调所属关系,是“is-a”关系。
- 当功能需要累积时,用抽象类;不需要累积时,用接口。
接口被运用于实现比较常用的功能,便于日后维护或者添加删除方法;抽象类不适用于日后重新对里面的代码进行修改。
内部类
Java 中可以把一个类定义到另外一个类的内部,在类里面的这个类就叫做内部类。
静态内部类
只能访问外部类中的静态成员和静态方法。
成员内部类
可以自由地引用外部类中的属性和方法。
局部内部类
作用范围为其所在的代码块,最少使用。
匿名内部类
没有类名的内部类,一定是在 new 的后面,必须继承一个父类或实现一个接口。
获取父类的类名
getClass().getName()
this 与 super 的区别
名字相同会覆盖
- this 用来区分对象的成员变量、方法的形参;
- super 用来区分子类、父类的方法或成员变量。