Java 基础复习
P10 Windows 常用快捷键
Alt+F4
关闭窗口键
P11 常用 Dos 命令
- 在文件夹的路径前面(地址栏),输入
CMD
,即可在对应文件夹下打开 CMD 窗口 - 切换盘符:
D:
即可; dir
类似ls
- 切换到不通盘符下的目录:
cd /d D:\O1O-Code
cls
类似clear
- 创建文件夹
md
- 移除文件夹
rd
- 删除文件
del
ipconfig
mspaint
打开画图calc
打开计算机
P23 数据类型介绍
- 字符 char 占 2 个字节,字符和字符串是有区别的;
boolean
占 1 位;- 1 字节 = 8 位
p25 类型转换
低 ---------------------------------------------------------------------------------->高
byte(1字节),short(2字节),char(2字节)->int(4字节)->long(8字节)->float(4字节)->double(8字节)
- 「强制转换」:高 -> 低,比如
int -> byte
,a 为int
类型,就需要byte b = (byte)a;
- 「自动转换」:低 > 高,比如
byte -> int
,a 为byte
类型,则仅需int b = a;
JDK7 新特性,数字之间可以用下划线分割,方便阅读:
int money = 10_0000_0000;
注意点:
- 操作比较大的数字,注意溢出问题(可以先把计算公式中的一个数字类型强转为
long
型)
P29 逻辑运算符、位运算符
位运算的好处,计算效率高:
0000 0010 2
0001 0000 2*2*2*2
2<<3
相当于2*Math.pow(2,3)
5<<2
相当于2*Math.pow(2,2
P30 三元运算符及小结
字符串连接符:
System.out.println("" + 10 + 20); // 输出 1020
System.out.println(10 + 20 + ""); // 输出 30
三元运算符:x?y:z
如果 x 为真,则为 y,否则为 z;
JavaDoc
参数信息:
@author
作者@version
版本@since
指明需要最早使用的jdk版本@param
参数名@return
返回值情况@throws
异常抛出情况
快捷键:
- 输入
/**
+Enter之后,直接生成 javaDoc 注释文档
命令行生成 javaDoc:
javadoc -encoding UTF-8 -charset UTF-8 Doc.java
会生成 index.html
更多标记,查阅:
P33 用户交互 Scanner
java.util.Scanner
类是 Java 5 开始提供的。
Scanner s = new Scanner(System.in)
``
获取输入的字符串:
next:
- `next()` 一定要读取到有效字符后,才可以结束输入;
- 对输入有效字符之前遇到的空白,`next()` 方法将会自动将其去掉;
- `next()` 不能得到带有空格的字符串
nextLine():
- 以 `Enter` 为结束符,`nextLine()` 方法返回的是输入回车之前的所有字符;
- `hasNext()` 与 `hasNextLine()` 判断是否还有输入的数据;
## P37 流程控制:Switch 选择结构
```java
switch(expression){
case value:
// 语句
break;
case value:
// 语句
break;
default:
// 语句
}
语法点:
- 要注意
expression
和value
的值类型 expression
有的教程中也称为integral-selector
——「整数选择因子」。它要求使用一个选择因子,并且必须是byte/short/int/char
四种数据类型、枚举类型、String 类型(从 Java7 开始);- 枚举类型用来搭配 switch 工作,优雅;
- case 标签后的
value
值也称为integral-value
,也可以是一个表达式; default
标签是当前面没有匹配的 case 时,会进入执行;
补充:
.class
文件时字节码文件,需要反编译查看,编译结果可能在 target
目录下,或者打开 IDEA 的 Project Structure
设置,查看 Project complier output
设置的路径,复制对应的 .class
文件到IDEA的目录下,可以实现反编译打开。
经过反编译查看,可以发现当使用 String 作为表达式时,其实还是会转换成数字。
P38 While 循环
需要一个让表达式可以停止的操作;
P45 方法
方法的设计原则:方法的本意是功能块,最好保持方法的「原子性」,一个方法只完成 1 个功能,这样有利于日后的扩展和维护。
-
形参:方法定义的变量;
-
实参:调用方法时,传入的参数值;
-
Java 是值传递,不是引用传递;
-
方法的重载就是在一个类中,有相同的函数名称,但是形参不同的方法;
- 同名方法,参数的类型必须不同,返回值类型不做要求;
直接编译 java
文件,例如 java Demo.java
,会生成 Demo.class
文件。如果直接 java Demo
运行这个文件,会报错:错误: 找不到或无法加载主类
,怎么解决这个问题呢?需要切换到包的路径的上一层去执行。
P49 可变参数
- 从 JDK 1.5 之后开始的,方法声明中,参数类型后加一个省略号
...
; - 一个方法中,只能指定一个可变参数,它必须是方法的最后一个参数;
- 其实就是存入了一个数组内;
public static void add(int... numbers) {
if (numbers.length == 0) {
System.out.println("未输入求和数字!退出");
return;
}
int sum = 0;
for (int number : numbers) {
sum = sum + number;
}
System.out.println(sum);
}
P50 递归 recursive
- 递归:A 方法调用 A 方法本身!
- 使用场景:想想数学中的归纳推理!
- 递归利用了栈机制,效率并不一定高;
递归结构主要包括两个部分:
- 递归头:什么时候终止调用。如果没有停止的条件,将会陷入死循环 —— 边界条件
- 递归体:什么时候需要调用方法自身;
P51 数组 Array
- 相同类型的数据的有序集;
数组的创建:
// 定义
dataType[] arrayRefVar;
//初始化,指定了数组的长度
arrayRefVar = new dataType[arraySize];
还可以:
// 直接赋值了
dataType[] arrayRefVar = new dataType[]{xx,...}
还可以:
// 省略new
dataType[] arrayRefVar = {xx,...}
Java 内存分析:
- 堆:
- 存放 new 的对象和数组;
- 可以被所有线程共享,不会存放别的对象的引用
- 栈:
- 存放基本变量类型(会包含这个基本类型的具体数值);
- 引用对象的变量(会存放这个引用在堆里面的具体地址)
- 方法区:
- 可以被所有的线程共享;
- 包含了所有的class和static变量;
数组的基本特点:
- 数组的长度是确定的;
- 元素类型相同;
- 数组元素可以是任何类型;
- 数组的变量属于引用类型;
- 数组对象本身是在堆中的;
Tips:
arrayName.for
快速生成for each
循环;
二维数组:
// 类似于 2 行 5 列
int[][] demo = new int[2][5]
// 实例,类似 4 行 2 列
int[][] array = {{1,2},{2,3},{3,4},{4,5}}
P57 数组:Arrays 类讲解
工具类 Arrays 提供了很多 static 方法供我们使用,方便对数组对象的操作。
Arrays.toString(arrayName)
打印数组arrayName
中的每个元素;Arrays.sort(arrayName)
对数组排序,方法无返回值,作用于数组对象本身;Arrays.fill
填充方法,很多重载定义;
P58 冒泡排序
总共有 8 大排序。
- 冒泡排序,两层循环,外层冒泡论述,里面依次比较;
- 嵌套勋魂,可以得出这个算法的时间复杂度
O(n2)
- 可以进一步优化
P60 面向对象
- 面向对象编程(
Object-Oriented Programming,OOP
) - 面向对象编程的本质就是:以类的方式组织代码,以对象组织(封装)数据。类是对象的「模板」。
三大特性:
- 封装
- 继承
- 多态
P63 类与对象的创建
- 使用
new
关键字创建对象(类的实例)的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及类中构造器的调用; - 类中构造器也称为构造方法,在进行创建对象的时候必须被调用的。
- 构造器有以下 2 个特点:
- 必须和类同名;
- 必须没有返回类型,也不能写
void
P64 构造器详解
- 无参构造方法:即使没有定义构造器,依然包含了一个无参构造方法;
一个类如果没有显示地定义构造器方法,其实,默认包含无参的构造方法。编译器帮你自动做了这样的操作。比如一个 Person.java
类,编译好之后,对应生成的 Person.class
字节码文件中,其实是有如下的无参构造方法的:
public Person() {
}
- 有参构造器:一旦定义了有参构造器,无参构造必须显示地定义!
注意点:
- 使用
new
关键字,必须要有构造器,本质需要调用构造器; - 构造方法主要用来初始化值;
P65 创建对象内存分析
- 粗略讲,对象真实存储在「堆」中,变量名本身存储在「栈」中。
- 堆里面包含了方法区;
P66 简单小结类与对象
- 对象(实例)是通过引用看来操作的:栈中变量-->堆中对象;
P67 面向对象:封装
- 该露的露,该藏的藏
- 「高内聚,低耦合」:高内聚就是类的内部数据操作细节自己完成;低耦合就是仅暴露少量方法给外部使用;
- 封装:数据的隐藏
- 简单一句话:「属性私有,
get/set
」 private
私有
封装的意义:
- 提高程序的安全性,保护数据
- 隐藏代码的细节
- 系统可维护性增加了
P68 继承
- 关键字
extends
- Java 中只有单继承,没有多继承!
- 子类和父类之间,从意义上讲应该具有
is a
的关系,例如Student is a Person
- 子类不可以继承父类中
private
修饰的属性和方法;
Tips:
Ctrl+H
查看继承关系;
P69 Super 详解
super
作用:
super
只能出现在子类的方法或者构造方法中;super.name
子类调用父类中的属性super.test()
子类中调用父类中的方法;super()
调用了父类中的无参构造方法,这句话隐式包含在了子类的无参构造器中,并且,是第一行(也就是说,首先调用了父类的无参构造器,其次,再调用了子类本身的无参构造器)!
注意点:
- 父类中的
private
修饰的属性和方法,子类中还是无法被调用的; - super 和 this 不能同时调用构造方法
- super() 调用父类的无参构造方法;
- this() 调用本类中的的构造方法;
P70 方法的重写
重写:
- 方法名必须相同;
- 参数列表必须相同
- 修饰符:范围可以扩大
public > protected > default > private
- 抛出的异常:范围,可以被缩写,但不能扩大;
例子:
- 父类的引用指向了子类时:
Father demo = new Son();
- 调用了静态方法时,比如
demo.methodA()
,加入这个methodA
是静态方法,那么,即使子类中重写了这个方法,依然调用的是父类的方法; - 调用不是静态方法时,
demo.methodB()
,这时候就会调用子类中重写的这个方法;
- 调用了静态方法时,比如
注意点:
- 重写,仅和非静态方法有关!
private
方法不能被重写!
P71 什么是多态
- 同一方法可以根据发送对象的不同而采用多种不同的行为方式;
- 一个对象的实际类型是确定的,但可以指定对象的引用的类型有很多;
使用 new 创建出的对象的实际类型是确定的:
new Student()
new Person()
指向对象的变量的引用类型不确定:
Student s1 = new Student()
Person s2 = new Student()
s1、s2
能执行哪些方法,它们的引用类型是关键。比如 Student
类中比父类多定义了一个 say()
方法,s2
依然是无法调用 s2.say()
的,因为 Person
类没有该方法!
Person s2 = new Student()
这样写的意义是什么呢?
- 用父类规范了对象的行为,无法调用子类独有的方法!
注意事项:
-
多态是方法的多态!属性并没有多态!
-
父类和子类有联系
-
多态存在的条件:
- 继承关系
- 方法的重写(
s1.run();s2.run();
虽然可能都是Person
的引用类型,但是实际对象可能一个是Student
对象,一个是Teacher
对象) - 父类引用指向子类对象:
Person aa = new Student(); Person bb = new Teacher();
这里的 aa 类型就是 Person,但是会优先调用子类中重写的方法,如果没有重写,才调用父类中的方法;
-
static 方法属于类,它不属于实例,不能被重写!
-
private 方法私有的,也不能重写!
P72 instanceof 和 类型转换
instanceof
关键字用于判断 2 个类之间是否具有父子关系,例如 aa instanceof Person
;
类型之间的转换:
- 高(父)转低(子),需要强制转换 ——「向下转换」
- 低(子)转高(父),自动转换,子类转换为父类,可能会丢失子类中自己的独有的一些方法:
Person aa = new Student();
——「向上转型」
P73 static 关键字详解
属于类,而不是对象(实例):
- 静态属性
- 静态方法
- 静态代码库
注意点:
- 静态方法不能调用非静态的属性和方法,因为静态方法是随着类加载的;
补充:
- 匿名代码块是创建对象时调用的,在构造方法之前;
- 静态代码块是在匿名代码块执行之前执行的,只执行一次
- 匿名代码块中定义的变量属于局部变量,并不是类的属性!
- 导入静态方法:
import static java.lang.Math.random;
P74 抽象 abstract
- 定义抽象类,抽象类的子类都必须实现它的方法,除非它的子类也是抽象类;
- 定义抽象方法,不定义方法体;
注意点:
- 不能
new
抽象类创建对象,但是通过.class
文件可以发现,抽象类是有无参构造器的,说明有构造器不一定就能用 new 创建对象! - 抽象类中可以定义非抽象方法,所以,抽象类是一个不彻底的抽象!没有
interface
专业! - 抽象方法必须在抽象类中;
抽象类存在的意义?
- 提高开发效率,节省代码;
P75 接口的定义与实现 interface
- 接口只有规范,自己无法写方法 —— 相对于抽象类来讲,接口类似专业做规范的!约束和实现分离:面向接口编程~
- 接口中的方法,缺省就是
public abstract
修饰的! - 接口中定义的属性,其实是一个常量,缺省是
public static final
修饰的!—— 所以实际项目中,常常也会通过接口定义一些常量~ - 接口需要实现类,使用
implements
关键字定义实现类; implements
可以实现多个接口,这就是比extends
有优势的地方了,「多继承」的效果!- 子类需要重写接口中的方法!
理解:
- 接口就是规范,定义一组规则;
- 接口的本质是契约,让它的子类去遵守;
- OOP 的精髓,是对对象的抽象
作用:
- 约束,规范,契约
- 定义一些方法,让人去实现;
注意点:
- 查看接口类对应的字节码文件,可以发现接口是没有无参构造器的!
P76 N 种内部类
- 内部类就是在一个类的内部再定义一个类
- 内部类可以获得外部类的私有属性、私有方法!
内部类的种类:
- 成员内部类
- 静态内部类
- 局部内部类:在方法里定义一个类;
- 匿名内部类:没有名字初始化一个对象,不用将实例保存到变量中(接口常用);
P77 异常
主要分为三种类型的异常:
- 检查性异常:用户错误或问题引起的异常。这是程序猿无法预见的。
- 运行时异常:运行时异常是可能被程序猿避免的异常。
- 错误:错误不是异常,而是脱离程序猿控制的问题。例如,当栈溢出时(
OutOfMemory
),一个错误就发生了,它们在编译时是检查不到的。
Java 异常体系结构:
- Java 把异常当做对象处理,并定义一个基类
java.lang.Throwable
作为所有异常的超类; - 在 Java API 已定义了许多异常类,这些异常类分为两大类,错误
Error
和 异常Exception
;
Error:
- Error 类对象由 Java 虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关;
- Java 虚拟机运行错误(
Java MachineError
) - 虚拟机试图执行应用时,如类定义错误(
NoClassDefFoundError
)、链接错误(LinkageError
)
Exception:
- Exception 分支中,有一个重要的子类 RuntimeException(运行时异常),它下面又定义了很多具体的异常子类:
- NullPointerException:空指针异常;
- MissResourceException:丢失资源
- ClassNotFoundException:找不到类等异常
- 这些异常一般由程序逻辑错误引起,应该从逻辑角度尽可能避免这类异常发生;
Error 和 Exception 的区别:
- Error 通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这类异常时,Java 虚拟机一般会选择终止线程;
- Exception 通常是可以被程序处理的,并且,应该在程序中尽可能的去处理这些异常;
P78 异常处理机制
- 抛出异常
- 捕获异常
try {
System.out.println(1 / 0);
} catch (ArithmeticException e) {
System.out.println("算术异常 ArithmeticException: "+e.getMessage());
// 打印错误的栈信息
e.printStackTrace();
} catch (Exception e) {
System.out.println("漏网之鱼 Exception: " + e.getMessage());
e.printStackTrace();
} catch (Error e) {
System.out.println("漏网之鱼 Error: " + e.getMessage());
e.printStackTrace();
} finally {
System.out.println("END~");
}
主动抛出异常:
throw
关键字,throw new ArithmeticException("哎呀,计算出错了!");
一般在方法中主动抛出异常;throws
关键字,用在方法上,那么,使用该方法时,就需要主动利用try catch
捕获,或者,继续向上抛出异常;
注意点:
- 异常的范围要逐级扩大,否则会报错,
Tips:
- 快捷功能
surround with
可以快速选中代码段上下生成相关片段,Win 快捷键Ctrl+Alt+T
,Mac 快捷键Commadn+Option+T
;
P79 自定义异常及经验小结
- 自定义异常,可继承 Exception 类即可;
经验总结:
- 尽量去处理异常,切忌仅简单的调用
printStackTrace()
打印输出; - 在多重 catch 块后面,可以加一个
catch (Exception e)
来处理可能会被遗漏的异常; - 具体如何处理异常,需要结合具体的业务;
- 尽量添加
finally
语句块去释放占用的资源;