JAVA基础复习
[[Java 基础知识]]
考试月忙着复习计算机病毒,网络攻防,协议分析,密码学,还有实训.
一个月没接触JAVA,都快忘光了.
之前买的SpringBoot的书,太多Spring的annotation没学过,看得很难受.
所以暑假买了本SSM的书,从Spring->SpringMVC->SpringBoot一步步学起.
然后,看书之前,先把Java和Java Web的基础内容复习一下.
Hello World
首先,从最简单的hello world来看Java的基础语法和编译执行过程.
package com.company;
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
第一句的package com.company;
,就是声明当前java文件所在的包,类似于C/C++里的library,Python里的package.
不过其他语言都只通过文件夹和路径,来限定一个package的范围.
Java在每个源文件头部,都显示地做了声明.
接下来是我们的类声明和主函数声明定义.
Java是一门彻头彻尾的面向对象语言,通过类和方法来组织代码,就像面向过程的C,用函数来组织代码一样.
有了类和对象,这层更高级的抽象,为代码复用和更高级的设计模式奠定了基础.
第二句public class Main
,类的定义,由三部分组成访问修饰符 class 类名 {...}
class
是声明类的关键字,类名就是这个类的名字,都好理解.
访问修饰符呢,得解释一下.
Java中有很多修饰符,主要分为两大类
- 访问修饰符
- 非访问修饰符
访问修饰符,顾名思义,就是用来控制 类,变量,方法和构造函数 访问权限的修饰符,有如下四类:
- default(默认,缺省):同一包内可见,不使用任何修饰符.可用于类,接口,变量,方法.
- private:同一类内可见.可用于变量,方法.=>不能修饰类,类外不可见
- public:对所有类可见.可用于类,接口,变量,方法.
- protected:对同一包内的类和所有子类可见.可用于变量,方法.=>不能修饰类
非访问控制符,包括static,fianl,abstract,synchronized,volatile等等,之后用到再逐一介绍.
详见参考资料.
第三句public static void main(String[] args)
这些关键字依次是 访问修饰符,static关键字,返回类型,方法名,参数类型和参数名
- public访问修饰符,表示该函数对所有类可见.
- static关键字表示该函数为静态函数,程序运行时便会载入内存.(详见参考资料)
- void返回类型,表示返回null
- main为方法名,主函数的意思
- String[]表示参数类型为字符串数组类型
- args为参数名
System.out.println("Hello World!");
则是调用Java类库的println()
函数输出字符串Hello World!
具体Java类库包含哪些package,以及具体功能详见参考资料.
解析完源码后,我们就可以进行编译执行了.
在命令行中输入javac HelloWorld.java
将Java源程序(.java)编译成字节码程序(.class)
接着输入java HelloWorld
解析执行字节码程序
如图所示,和C/C++这种编译型程序比起来,Java程序多了通过解释器进行解释执行的过程.
这使得Java程序效率较C/C++低,但是也获得了跨平台的优势(在Windows上开发的程序,能够直接在Linux服务器上正常的运行).
同时因为Java程序有编译成字节码,而不是像Python一样完全依靠解析,所以也有不错的性能.
就我认为,综合来说,Java在性能,可移植和开发效率性达成了一个比较好的平衡,非常适合商业软件的开发.
2021年7月8日20:17:47:上面helloworld的例子,把基本的class,package,method,paramater,modifier都做了介绍.
Java基础语法还包括variable,array,enumeration,interface,loop/conditional statement,Java API,exception handling,OOP...
接下来,将逐一过一遍.
类和对象
- Employee.java
public class Employee {
static int number=0;
String name;
String designation;
int age;
double salary;
public Employee(String name){
this.name = name;
number+=1;
}
public void setAge(int age){
this.age = age;
}
public void setSalary(double salary){
this.salary=salary;
}
public void setDesignation(String designation){
this.designation=designation;
}
public void printEmployee(){
System.out.println("name:"+this.name);
System.out.println("age:"+this.age);
System.out.println("designation:"+this.designation);
System.out.println("salary:"+this.salary);
}
}
- Main.java
public class Main {
public static void main(String[] args) {
Employee emp1 = new Employee("Dou");
Employee emp2 = new Employee("Smith");
System.out.println(Employee.number);
emp1.setAge(18);
emp1.setSalary(10086.11);
emp1.setDesignation("CEO");
emp1.printEmployee();
}
}
如上这段代码,演示了类和对象中一些常用的概念.
- 一个类中的三种变量:
- 局部变量:method,constructor中的变量.
- 成员变量:定义在类中的,method外的变量,如name,designation,age,salary
- 类变量:类中,method外,的static类型变量,如上述的number
- 构造函数:函数名与类名相同的函数
public Employee(String name)
,多个构造函数可重载. - 创建一个对象的三个过程
- 声明:声明一个对象的名词和类型
Employee emp1
- 实例化:使用关键字new来创建一个对象
Employee emp1 = new Employee
- 初始化:使用new创建对象时,会调用构造方法初始化对象
Employee emp1 = new Employee("Dou");
- 声明:声明一个对象的名词和类型
- 访问实例变量和方法
- 通过已创建的对象来访问成员变量和方法
emp1.setAge(18); emp1.printEmployee();
- 通过已创建的对象来访问成员变量和方法
- 源文件声明规则
- 一个源文件只能有一个public类
- 源文件名应该和public类的类名保持一致
基本数据类型
- 两大类数据类型
- 内置数据类型
- 四个整数型
- byte
- 8位 有符号 二进制补码表示的整数
- 取值范围:-128(-27)~127(27-1)
- 默认值:0
- short
- 16位 有符号 二进制补码表示的整数
- 取值范围:-32768(-215)~32767(215-1)
- int
- 32位 有符号 二进制补码表示的整数
- 取值范围:-2147483648(-231)~2147483647(231-1)
- long
- 64位 有符号 二进制补码表示的整数
- 取值范围:-9223372036854775808(-263)~9223372036854775803(263-1)
- 一般用在比较大整数的系统上
- 默认值0L
- byte
- 两个浮点型
- float
- 单精度 32位 符合IEEE 754标准的浮点数
- 默认值:0.0f
- double
- 双精度 64位 符合IEEE 754标准的浮点数
- 默认值:0.0d
- float
- 字符类型
- char
- 16位 Unicode字符
- 默认值: 'u0000'
- char
- 布尔型
- boolean
- true/false
- 默认值:false
- boolean
- 四个整数型
- 引用数据类型
- 类似于C++中的指针,指向一个对象,指向对象的变量是引用变量
- 对象,数组都是引用数据类型
- 默认值为null
- 内置数据类型
- 常量
- 程序运行时不能修改
- 用
final
进行修饰,声明方式与变量相似final double Pi = 3.1415926;
0
开头表示八进制,0x
开头表示十六进制int octal = 0144;
int hexa = 0x64;
- 类型转化
- 自动类型转换
- 转换前数据类型位数要低于转换后数据类型位数
- byte,short,char—> int —> long—> float —> double
- 转换前数据类型位数要低于转换后数据类型位数
- 强制类型转换
- 可以把容量大的类型转成容量小的类型
- 转换过程可能导致溢出或者精度损失
int i = 128;
byte b = (byte)i;
- byte类型最大值为127,所以该转换会导致溢出
- 自动类型转换
变量类型
- 变量声明格式
type identifier [= value][, identifier [= value]...];
- type是Java数据类型
- identifier是标识符/变量名
- 中间可以用逗号隔开,同时声明多个同类型变量
- 变量类型
- 类变量/静态变量
- 独立于方法外的变量,用
static
修饰 - 无论创建了多少个对象,类只有类变量一份拷贝
- 除了被声明为常数外,很少使用
- 在第一次访问时创建,程序结束时销毁
- 有默认值
- 可通过
ClassName.VariableName
的方式访问 - 声明为
public static final
类型时,建议变量名使用大写字幕.- 如果不是
public
,final
类型,命名方式与实例变量,局部变量相同
- 如果不是
- 独立于方法外的变量,用
- 实例变量
- 方法外,没有
static
修饰的变量 - 在对象实例化后创建,对象销毁时销毁
- 至少被一个方法调用
- 访问修饰符可修饰实例变量
- 对类中方法可见=>一般把实例变量设为私有,再通过访问修饰符使其对子类可见
- 有默认值 0,nul,etc
- 可以通过变量名访问=>但在静态方法/其他类中,应该用完全限定名
ObjectReference.VariableName
- 方法外,没有
- 局部变量
- 类的方法中的变量
- 方法执行时创建,完成后销毁
- 访问修饰符不能用于局部变量
- 仅在声明的方法内可见
- 在栈上分配
- 无默认值,必须手动初始化后才可使用
- 类变量/静态变量
- 例子
public class Variable{ static int classVariable = 0; String instanceVariable = "hello world"; public void method(){ int localVariable = 0; } }
修饰符
- 访问修饰符
- 用来控制类,变量,方法的访问控制权限的修饰符.
- default=>同package内可见,不用修饰符
- private=>同class内可见(不能修饰外部类)
- 私有访问类型的变量只能通过类中公共的getter方法被外部类访问
- public=>对所有class可见
- interface里的变量都隐式声明为
public static fianl
,方法为public
- interface里的变量都隐式声明为
- protected=>同package内的所有subclass可见(不能修饰外部类)
- 如果subclass和superclass不在同一个package=>可以继承superclass的,protected方法,但不能直接访问
- 非访问修饰符
- 用于实现其他功能的修饰符
- static
- 静态变量/类变量:
- static修饰,独立于对象的静态变量.
- 无论类实例化多少次,只有一份拷贝.
- 静态方法:
- static修饰,独立于类的方法.
- 静态方法不能使用非静态变量.
- 静态方法从参数表得到数据,然后计算.
- 静态变量/类变量:
- final
- final变量
- 变量赋值后不能被修改
- 常和static一起用来创建常量
- final方法
- 可被子类继承,但不能被子类重写=>防止方法内容被修改
- final类
- 不能被继承
- final变量
- abstract
- 抽象方法
- 没有任何实现的方法=>具体实现由子类提供
- 任何继承抽象类的子类必须实现父类的所有抽象方法,除非子类也是抽象类
- 不能被声明成static,final
- 没有任何实现的方法=>具体实现由子类提供
- 抽象类
- 不能实例化对象
- 不能同时被abstract和final修饰
- 抽象类可以不包含抽象方法,但是如果一个类含抽象方法,就必须声明为抽象类=>否则编译错误
- 抽象方法
- synchronized
- 声明方法同一时间只能被一个线程访问
- volatile
- 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值.且该值发生变化时,会强制要求线程将变化值写回共享内存=>任何时刻,两个不同线程总是看到某个成员变量的同一个值
运算符
- 算术运算符
- +
- -
- *
- /
- %
- ++
- --
- 关系运算符
- ==
- !=
- >
- <
- >=
- <=
- 位运算符
- & =>and
- | =>or
- ^ =>xor
- ~ =>not
- <<
- >> =>按位右移
- >>> =>按位右移,补0
- 逻辑运算符
- &&
- ||
- !
- 赋值运算符
- =
- +=
- -=
- *=
- /=
- (%)= =>A%=B 等价于 A=A%B
- <<=
- >>=
- &=
- ^=
- |=
- 其他运算符
- 三目运算符
variable x = (expression) ? value if true : value if false
- instanceof
- 检查实例是否为指定类型(数据类型/类/接口)
( Object reference variable ) instanceof (class/interface type)
- 三目运算符
循环结构
- while循环
while( 布尔表达式 ) {
//循环内容
}
- do...while循环
- 先做一遍,在看是否满足循环条件
do {
//代码语句
}while(布尔表达式);
- for循环
for(初始化; 布尔表达式; 更新) {
//代码语句
}
- 增强 for 循环
- 主要用于遍历数组
for(声明语句 : 表达式) {
//代码句子
}
声明语句=>声明局部变量,类型与其后数组类型匹配.
表达式=>要访问的数组名or返回值为数组的方法
- continue和break
- break
- 跳出本层循环
- continue
- 跳过本次循环=>判断条件是否满足,进行下一次循环
- break
条件语句
- if-else
if(布尔表达式){
//如果布尔表达式的值为true
}else if(布尔表达式 2){
//如果布尔表达式 2的值为true执行代码
}else{
//如果以上布尔表达式都不为true执行代码
}
- switch-case
switch(expression){
case value :
//语句
break; //可选
case value :
//语句
break; //可选
default : //可选
//语句
}
switch语句中的变量可以是byte,short,int,char,String(Java SE7)
Number&Math类
- WrapperClass
-
在开发中,我们常常要使用对象,而不是内置数据类型,所以Java为每个内置数据类型都提供了对应的WrapperClass
-
boolean=>Boolean
-
byte=>Byte
-
short=>Short
-
int=>Integer
-
long=>Long
-
char=>Character
-
float=>Float
-
double=>Double
-
- Integer,Byte..都是抽象类java.lang.Number的子类
- 编译器可以把内置类型当做对象使用(装箱),也可以把一个对象拆箱为内置类型
- 比如让内置类型变量和包装类对象相加
- Number类常用方法
- xxxValue=>将Number对象转化为xxx数据类型的值并返回
- compareTo=>将Number对象与参数比较
- equals=>判断Number对象是否与参数值相等
- valueOf=>返回一个Number对象指定的内置数据类型
- toString=>以字符串形式返回
-
- Math类
- 包含了执行基本数学运算的属性和方法
- Math的方法都被定义为static,通过Math类可以直接在主函数中调用
- parseInt=>将字符串解析为int类型
- abs=>返回参数的绝对值
- ceil=>返回大等于参数的最小整数,类型为double
- floor=>返回小等于参数的最大整数
- rint=>返回与参数最接近的整数
- round=>四舍五入
- min=>返回两个参数最小值
- max=>返回两个参数最大值
- exp=>返回自然数底数e的参数次方
- log=>返回参数的自然数底数的对数值
- pow=>返回第一个参数的第二参数次方
- sqrt=>算术平方根
- sin=>求正弦值
- cos,tan,asin,acos,atan
- atan2=>将笛卡尔坐标转化为极坐标,并返回极坐标角度
- toDegrees=>将参数转化为角度
- toRadians=>将角度转化为弧度
- random=>生成随机数
Character类
- character类用于对单个字符进行操作
- character类在对象中包装了一个基本数据类型char的值
- 为什么不用内置数据类型char,而是使用character类?
- character类提供了一系列操作字符的方法
- 和Number类一样,character类和char内置数据类型可以互相转换(装箱,拆箱)
- 方法
- isLetter()
- isDigit()
- isWhitespace()
- isUpperCase()
- isLowerCase()
- toUpperCase()
- toLowerCase()
- toString()
- 转义字符
- \t 制表符,插入一个Tab
- \b 插入一个人后退键
- \n 换行
- \r 插入回车
- \f 插入换页符
- \' 单引号
- \" 双引号
- \\ 反斜杠
String类
- 创建字符串
- 直接赋字符串常量
String s1="iamnotastring"
- 字符串存储在公共池里,多个变量值相同,则指向同一个存储单元
- 构造函数
String s2= new String("iamnotastring")
- 存储在堆上,值相同也是不同存储单元
- 还可以用char[]来初始化字符串
- 直接赋字符串常量
- String类不可变,一旦创建完对象,值就无法改变
- 如果需要对字符串做多次修改,应该选择使用StringBuffer&StringBuilder类
- 通过
length()
方法获取长度 - 通过
concat()
方法,或者.
,+
操作符,连接字符串 - 通过String类的静态方法
format()
,可以创建一个格式化的String对象 - String类 更多方法
StringBuffer & StringBuilder 类
- 上图可见StringBuffer,StringBuffer,String三个类的关系
- String类实现了charsequence,但没有实现appendable接口,所以是不可修改的字符序列
- StringBuilder和StringBuffer都是AbstractStringBuilder(实现了appendable接口)的子类,所以是能够进行修改的字符序列
- StringBuffer在使用时对对象本身进行操作,不产生新对象=>需要对字符串修改时推荐使用StringBuffer
- StringBuilder在Java5被提出,和StringBuffer最大的区别在于线程不安全(不能同步访问),但是也因此有速度优势,所以多数情况下还是建议使用StringBuilder类
- StringBuffer类 方法
- append
- reverse
- delete
- insert
- replace
- capacity
- charAt(int index)
- ensureCapacity(int minimumCapacity)
- getChars(int srcBegin,int srcEnd,char[] dst,int dstBegin)
- indexOf(String str)
- lastIndexOf
- length
- setCharAt
- subSequence
- subString
- toString
数组
- 用来存储固定大小的同类型元素
- 声明
- 推荐方法
dataType[] arrayRefVar;
- 效果相同,不推荐=>为方便C/C++程序员看懂而设计
dataType arrayRefVar[];
- 推荐方法
- 创建数组
arrayRefVar = new dataType[arraySize];
- 使用
dataType[arraySize]
创建了一个数组 - 把新创建的数组赋值给arrayRefVar
- 使用
- 创建和声明2 in 1
dataType[] arrayRefVar = new dataType[arraySize];
- 声明,创建,初始化3 in 1
dataType[] arrayRefVar = {value0,value1,...};
- 处理数组
- 数组元素类型和大小都是固定的=>一般用For-Each循环遍历处理
for(type element:array){ ... }
- 数组作为参数
public static void printArray(int[] array){...}
- 数组作为返回值
public static int[] reverse(int[] list) {...}
- 多维数组
- 声明定义
type[][] typeName = new type[typeLength1][typeLength2];
- 引用
arrayName[index1][index2]
- 声明定义
- Arrays类
- java.util.Arrays类提供了很多静态方法来方便地操作数组
- 给数组赋值=>
public static void fill(int[] a, int val)
=>将指定的 int 值分配给指定 int 型数组指定范围中的每个元素 - 对数组排序=>
public static void sort(Object[] a)
=>对指定对象数组根据其元素的自然顺序进行升序排列 - 比较数组=>
public static boolean equals(long[] a, long[] a2)
=>如果两个指定的 long 型数组彼此_相等,则返回 true - 查找数组元素=>
public static int binarySearch(Object[] a, Object key)
=>用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。
时间日期
- java.util包提供了Date类来封装当前的日期和时间
- 构造函数
Date()
自动获取当前日期和时间来初始化对象Date(long millisec)
通过1970年1月1日至今的毫秒数来初始化对象
- 方法
boolean after(Date date)
=>若当调用此方法的Date对象在指定日期之后返回true,否则返回falseboolean before(Date date)
=>若当调用此方法的Date对象在指定日期之前返回true,否则返回falseObject clone()
=>返回此对象的副本int compareTo(Date date)
=>比较当调用此方法的Date对象和指定日期。两者相等时候返回0。调用对象在指定日期之前则返回负数。调用对象在指定日期之后则返回正数。int compareTo(Object obj)
=>若obj是Date类型则操作等同于compareTo(Date) 。否则它抛出ClassCastException。boolean equals(Object date)
=>当调用此方法的Date对象和指定日期相等时候返回true,否则返回false。long getTime()
=>返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。int hashCode()
=>返回此对象的哈希码值void setTime(long time)
=>用自1970年1月1日00:00:00 GMT以后time毫秒数设置时间和日期。String toString()
=>把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy- dow(DayOfWeek) 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。
- 格式化时间
- 使用 SimpleDateFormat 格式化日期
Date dNow = new Date( ); SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss"); System.out.println("当前时间为: " + ft.format(dNow));
- 也可以用printf输出格式化时间
- SimpleDateFormat还可以使用
parse()
方法解析提取字符串中的时间
- 休眠
Thread.sleep(3*1000);
使当前线程休眠3秒
- Calendar类
- 可以获取日期的特定部分(小时,日,分钟)
- 功能比Date类强大,也更复杂
正则表达式
- 定义了字符串的模式,可以用来搜索,编辑,处理文本
- java.util.regex提供了以下三个类
- Pattern
- pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
- Matcher
- Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
- PatternSyntaxExecption
- PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
- Pattern
- 例子
import java.util.regex.*; class RegexExample1 { public static void main(String[] args){ String content = "I am noob " + "from runoob.com."; String pattern = ".*runoob.*"; boolean isMatch = Pattern.matches(pattern, content); System.out.println("字符串中是否包含了 'runoob' 子字符串? " + isMatch); } }
- 正则表达式要用的时候再看,不然看了也是忘
复习完上面这些基础内容
剩下的输入输出流,文件操作,OOP,异常处理
可以看我之前看翁恺老师课程做的笔记
Java 基础知识 - rpish - 博客园 (cnblogs.com)