这是我听翁恺老师JAVA课程的笔记
之前在W3SCHOOL过了一下,前面一下变量循环之类的就跳过了,这里主要记一下和其他语言语法上,概念上不同的地方
二维数组
//Declare an array
int a[][] = new int[3][5];
//Define an array
int [][]b = {
{1,2,3},
{4,5} //缺省自动补0
};
//Traverse an array
for(int i=0;i<2;i++){
for(int j=0;j<3;j++){
System.out.println(b[i][j]);
}
}
字符类型
单个字符是种特殊的类型:char
- 单引号表示字符字面量:'a','1'
- JAVA使用Unicode来表示字符=>可以表达汉字等多种语言文字
- 可以进行字符计算=>对Unicode编码进行操作
- 加减法
- 大小写换算
- 比较大小
- 逃逸字符/转义字符 Escape character
+字符
表示无法打印出来的控制字符or特殊字符
包裹类型
- 每种基础类型有一种与之相对应的包裹类型
基础类型 Primitive Type | 包裹类型 Wrapper Type |
---|---|
boolean | Boolean |
char | Character |
int | Integer |
double | Double |
- 包裹类型有什么用?
- 和基础类型一样,定义变量
- 提供一些方便实用的方法
- INT 获得类型最大值
WrapperType.MAX_VALUE
- Character 判断/转换大小写
- String 比较是否相等
String.equals()
- INT 获得类型最大值
字符串
-
定义字符串
Sting s;
-
Sting是一个类,Sting的变量是对象的管理者,而为拥有者
- 就像数组变量是数组的管理者而非拥有者一样=>用new创建一个新的对象,初始化后,再交给一个变量进行管理
String s = new String("hello world");
- 就像数组变量是数组的管理者而非拥有者一样=>用new创建一个新的对象,初始化后,再交给一个变量进行管理
-
使用
+
进行字符串连接- 如果一边为字符串,另一边不是字符串,则会将另一边自动转化为字符串进行连接
-
输入字符串
in.next()
读入一个单词,单词标志是空格(包括空格,tab,换行)in.nextLine()
读入一整行
Scanner in = new Scanner(System.in);
String s;
s = in.nextLine(); //读入一行
System.out.println(s);
s = in.next(); //仅读入第一个单词
System.out.println(s);
- 判断两个字符串变量相同还是内容相同
- 内容相同,但是变量名称不同的两个变量=>
person1 == person2 ?
=>False=>因为==
比较的是两个变量指向的是否为同一个对象 str1.equals(str2) ?
=>比较两个字符串内容是否相同
- 内容相同,但是变量名称不同的两个变量=>
字符串操作
操作 | 方法 |
---|---|
比较是否相等 | s1.equals(s2) |
比较大小 | s1.compareTo(s2) |
获取长度 | s1.length() |
访问字符 | s1.charAt(index) |
子串 | s1.substring(n) |
子串 | s1.substring(a,b) |
寻找字符 | s1.indexOf(c) |
寻找字符 | s1.indexOf(c,n) |
寻找字符串 | s1.indexOf(s2) |
判断是否以另一字符串开头 | s1.startsWith(s2) |
判断是否以另一字符串结尾 | s1.endWith(s2) |
去除两端空格 | s1.trim() |
替换 | s1.replace(c1,c2) |
变为小写 | s1.toLowerCase() |
变为大写 | s1.toUpperCase() |
- 所有的字符串都是不可变的,对它们操作的结果都是制造出新的字符串出来
String s1 = "abcd";
s1.toUpperCase();
System.out.println(s1);
=>abcd 并没有变成大写
s2 = s1.toUpperCase();
System.out.println(s2);
=>ABCD 变成了大写
为什么要这么设计呢?=>个人人为是为了方便项目维护,避免一些字符串操作造成的低级错误
- 字符串只能通过for循环遍历,不能通过for-each循环
String s1="汉字";
for (int i=0; i<s1.length(); i++){
System.out.println(s1.charAt(i));
}
=> OK
for (char c : s1){
...
}
=>Can only iterate over an array or an instance of java.lang.Iterable
- Switch-Case中使用字符串
switch (s){
case "this":...break;
case "that":...break;
}
Math类
函数 | 功能 |
---|---|
abs() | 绝对值 |
pow() | 幂 |
random() | 随机数 |
round() | 四舍五入 |
函数参数传递
-
类型不匹配
=>如果 所需值/形式参数 比 传入值/实际参数 要"宽"(loose),换句话说精度不变低,那么编译器会帮我们自动转换
char->int->double -
传递的是什么?
=>传值而不是传引用
本地变量
- 函数每次运行,会产生一个独立的变量空间,在这个空间中的变量,是函数这次运行所独有的,称作本地变量(Local Variable)
- 定义在函数内部的变量就是本地变量
- 参数也是本地变量
本地变量的生存周期和作用域
- 生存期:什么时候出现,什么时候消亡
- 作用域:在什么范围内可以访问这个变量
- 对于本地变量,它的生存周期和作用域都在大括号(块)内=>程序在进入块前,其中的变量不存在;离开后,也不存在.
- 成员变量的生存期是对象的生存期,作用域是类内部的成员函数
类和对象
-
对象是(类的)实体,需要被创建,为我们做事情
- 表达东西或事件
- 运行时响应消息(提供服务)
-
类是(对象的)规范,根据类的定义来创建对象
- 定义属性
- 就是JAVA中的类型
- 可以用来定义变量
-
对象=数据+操作
- 数据:属性or状态
- 操作:函数
对象初始化
- 过程:成员变量初始化=>构造函数=>将对象交给变量管理
- 成员变量如果没有初始化,编译器会给默认的"零值"(boolean=>false,object=>null)
- 本地变量如果没有初始化,编译器会直接报错
- 构造函数
- 与类同名
- 没有返回类型
- 可以有多个构造函数,参数表不同=>函数重载
- 创建对象时给的参数不同,就会自动调用不同的构造函数
- 通过
this()
调用其他的构造函数 - 一个类里同名但参数表不同的函数构成了重载关系
封闭的访问属性
- private只能修饰成员变量or成员函数
- 除非必要成员变量尽量设为private=>防止被外界随意修改
- private是针对类,而不是对象=>同一个类创建的不同对象,可以通过public函数成员互相访问private数据成员
开放的访问属性
- public=>任何类的函数都能够调用,访问,定义变量
- Public Type must be defined in its own file=>一个文件=一个编译单元
- (缺省)friendly=>同一package的其他类可以访问
包
-
friendly修饰的成员,在其他package无法访问
-
导入方式
import package.class
=>调用时使用package.class
import package.*
=>调用时直接写类名- 缺点:重名会冲突
-
package内还可以有package
类变量
- static修饰的成员变量
- 这个类的所有对象共享这个变量
- 可以在类外通过
Class.StaticVaribale
进行访问
类函数
- static修饰的函数
- 函数内不能访问non-static field value
- 只能访问static函数,成员变量
- 可以不通过对象直接调用=>不属于任何具体的对象
业务逻辑/接口设计
- 人机交互和业务逻辑分离
- 业务逻辑/接口设计只考虑数据本身
泛型容器类
- 容器类:可以存放任意数量的对象
- 定义时得给两个类型
- 容器的类型
- 元素的类型
ArrayList<String> ArraryListOfString = new ArraryList<String>();
- 定义时得给两个类型
ArrayList操作
ArrayList.add(element)
ArrayList.add(element,index)
ArrayList.remove(index)
ArrayList.get(index)
ArrayList.add(element)
ArrayList.size()
ArrayList.toArray(array)
对象数组
- 对象数组中每个元素都是对象的管理者,而不是对象本身
- 创建对象之后,都是null pointer
- 对象数组可以使用for-each循环
集合容器
- HashSet=>集合=>集合中没有重复元素,无序
Hash表
-
HashMap<KeyType,ValueType>
- Type是WrapperType,不是PrimitiveType
-
HashMap.put(key,value)
-
HashMap.get(key)
-
HashMap.keySet()
HashMap.keySet().size()
-
Key是唯一的=>放入两个键值对,键一样,那么先放入的就会被覆盖
继承
public class Subclass extends Superclass{...}
- subclass 无法访问 superclass private 成员变量
- private=>protected=>子类和同个package可以访问
- 给superclass写一个constructor,再通过method进行操作
super()
调用superclass的constructor- 可以传参数
- subclass初始化工程:superclass定义初始化=>自身类定义初始化=>构造函数
- 如果subclass含有和superclass同名的成员变量
- 那么superclass的成员变量会被隐藏(一样会创建,但是method操作的是subclass的)
- superclass的method修改的是superclass的成员变量
- =>谁的method修改谁的成员变量
super.method()
调用superclass的method
多态变量
- 子类和子类型
- 类就是类型=>子类定义了子类型
- 子类的对象可以当做父类的对象来使用
- 赋值给父类的变量
- 传递给需要父类对象的函数
- 放进需要父类对象的容器里
- 多态变量
- 多态变量:运行时,所管理的变量是会变化的
- JAVA的对象变量是多态的,它们能保存不止一种类型的对象
- 声明类型(静态类型)的对象或其子类的对象
- 把子类对象赋给父类的变量时,就发生了向上造型
向上造型
- 造型:把一个类型赋给另一个类型
- 让一个变量去管理一个动态类型与其静态类型不符的对象
- 造型就是用
()
围起来放在值的前面
- 对象的赋值
- 不是拿一个对象给另一个对象赋值
- 而是让两个对象的管理者,共同管理同一个对象
- 子类对象可以赋值给父类变量
- 父类对象不能赋值给子类变量
- 除非强制造型
SubclassVariable=(Subclass)SuperclassObj;
- 这种转换不一定是安全的
- 对象本身没有发生任何变化=>不是类型转换
- 类型转化完,对象本身就发生了彻底地变化
- 运行时有机制检查转化是否合理=>ClassCastException
- 除非强制造型
- 父类对象不能赋值给子类变量
- 向上造型
- 拿一个子类的对象当做父类的对象来用
- 向上造型是默认的,不需要运算符
- 向上造型总是安全的
多态
- 函数调用的绑定
- 绑定:通过对象变量调用函数,调用哪个函数这个事件叫做绑定
- 静态绑定:根据变量的声明类型来决定
- 动态绑定:根据变量的动态类型来决定
- 绑定:通过对象变量调用函数,调用哪个函数这个事件叫做绑定
- 在成员函数中调用其他成员函数也是通过this这个对象变量来调用的=>所有成员函数的调用都应该被看做一种动态绑定
- 覆盖override
- 子类和父类中存在名称和参数表完全相同的函数,这一对函数构成覆盖关系
- 通过父类的变量调用存在覆盖关系的函数时,会调用变量当时所管理对象所属的类的函数
- 多态:通过一个变量去调用一个函数,不关心实际类型是什么(不需要去判断),对应的函数就会被调用
Object类
- JAVA的单根结构:Object类是所有类的Root=>所有类都是Object类的子类
- Object类的函数
toString()
equals()
notify()
- ...
- override methods
@Override
- 覆盖父类的方法
- 要和父类函数有相同的函数原型(名字,参数表,都是public)
消除代码复制
- 代码复制是设计不良的一种表现=>消除代码复制(提取重复代码到函数,再调用)
封装
- 增加可扩展性
- 可运行的代码!=良好的代码
- 对代码做维护时最能看出代码质量
- 用封装降低耦合
- 类和类之间的关系称作耦合
- 耦合越低越好,保持距离是形成良好代码的关键
- 具体措施
- 将成员变量设为私有
- 对成员变量的操作封装为函数
- 不是简单的get,而是需要加以逻辑判断,或者数据结构的修改
- 类和类之间的关系称作耦合
可扩展性
- 用接口实现聚合
- 用框架+数据提高可扩展性
- 出口:成员变量做硬编码=>用容器+method(形成框架)
- 命令解析脱离if-else
- 定义一个handler来处理命令
- 用hashmap来存储命令和handler之间的关系
- 使交互部分代码得以复用,且新增功能只需添加handler
抽象
- 抽象函数:表达概念而无法实现具体代码的函数,带有
abstract
修饰符 - 抽象类:表达概念而无法构造出实体的类
- 限定
- 抽象函数只有声明,没有定义
- 包含抽象函数的类必须是抽象类
- 抽象类不能产生对象
- 但是可以定义变量,用于接收改抽象类子类的实例
- 继承抽象类的子类必须覆盖父类中的抽象函数(implementation)
- 否则自己成为抽象类=>无法实例化
- 两种抽象的概念
- 与具体相对=>表示一种概念而非实体
- 与细节相对=>表示一定程度上忽略细节,着眼大局
接口
- 接口是纯抽象类
- 所以成员函数都是抽象函数
- 所以成员变量都是public static final
- 接口规定长什么样,但是不管里面有什么
- 实现接口
- 类用extends,接口用Implements
- 类可以实现多个接口
- 接口可以继承接口,但是不能继承类
- 即可不能实现接口
- 面向接口编程
- 为了解决一个问题,先定义各个接口,然后再实现类
- 任何需要在函数间传入传出的一定是接口,而不是具体的类=>使得JAVA适合多人协作,编写大型程序(+)=>代码量快速膨胀(-)
2021年4月24日01:34:02:未完待续
内部类
- 在类内部的类
- 和其他数据/函数一样是外部类的成员=>有成员的权利,能够访问外部类的成员(包括private member)
匿名类
- 在new对象时给出定义,形成匿名类
- 匿名类可以继承某个类,或者实现某个接口
- Swing消息机制广泛使用匿名类=>减少大量函数声明
MVC设计模式
- 表现和数据分离的同时,加入控制control=>根据用户的输入对model进行调整
- View和Controller之间没有直接联系
- control通过修改model,来对view进行修改=>降低耦合,简化VIEW
异常捕捉
try{...}catch(XException e){...}
- 一个try,可以堆叠多个catch
异常捕捉机制
- 有异常抛出
位置 | 行为 |
---|---|
在函数 | 返回调用者 |
在try | 执行catch |
其他情况 | 退到外层 |
捕捉到异常
捕捉到异常,可以对异常对象做什么?
e.getMessage()
e.toString()
e.printStackTrace()
throw e
=>将异常交给上层处理
异常
- 有不寻常的事情发生,停止原本要做的事,让其他地方的代码来处理
- 清晰区分了业务逻辑代码和异常处理代码
- 相较传统的通过ErrorCode和层层嵌套的if进行异常处理,二者夹杂在一起
异常抛出与声明
- 抛出异常的地方
- 添加throw声明(函数声明)
- 用try-catch包括起来
- XException继承自Exception
- Exception继承自Throwable
运行时异常
- 类似于ZeroDivisionException之类的大量运行时会产生的异常
- 每种情况都catch处理会让代码量急剧膨胀
- 可以使用
catch(Execption e){...}
捕获所有异常来统一处理=>避免过多的异常处理代码
流
- 流是IO的方式
- 流是单向的
流的基础类
- InputStream
- OutputStream
- 二者都是以字节为操作单位的
文件流
- FileInputStream
- FileOutputSteam
流过滤器
- 将输入流转化为特定编码格式
文本流
- InputStream/OutputStream只能处理Byte
- 处理文本用Reader/Writer=>处理Unicode字符
- 文件不一定是Unicode编码
=>可以借助Stream打开文件,再通过过滤器,转化为Unicode,再传给Reader/Writer
汉字编码
- GBK和UTF-8
InputStreamReader(InputStream,Charset)
指定Charset打开
格式化输入输出
- PrintWriter
format()
print()
printf()
println()
- Scanner
next...()
- 如何选择Stream/Reader/Scanner
- Binary=>Stream
- Text=>Reader
- Other(Data)=>Scanner
流的应用
- 常用于内存数据或网络通信
- Read和其他的ReadLine(),nextInt()等基于它的函数都是阻塞的,在得到所需内容前会停来
- 要改阻塞为非阻塞有两种办法
- 多线程
- NIO的channel选择机制
对象序列化
- 将对象转化为文本
- ObjectInputStream
- ReadObject()
- ObjectOutputStream
- Serialization Interface
2021年4月27日16:51:12:到这里课程就结束了.感觉翁恺老师这门课是真的神,尤其是OOP和后面的异常,流讲特别好,深入浅出.
不过我一下子应该不能全部消化.这可以做个roadmap,之后逐块深入.