《面试宝典》读书笔记 Ⅰ

基本概念、面向对象技术

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 中一个非常重要的特性,它允许程序在运行时进行自我检查,同时也允许对其内部的成员进行操作。

非常重要的一个作用:在运行时动态地创建类的对象。

创建对象的方法

  1. 通过 new 语句实例化一个对象。
  2. 通过反射机制创建对象。
  3. 通过 clone() 方法创建一个对象。
  4. 通过反序列化的方式创建对象。

package

宗旨是把 .java 文件、.class 文件(编译后的文件)、其他 resource 文件有条理地进行一个组织,以供使用。类似于 Linux 文件系统。

作用

  • 提供多层命名空间,解决命名冲突;
  • 对类按功能进行分类,使项目的组织更加清晰。

实现 C++ 中的函数指针

回调函数:函数先在某处注册,而它将在稍后某个需要的时候被调用。
可以利用接口与类实现函数指针的功能。


面向对象与面向过程的区别

出发点不同

  • 面向对象:符合常规思维方式,映射到对象及对象之间的接口上。
  • 面向过程:强调过程的抽象画与模块化。

层次逻辑不同

面向对象:用类的层次结构体现类之间的继承和发展;
面向过程:用模块的层次结构概括模块或模块间的关系与功能,把客观世界的问题抽象成计算机可以处理的过程。

数据处理方式与控制程序方式不同

面向对象:原则上对象的修改只能由自身的成员函数完成,通过事件驱动来激活和运行程序;
面向过程:直接通过程序来处理数据,各模块之间存在着控制与被控制、调用与被调用的关系。

分析设计与编码转换方式不同

面向对象:分析、设计、编码采用一致性的模型,实现的是一种无缝连接;
面向过程:分析、设计、编码之间按规则进行转换,实现的是一种有缝连接。

面向对象的特征

抽象

并不打算了解全部问题,只是选择其中的一部分。包括:

  • 过程抽象
  • 数据抽象

继承

一种联结类的层次模型,子类可以修改或增加新的方法使之更适合特殊的需要。

封装

每个类对自身的数据和方法实行保护,对不可信的操作进行信息隐藏。

多态

允许不同类的对象对同一消息作出响应,很好地解决了应用程序函数同名的问题。

面向对象的优点

较高的开发效率

与人类的思维过程类似,可以通过继承或组合的方式来实现代码的重用,大大地提高了软件的开发效率。

保证软件的鲁棒性

可以重用在相关领域经过长期测试的代码,对软件的鲁棒性起到了良好的促进作用。

保证软件的高可维护性

一些非常成熟的设计模式,使程序在面对需求变更时,只需要修改部分的模块就可以满足需求。

继承的特性

  • Java 不支持多重继承。
  • 子类只能继承父类的非私有成员变量与方法。
  • 同名时,子类将会覆盖父类,而不会继承。

组合与继承的区别

组合和继承是面向对象中两种代码复用的方式。

组合

组合中的整体类对应继承中的子类,是显式的。

继承

继承中的父类对应组合中的局部类,是隐式的。

原则

  • 不要单纯地为了实现重用而使用继承,会破坏代码的可维护性;
  • 不要仅仅为了实现多态而使用继承,可以通过接口与组合的方式达到相同的目的,具有更好的可扩展性。

在 Java 语言中,能使用组合就尽量不要使用继承。

多态的实现机制

方法的重载(overload)

编译时的多态。

方法的覆盖(override)

运行时的多态。

只有类中的方法才有多态的概念,类中的成员变量没有多态的概念。

重载和覆盖的区别

重载

  • 通过不同的方法参数来区分。
  • 不能通过方法的访问权限、返回值类型、抛出的异常类型来进行重载。
  • private 不能重载。

覆盖

  • 有相同的函数名和参数。
  • 返回值相同。
  • 抛出的异常一致。
  • private 不能覆盖。

区别

  • 覆盖是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系
  • 覆盖只能由一对方法产生关系;重载是多个方法之间的关系。
  • 覆盖要求参数列表相同;重载要求参数列表不同。

抽象类与接口的异同

相同点

  • 都不能被实例化。
  • 只有实现了接口或抽象类中的方法才能被实例化。

不同点

  • 接口只有定义,其方法不能在接口中实现;抽象类的方法可以在抽象类中被实现。
  • 接口需要实现,一个类可以实现多个接口;抽象类只能被继承,一个类只能继承一个抽象类。
  • 接口强调特定功能的实现,是“has -a”关系;抽象类强调所属关系,是“is-a”关系。
  • 当功能需要累积时,用抽象类;不需要累积时,用接口。

接口被运用于实现比较常用的功能,便于日后维护或者添加删除方法;抽象类不适用于日后重新对里面的代码进行修改。

内部类

Java 中可以把一个类定义到另外一个类的内部,在类里面的这个类就叫做内部类。

静态内部类

只能访问外部类中的静态成员和静态方法。

成员内部类

可以自由地引用外部类中的属性和方法。

局部内部类

作用范围为其所在的代码块,最少使用。

匿名内部类

没有类名的内部类,一定是在 new 的后面,必须继承一个父类或实现一个接口。

获取父类的类名

getClass().getName()

this 与 super 的区别

名字相同会覆盖

  • this 用来区分对象的成员变量、方法的形参;
  • super 用来区分子类、父类的方法或成员变量。