Java简介
Java由Sun公司发布于1995年5月,是Java面向对象程序设计语言和Java平台的总称。现在的Java是Oracle公司的产品。
Java分为三个体系:
- JavaSE(Java2 Platform Standard Edition,java平台标准版,简称J2SE)
- JavaEE(Java 2 Platform,Enterprise Edition,java平台企业版,简称J2EE)
- JavaME(Java 2 Platform Micro Edition,java平台微型版,简称J2ME)
2005 年 6 月,JavaOne 大会召开,SUN 公司公开 Java SE 6。此时,Java 的各种版本已经更名,以取消其中的数字 “2”:J2EE 更名为 Java EE,J2SE 更名为Java SE,J2ME 更名为 Java ME。
主要特性
简单性
注意:Java底层是C++实现,而非C语言
C中有指针,Java没有指针;C支持多继承,Java使用接口代替多继承。
面向对象
Everything is Object.
Java是纯面向对象(封装、继承、多态、抽象),采用类机制。
可移植性(跨平台)
Compile Once, Run Anywhere
通过对.java源文件编译得到.class字节码文件,通过java.exe运行在各个平台上的JVM。
分布式
Java 语言支持 Internet 应用的开发,在基本的 Java 应用编程接口中有一个网络应用编程接口(java net),它提供了用于网络应用编程的类库,包括 URL、URLConnection、Socket、ServerSocket 等。Java 的 RMI(远程方法激活)机制也是开发分布式应用的重要手段。
多线程
多线程:允许一个应用程序同时存在两个或两个以上的线程,用于支撑事务并发和多任务处理。
在 Java 语言中,线程是一种特殊的对象,它必须由 Thread 类或其子(孙)类来创建。
Java 语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为 synchronized)。
健壮性
自动垃圾回收机制(GC机制)、强类型机制、异常处理等。
安全性
Java程序在JVM(Java虚拟机)中运行。
Java没有指针等语法,避免了非法操作内存。
Java 对通过网络下载的类具有一个安全防范机制(类 ClassLoader),如分配不同的名字空间以防替代本地的同名类、字节代码检查,并提供安全管理机制(类 SecurityManager)让 Java 应用设置安全哨兵。
高性能
Java属于解释型语言
先编译后解释。
Java开发环境
搭建Java开发环境前首先需要下载JDK
JDK是什么?
JDK是整个Java开发的核心
JDK(Java Development Kit,Java开发工具包)是由Sun公司开发的,它包括JRE,一堆Java工具(javac.exe、java.exe)和Java基础的类库。
官网下载地址为Java Downloads | Oracle 中国,目前最新的JDK版本为JDK 19,《Java 2实用教程》这本书中的版本为JDK 16。
JRE是什么?
JRE(Java Runtime Environment,Java运行环境),**包含JVM标准实现及Java核心类库。**JRE是Java运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器)
JVM是什么?
JVM(Java Virtual Machine,Java虚拟机)是一个可执行Java字节码的虚拟机进程,用于解释编译后的字节码文件(.class)。
可以把JVM类比成一台只针对Java程序的PC虚拟机,**在Java的世界中,JVM的地位就像一台PC机器。**正因如此,Java才能够实现”一次编译,到处运行“。
三者关系
- JDK是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。
- JRE是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。
- JVM是整个java实现跨平台的最核心的部分,能够运行以Java语言写的程序。
Java基础知识
引用贯穿Java始终,Java中的“指针”就是引用
文件扩展名
- java源文件扩展名为.java
- 编译java源文件得到的字节码文件扩展名为.class
- javac.exe是java编译器
主类
主类:类的名字和文件名一致,并且包含main函数的类,主类是程序的入口。
- java源文件是由若干个书写形式相互独立的类组成
- java源文件中可以有多个类,可以没有主类
- 如果源文件中有多个类,最多有一个是public类,也可以没有 public类
- java中如果有主类,不一定是public类
- java 应用程序必须要有主类,但是可以不是public类
Java注释
代码注释是极其重要的。注释不仅提高了代码的可读性,也是程序代码可维护性的重要环节之一。
注意:多行注释和文档注释可以嵌套单行注释,但不能嵌套多行注释和文档注释
单行注释
以双斜杠“ // ”标识,只能注释一行内容。
多行注释
包含着“ /* ”和“ */ ”之间,能注释多行内容。为了可读性比较好,一般首行和尾行不写注释。
文档注释
包含在“ /** ”和“ */ ”之间,也能注释多行内容,一般用在类、方法和变量上面,用来描述其作用。
注释内容可以被JDK提供的工具 Javadoc 所解析,生成一套以HTML文件形式体现的该程序的说明文档,一般写在类前。
Java常量
在 Java 中使用 final 关键字来修饰常量,声明方式和变量类似:
1 | final double PI = 3.1415926; |
虽然常量名也可以用小写,但为了便于识别,通常使用大写字母,单词之间下划线隔开表示常量。例如:
1 | final int MAX_VALUE = 520; |
byte、int、long、和short都可以用十进制、16进制以及8进制的方式来表示。
当使用字面量的时候,前缀 0 表示 8 进制,而前缀 0x 代表 16 进制,例如:
1 | int decimal = 100; |
Java转义字符
符号 | 字符含义 |
---|---|
\n | 换行 (0x0a) |
\r | 回车 (0x0d) |
\f | 换页符(0x0c) |
\b | 退格 (0x08) |
\0 | 空字符 (0x0) |
\s | 空格 (0x20) |
\t | 制表符 |
\" | 双引号 |
\’ | 单引号 |
\ | 反斜杠 |
\ddd | 八进制字符 (ddd) |
\uxxxx | 16进制Unicode字符 (xxxx) |
Java反编译
将class文件转换成java文件
语法格式:
1 | javap filename.java |
Java基础语法
- 对象:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
- 类:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
- 方法:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
- 实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定。
基本语法
大小写敏感:标识符Hello不同于hello
类名:类名应遵循“帕斯卡命名法”,即如果类名由多个单词组成,那么每个单词的首字母应该大写,例如HelloWorld。
方法名:方法名应遵循“驼峰命名法”,即如果类名由多个单词组成,那么第一个单词首字母小写,其他单词首字母大写,例如helloWorld。
源文件名:源文件名必须和主类类名相同。
主方法入口:所有的Java程序都从public static void main(String[] args)
方法开始执行。
Java标识符
类名、变量名以及方法名都被称为标识符。
- 首字符必须是字母,美元符号($)或下划线(_)
- 首字符之后可以是字母,美元符号($)、下划线(_)或数字的任意组合
- 关键字不能用作标识符
Java修饰符
- 访问控制修饰符 : default, public , protected, private
- 非访问控制修饰符 : final, abstract, static, synchronized
Java关键字
关键字不能用于常量、变量和任何标识符的名称。
Java关键字可在Java API文档中查询。
Java数据类型
Java 的两大数据类型:
- 基本数据类型
- 引用数据类型
基本数据类型
Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
数据类型 | 默认值 | 大小 | 表示范围 |
---|---|---|---|
byte | 0 | 1字节 | -128(-2^7) ~ 127(2^7-1) |
short | 0 | 2字节 | -32768(-2^15) ~ 32767(2^15-1) |
int | 0 | 4字节 | -2,147,483,648(-2^31) ~ 2,147,483,647(2^31-1) |
long | 0L | 8字节 | -9,223,372,036,854,775,808(-2^63) ~ 9,223,372,036,854,775,807(2^63-1) |
float | 0.0f | 4字节 | 遵循 IEEE 754(二进制浮点数算术标准),取值范围是无限的 |
double | 0.0d | 8字节 | 遵循 IEEE 754(二进制浮点数算术标准),取值范围是无限的 |
boolean | false | 1比特 | true、false |
char | ‘\u0000’ | 2字节 | ‘\u0000’(0)~ ‘\uffff’(65,535) |
引用数据类型
数组,类,接口被称为引用数据类型,共同特点是,他们的字面值并不是一个“值”而是一段地址。
数据类型 | 默认值 |
---|---|
数组 | null |
类 | null |
接口 | null |
注意事项
- 浮点数不能用来表示精确的值,如货币。
- Java的整型常量默认为int型,声明long型常量,须后加‘l’或‘L’
- long型的"L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩,所以最好大写。
- Java的浮点型常量默认为double型,声明float型常量,须后加‘f’或‘F’
- 将较小字节同类数据类型赋值给较大字节同类数据类型是可以的,反之需要用到强制转换
- 布尔型与C/C++不同,其关键字为boolean,且只有true和false两个取值,不能赋值1表示true。
- char类型是一个单一的16为Unicode字符
- String类型,String是项目中必不可少且使用最多的数据类型,它属于引用数据类型中“类”的范畴。
- 一个引用变量可以用来引用任何与之兼容的类型。
Java类型转换
Java是一门强类型语言
Java中的类型转换分为自动类型转换和强制类型转换。
自动类型转换
整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。
把一个表示数据范围小的数值或者变量赋值给另一个表示数据范围大的变量。这种转换方式是自动的,直接书写即可。
强制类型转换
强制类型转换是大范围的数据类型转为小范围的数据类型时进行强制类型转换,需要自己去操作。
强制类型转换格式:
1 | 目标数据类型 变量名 = (目标数据类型)值或变量; |
注意事项
- boolean类型不能与其他基本数据类型相互转换
- 整数默认是int类型,byte、short和char类型数据参与运算均会自动转换为int类型。
- 转换过程中可能导致溢出或损失精度。
- 小数默认是 double 类型浮点型,在定义 float 类型时必须在数字后面跟上 F 或者 f。
Java变量类型
Java语言支持的变量类型有:
- 局部变量:类的方法中的变量。
- 实例变量:独立于方法之外的变量,不过没有 static 修饰。
- 类变量:独立于方法之外的变量,用 static 修饰。
局部变量
- 局部变量声明在方法、构造方法或者语句块中;
- 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;
- 访问修饰符不能用于局部变量;
- 局部变量只在声明它的方法、构造方法或者语句块中可见;
- 局部变量是在栈上分配的。
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。
实例变量
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
- 当一个对象被实例化之后,每个实例变量的值就跟着确定;
- 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
- 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
- 实例变量可以声明在使用前或者使用后;
- 访问修饰符可以修饰实例变量;
- 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;
- 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;
- 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObjectReference.VariableName。
类变量(静态变量)
- 类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外。
- 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
- 静态变量除了被声明为常量外很少使用,静态变量是指声明为 public/private,final 和 static 类型的变量。静态变量初始化后不可改变。
- 静态变量储存在静态存储区。经常被声明为常量,很少单独使用 static 声明变量。
- 静态变量在第一次被访问时创建,在程序结束时销毁。
- 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为 public 类型。
- 默认值和实例变量相似。数值型变量默认值是 0,布尔型默认值是 false,引用类型默认值是 null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
- 静态变量可以通过:ClassName.VariableName的方式访问。
- 类变量被声明为 public static final 类型时,类变量名称一般建议使用大写字母。如果静态变量不是 public 和 final 类型,其命名方式与实例变量以及局部变量的命名方式一致。
注意事项
每个变量都有类型,类型可以是基本类型,也可以是引用类型
变量名必须是合法的标识符,命名遵守驼峰命名法
避免使用单个字符当作变量名
Java运算符
我们可以把运算符分成以下几组:
- 算术运算符
- 关系运算符
- 位运算符
- 逻辑运算符
- 赋值运算符
- 其他运算符
算术运算符
运算符 | 含义 |
---|---|
+ | 求和 |
- | 相减 |
* | 乘积 |
/ | 商 |
% | 求余数(求模) |
++ | 自加一 |
– | 自减一 |
**注意:**当出现在变量前时,会先自加一,在做赋值运算;当出现在变量后时,会先做赋值运算,再自加一。–运算符同理
关系运算符
运算符 | 含义 |
---|---|
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
== | 等于 |
!= | 不等于 |
注意:所有的关系运算符的运算结果都是布尔类型,不是true就是false,不可能是其他值。
位运算符
基于二进制计算
运算符 | 含义 | 例子 |
---|---|---|
& | 如果相对应位都是1,则结果为1,否则为0 | (A&B),得到12,即0000 1100 |
| | 如果相对应位都是 0,则结果为 0,否则为 1 | (A | B)得到61,即 0011 1101 |
^ | 如果相对应位值相同,则结果为0,否则为1 | (A ^ B)得到49,即 0011 0001 |
〜 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 | (〜A)得到-61,即1100 0011 |
<< | 按位左移运算符。左操作数按位左移右操作数指定的位数。 | A << 2得到240,即 1111 0000 |
>> | 按位右移运算符。左操作数按位右移右操作数指定的位数。 | A >> 2得到15即 1111 |
>>> | 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 | A>>>2得到15即0000 1111 |
逻辑运算符
运算符 | 含义 | 结果 |
---|---|---|
& | 逻辑与(可以翻译成并且) | 两边都是true,结果才是true |
│ | 逻辑或(可以翻译成或者) | 有一边是true,结果就是true |
! | 逻辑非(取反) | !true = false、!false = true |
&& | 短路与 | 两边都是true,结果才是true |
││ | 短路或 | 有一边是true,结果就是true |
短路与&& 和 逻辑与&的区别
两个运算符的运算结果没有任何区别
“短路与&&”运算符会发生短路现象,即当左侧表达式为false时,不再执行判断右侧表达式。例如:
1 | boolean left = false; |
因此从效率方面来说,&&比&的效率高一些。因为逻辑与&不管左侧表达式结果是什么,第二个表达式一定会执行。
短路或|| 和 逻辑或|同理
赋值运算符
操作符 | 描述 | 例子 |
---|---|---|
= | 赋值 | C = A + B将把A + B得到的值赋给C |
+= | 加等 | C + = A等价于C = C + A |
-= | 减等 | C - = A等价于C = C - A |
*= | 乘等 | C * = A等价于C = C * A |
/= | 除等 | C / = A,C 与 A 同类型时等价于 C = C / A |
%= | 模等 | C%= A等价于C = C%A |
<<= | 左移位赋值运算符 | C << = 2等价于C = C << 2 |
>>= | 右移位赋值运算符 | C >> = 2等价于C = C >> 2 |
&= | 按位与赋值运算符 | C&= 2等价于C = C&2 |
^= | 按位异或赋值操作符 | C ^ = 2等价于C = C ^ 2 |
|= | 按位或赋值操作符 | C | = 2等价于C = C | 2 |
其他运算符
条件运算符(三目运算符)
该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。
1 | variable x = (expression) ? value if true : value if false |
字符串连接运算符(+)
+运算符再Java中有两个作用:
- 求和
- 字符串拼接
当+运算符两边都是数值类型时,执行求和操作
当+运算符任意一边为字符串类型,则执行拼接操作,例如:
1 | int a = 520; |
instanceof 运算符
该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)。
instanceof运算符使用格式如下:
1 | ( Object reference variable ) instanceof (class/interface type) |
如果运算符左侧变量所指的对象,是操作符右侧类或接口(class/interface)的一个对象,那么结果为真。例如:
1 | String name = "James"; |
Java输入、输出数据
输入方法
Scanner类
- 使用Scanner类,首先需要导入java.util.Scanner包
1 | import java.util.Scanner; |
- 创建一个Scanner对象
1 | Scanner reader = new Scanner(System.in); |
- Scanner类对象的方法如下:
方法 | 描述 |
---|---|
nextInt() | 从用户读取int值 |
nextFloat() | 从用户读取float值 |
nextBoolean() | 从用户读取boolean值 |
nextLine() | 从用户读取一行文本 |
next() | 从用户那里读取一个单词 |
nextByte() | 从用户读取byte值 |
nextDouble() | 从用户读取double值 |
nextShort() | 从用户读取short值 |
nextLong() | 从用户读取long值 |
如要输入一个int型整数,使用方法如下:
1 | reader.nextInt(); |
输出方法
System.out.println()
换行输出
1 | System.out.println('z'); |
运行结果:
1 | z |
System.out.print()
不换行输出
1 | System.out.print('z'); |
运行结果:
1 | zc |
System.out.printf()
格式化输出,和c语言的printf()类似
1 | System.out.printf("%s\n","lzc"); |
运行结果:
1 | lzc |
Java选择结构
if条件分支语句
if语句
1 | if(布尔表达式) { |
if……else语句
1 | if(布尔表达式) { |
if……else if……else语句
else if可以有若干个
1 | if(布尔表达式1) { |
switch开关语句
switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
语法:
1 | switch(表达式) { |
switch case 执行时,一定会先进行匹配,匹配成功返回当前 case 的值,再根据是否有 break,判断是否继续输出,或是跳出判断。
switch case 语句有如下规则:
- switch 语句中的变量类型可以是: byte、short、int 或者 char。从 Java SE 7 开始,switch 支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。
- switch 语句可以拥有多个 case 语句。每个 case 后面跟一个要比较的值和冒号。
- case 语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量。
- 当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句。
- 当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。case 语句不必须要包含 break 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句。
- switch 语句可以包含一个 default 分支,该分支一般是 switch 语句的最后一个分支(可以在任何位置,但建议在最后一个)。default 在没有 case 语句的值和变量值相等的时候执行。default 分支不需要 break 语句。
Java循环结构
for循环
语法格式:
1 | for(初始化; 布尔表达式; 更新) { |
Java5 引入了一种主要用于数组的增强型 for 循环。
Java 增强 for 循环语法格式如下:
1 | for(声明语句 : 表达式) { |
**声明语句:**声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
**表达式:**表达式是要访问的数组名,或者是返回值为数组的方法。
while循环
语法格式:
1 | while( 布尔表达式 ) { |
只要布尔表达式为 true,循环就会一直执行下去。
do…while循环
语法格式:
1 | do { |
do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。
break关键字
break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。
break 跳出最里层的循环,并且继续执行该循环下面的语句。
语法:
1 | break; |
continue关键字
continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
语法:
1 | continue; |
Java数组
Java 语言中提供的数组是用来存储固定大小的同类型元素。
声明数组
声明数组有两种格式
1 | dataType[] arrayRefVar; |
1 | dataType arrayRefVar []; |
注意: 建议使用 dataType[] arrayRefVar 的声明风格声明数组变量。 dataType arrayRefVar[] 风格是来自 C/C++ 语言 ,在Java中采用是为了让 C/C++ 程序员能够快速理解java语言。
声明二维数组,则两个方括号:
1 | dataTepy [][] arrayRefVar; |
创建数组
Java语言使用new操作符来创建数组
语法格式:
1 | arrayRefVar = new dataType[arraySize]; |
数组变量的声明,和创建数组可以用一条语句完成,如下所示:
1 | dataType[] arrayRefVar = new dataType[arraySize]; |
Java中的数组索引从0开始,索引值从0到arrayRefVar.length - 1
处理数组
数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者 For-Each 循环。
For-Each循环
JDK 1.5 引进了一种新的循环类型,被称为 For-Each 循环或者加强型循环,它能在不使用下标的情况下遍历数组。
语法格式如下:
1 | for(type element: array) { |
例如:
1 | double[] myList = {1.9, 2.9, 3.4, 3.5}; |
Java类和对象
类和对象是面向对象编程(Object Oriented Programming)中最基础的组成单元。
类和对象的基本概念
类:是抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法)。
对象:对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。
类是对象的模板,对象是类的实例。
类只有通过对象才能使用,先产生类再产生对象。类不能直接使用,对象是可以直接使用的。
类和对象的定义和使用
在Java中定义类需要使用class关键字。语法如下:
1 | class <class_name> { |
例如创建一个Person类
1 | class Person { |
类定义好以后要依靠对象来使用,由于类属于引用数据类型,那么对象的产生格式如下:
1 | <class_name> <对象名> = new <class_name>(); |
或
1 | <class_name> <对象名> = null; |
引用数据类型与基本数据类型最大的不同在于:引用数据类型需要内存的分配和使用。所以,关键字new的主要功能就是分配内存空间,也就是说,只要使用引用数据类型,就要使用关键字new来分配内存空间。
当一个实例化对象产生之后,可以按照如下的方式进行类的操作:
对象.属性:表示调用类之中的属性;
对象.方法():表示调用类之中的方法。
例如:
1 | Person lzc = new Person(); |
成员变量与局部变量
- 成员变量:类中方法外的变量
- 局部变量:方法中的变量
区别 | 成员变量 | 局部变量 |
---|---|---|
类中位置 | 类中方法外 | 类中方法内 |
内存中位置 | 堆内存 | 栈内存 |
生命周期 | 与对象的生命周期相关 | 与方法的生命周期相关 |
初始化值 | 有默认初始化值 | 无默认初始化值,先定义赋值在使用 |
成员变量的默认初始化值:
基本数据类型符合其默认值规则
引用数据类型默认值为null
this关键字
this修饰的变量用于指代成员变量
1 | class Person { |
方法
定义
方法的定义包括两部分:方法头和方法体。
一般格式为:
1 | 访问修饰符 返回数据类型 方法名 (形参列表) { |
**访问修饰符:**作用是控制方法的使用范围,有四种(public,protected,default,private),不写访问修饰符时,默认为public。
**返回数据类型:**可以为任意类型,包含基本类型或引用类型(数组、对象)。如果方法要求有返回数据类型,则方法体中最后的return的值必须和返回数据类型一致或兼容。
**方法名:**遵循驼峰命名法,见名知义。
方法的调用
样例代码
1 | class A { |
同类调用
同一个类中的方法调用,直接调用即可。
如类A
中的sayBye方法
要调用同类的sayHello方法
,则调用方法如下:
1 | public void sayBye() { |
跨类调用
跨类中的方法调用,需要通过对象名调用。
如类B中的sayOk()方法要调用类A中的sayHello方法,则调用方法如下:
1 | public void sayOk() { |
参数传递
在Java中,基本数据类型和String类作为参数传递时,都是按值传递。
引用类型传递的是地址(传递的也是值,但是这个值是地址),所以可以通过形参影响实参。
访问权限
定义
对象是否可以通过.
运算符操作自己的变量或调用类中的方法。
访问权限分类
- 公共类
- 非公共类
使用public
修饰的类为公共类,反之为非公共类。
四种访问权限
- private
- default(包访问权限,一般省略)
- public
- protected
public
用public
关键字修饰的成员变量和成员方法称为共有变量
和共有方法
。
被public
修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包访问。
protected
用protected
关键字修饰的成员变量和成员方法成为受保护的成员变量
和受保护的成员方法
。
被protected
修饰的类、属性以及方法只可跨类访问,不允许跨包访问。
友好(default默认权限)
不用private
,public
,protect
关键字修饰的成员变量和方法成为友好变量
和友好方法
。
下面这个add()方法就是友好方法
1 | int add(int a,int b) { |
在同一个包中,一个类中的友好变量和友好方法,在另一个类中通过类名来操作这个成员变量和调用方法。在不同包中,如果源文件用import
语句引入另一个包中的类,并使用该类创建了一个对象,那么该类的对象将不能访问自己的友好变量和友好方法。
private
用private
关键字就是的成员变量和成员方法称为私有变量
和私有方法
。
被private
修饰的成员变量和成员方法只能在本类中使用。
如果需要被别的类使用,则需用通过方法来返回值
1 | class Person { |
四种访问权限差异表
访问权限 | 同类 | 同包 | 子类 | 非子类的外包类 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
private | √ | × | × | × |
方法重载
重载(overloading)是在同一个类中,名同参数不同。
每个重载的方法(或构造函数)都必须有不同的参数类型列表。
重载是面向对象的一个基本特性。
说明:
- 方法名相同
- 方法的参数类型列表不同
- 方法的返回值可以不相同
- main方法可被重载
- 声明为final的方法不能被重载
- 声明为static的方法不能被重载,但可被声明
具体实例:
1 | class Lzc { |
在主方法中执行以下代码时
1 | Lzc t = new lzc(); |
程序输出结果:
1 | 76 //"L" |
重载分辨:方法名称相同时,编译器会自动根据相应的调用方法,去选择对应的方法,如果匹配失败,则报错。
封装
面向对象三大特性:封装、继承和多态
封装的好处:保护性和易用性
private实现属性和方法的封装只是封装的一种。、
private:私有的,被private修饰的属性和方法,只在当前类的内部可见,出了类的{},对外部就完全隐藏了,外部不知道有其存在。
public:公共的,公开的,被public修饰的东西,在当前程序(项目)中都是可见的,都是可以使用的。
封装原则
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
例如成员变量private,提供对应的方法。
上转型对象和下转型对象
上转型对象:子类转父类
下转型对象:父类转子类
基于继承。
上转型对象
1 | A a = new B(); //B是A的子类 |
称a为子类对象b的上转型对象。
- 上转型对象不能操作子类声明定义的成员变量、成员方法。
- 上转型对象可以访问子类继承或隐藏的成员变量,可以使用子类继承或重写的方法。
- 将上转型对象再强制转换成子类对象,就恢复成子类对象,相应的属性和方法随之恢复。
- 如果子类重写了父类的某个方法,上转型对象调用的是重写的方法。
上转型是父类的引用指向了子类的对象,所以它指向的是父类应该拥有的属性和方法。
下转型对象
如果直接使用下转型
1 | B b = new A(); //B是A的子类 |
会出错的。
因为向下转型,父类不具有子类的方法。
但是可以对上转型对象进行下转型,这类似于+1-1的过程。
为什么要用上转型对象
方便面向接口的编程思想和面向抽象的编程思想,实现了方法的多态,降低了程序之间关联性。
Java包
包的概念
包(package)是一种组织类的方式,使用包的主要目的是保证类的唯一性。
Java程序中,为了开发方便,会将功能相似的类放入一个文件夹中,这个文件结构就是包。
引入类库中的包(import语句)
import语句:引入包中的类
1 | import 包名.包中的类; //引入某个包中具体的某个类 |
Java String类
字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。
前言
- String表示字符串类型,属于
引用数据类型
,不属于基本数据类型。 - 在java中随便使用
双引号括起来
的都是String对象。 - C语言中没有字符串这种数据类型,只有字符数组。
- C中既包括C语言的字符数组(C风格字符串),也有C引入的string类型(‘s’小写)。
- Java中,有String类型(‘S’大写),String类型不属于8大基本类型。
创建字符串
1 | String str = "love"; |
在代码中遇到字符串常量时,这里的值是 “love”,编译器会使用该值创建一个 String 对象。
和其他对象一样,可以使用关键字和构造方法来创建String对象。
1 | String str = new String("love"); |
字符串方法
方法名 | 作用 |
---|---|
charAt(int index) | 返回指定位置的字符 |
compareTo(String anotherString) | 比较两个字符串。相等返回0;前大后小返回1;前小后大返回-1 |
contains(CharSequence s) | 判断字符串是否包含s |
endsWith(String suffix) | 判断字符串是否以suffix结尾 |
equals(Object anObject) | 判断两个串是否相等 |
equalsIgnoreCase(String anotherString) | 忽略大小写判断两个串是否相等 |
getBytes() | 将字符串串变成字节数组返回 |
indexOf(String str) | 返回str在字符串第一次出现的位置 |
isEmpty() | 字符串是否为空 |
length() | 字符串长度 |
lastIndexOf(String str) | 返回str最后一次出现的位置 |
replace(CharSequence target, CharSequence replacement) | 用replacement替换字符串target的字符 |
split(String regex) | 将字符串以regex分割 |
startsWith(String prefix) | 判断字符串是否以prefix开始 |
substring(int beginIndex) | 从beginIndex开始截取字串 |
substring(int beginIndex, int endIndex) | 截取beginIndex到endIndex - 1的字符串 |
toCharArray() | 将字符串转换乘char数组 |
toLowerCase() | 字符串转小写 |
toUpperCase() | 字符串转大写 |
trim() | 去除字符串两边空格 |
静态方法 | |
valueOf(int i) | 将 i 转换成字符串 |
关于字符串匹配 == 和 equals() 的区别
==
比较的是地址
在比较**引用类型(除了String)**时,只要不是同一个对象,就不是同一个地址。String类型new两个对象,也不是同一个地址。
equals()
String中比较的是值
在比较引用类型(除了String)时,使用的是object中的equals方法,比较的是地址是否一样。
但是String类重写了Object中的equals方法,依次比较顺序如下:
- 地址
- 类型
- 值(内容)
equals()语法如下:
1 | str1.equals(str2); |
正则表达式
正则表达式(Regular Expression)是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符")。
用途
- 匹配:判断给定的字符串是否符合正则表达式的规则逻辑
- 替换:对给定的字符串按指定的规则进行替换
检验程序员水平
正则表达式与元字符
一个正则表达式是含有一些具有特殊意义字符的字符序列。
这些特殊字符称作正则表达式中的元字符
。
例如,\\dhello
中的\\d
就是有特殊意义的元字符,代表一位数字。字符序列9hello
、3hello
都是与之匹配的字符序列之一。
正则表达式语法
元字符
转义字符"\"
在Java的正则表达式中,两个\\
代表其他语言中的一个\
,这也就是为什么表示一位数字的正则表达式为\\d
,而表示一个普通的反斜杠是\\
。
字符匹配符
字符 | 含义 | 示例 | 匹配输入 |
---|---|---|---|
[] | 字符集,可接收字符列表 | j[abc]va | java |
[^] | 反向字符集,不可接收字符列表 | j[^bcd]va | java |
- | 连字符,字符范围 | j[a-z]va | java |
. | 匹配除\n以外的任何单个字符 | j.va | java |
\d | 数字字符匹配,相当于[0-9] | \d{3}java | 520java |
\D | 非数字字符匹配,相当于[^0-9] | \D | java520 |
\w | 匹配任何字类字符,包括下划线,相当于[A-Za-z0-9_] | \d{3}\w{4} | 520java |
\W | 与任何非单词字符匹配,相当于[^A-Za-z0-9_] | \W{3}\w{4} | @#!java |
\s | 匹配任何空白字符,包括空格、制表符、换页符等,相当于[\f\n\r\t\v] | ja\sva | ja va |
\S | 匹配任何非空字符,相当与[^\f\n\r\t\v] | ja\Sva | java |
选择匹配符
符号 | 含义 | 示例 | 匹配输入 |
---|---|---|---|
| | 或。|两侧的表达式存在或的关系 | ab|bc | ab 和bc |
限定符
符号 | 含义 | 示例 | 匹配输入 |
---|---|---|---|
* | 零次或多次匹配前面的字符或子表达式 | a* | aa、abc、bc |
+ | 一次或多次匹配前面的字符或子表达式 | a+ | aa、abc |
? | 零次或一次匹配前面的字符或子表达式 | a? | bc、abc |
{n} | n是非负整数,正好匹配n次 | [abc]{2} | aa、ab、bc |
{n,} | n是非负整数,至少匹配n次 | [abc]{2} | abc、abcd |
{n,m} | n和m是非负整数,nm。至少匹配n次,至多匹配m次 | [abc]{1,2} | a、ab、b |
? | 当此字符紧随任何其他限定符之后时,匹配模式时非贪心的 |
注意:Java的匹配基于贪心思想,当有符合最长的匹配时,会优先匹配最长的。例如在字符串aaaa
中,a+
会匹配aaaa
,a+?
会匹配a
。
定位符
符号 | 含义 | 示例 | 匹配输入 |
---|---|---|---|
^ | 指定起始字符 | [1]+[a-z]* | 1a、12ab、520java |
$ | 指定结束字符 | [2]+[a-z]$ | 520j、12a |
\b | 匹配目标字符串的边界 | va\b | java |
\B | 匹配目标字符串的非边界 | av\B | java |
分组
捕获分组
常用分组构造形式 | 说明 |
---|---|
(pattern) | 非命名捕获。捕获匹配的字符串,编号为0的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则根据左括号的顺序从1开始自动编号 |
(?pattern) | 命名捕获。将匹配的字符串捕获到一个组名称或者编号名称中,用于name的字符串不能包含任何标点符号,并且不能以数字开头,可以使用单引号替代尖括号,例如(?'name’pattern) |
非捕获分组
常用分组构造形式 | 说明 |
---|---|
(?:pattern) | 匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"or"字符 (|) 组合模式部件的情况很有用。例如,'industr(?:y|ies) 是比 ‘industry|industries’ 更经济的表达式。 |
(?=pattern) | 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,‘Windows (?=95|98|NT|2000)’ 匹配"Windows 2000"中的"Windows",但不匹配"Windows 3.1"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。 |
(?!pattern) | 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,‘Windows (?!95|98|NT|2000)’ 匹配"Windows 3.1"中的 “Windows”,但不匹配"Windows 2000"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。 |
常用正则表达式
要求 | 规则 | 表达式 |
---|---|---|
汉字字符串 | 用16制编码范围来表示 | [3]+$ |
邮政编码 | 以1-9开头的六位数字 | [4]\d{5}$ |
QQ号 | 以1-9开头的5-10位数字 | [5]\d{4,9}$ |
URL | "^((http | |
电子邮箱 | 只能有一个@,以a-zA-Z0-9-_开头,以com、cn等结尾 | [6]+@([a-zA-Z].)+[a-zA-Z]+$ |
Java子类与继承
子类
由继承的得到的类
子类继承一般类的属性和行为,并且可根据需要在子类中添加新的属性和行为。
Java不支持多重继承,子类只能有一个父亲。子类和父类的关系称为is-a
关系。
在类的声明中,通过使用关键字extends
来定义一个类的子类,格式:
1 | class 子类名 extends 父类名 { |
类的树形结构
Java的类按继承关系形成树形结构,根节点是Object类
(Object是java.lang包中的类),即Object是所有类的祖先类。
每个类(除了Object类)有且仅有一个父类,可以有多个或零个子类。
如果进行类声明时没有使用extends关键字,则默认为Object的子类。
子类的继承性
继承家产
子类和父类的继承性分为同包
和不同包
。
子类和父类在同包中的继承性
若子类和父类在同一个包中,子类可以继承父类中除了private
的成员变量、方法作为自己的成员变量、方法。
不想被子孙继承的家产就用private修饰
子类和父类在不同包中的继承性
若子类和父类在不同包中,子类可以继承父类中除了private
和友好访问权限
成员变量、方法作为自己的成员变量、方法。
(不用private
、public
和protected
修饰的就是友好访问权限)
关于protected的进一步说明
一个类中的protected成员变量和方法可以被它的子孙类继承,但是需要继承下来的这个成员变量或方法所在的类和访问它的这个类在同一个包中。
可以把一个继承了很多次类看成一个家族,有很多代人,每代人都有可能移居不同的地方,把成员变量和方法看成固定资产。当这个家族到我这一代时,我可以继承这个家族在这个地方留下的资产,但是那些移居外地的祖先的固定资产,与我无关。
子类与对象
当用子类的构造方法创建了一个子类的对象时,子类和父类中声明的成员变量都被分配了内存空间,包括不被子类继承的父类中的private成员变量。
虽然无法直接操纵父类的private成员变量,但是可以通过从父类继承下来的方法来对这些父类的private成员变量进行操纵。
instanceof运算符是Java独有的双目运算符,左边是对象,右边是类,用来确定对象是否为右边类的子类。
1 | 对象名 instanceof 类名 //true or false |
上转型对象和下转型对象
上转型对象:子类转父类
下转型对象:父类转子类
基于继承。
上转型对象
1 | A a = new B(); //B是A的子类 |
称a为子类对象b的上转型对象。
- 上转型对象不能操作子类声明定义的成员变量、成员方法。
- 上转型对象可以访问子类继承或隐藏的成员变量,可以使用子类继承或重写的方法。
- 将上转型对象再强制转换成子类对象,就恢复成子类对象,相应的属性和方法随之恢复。
- 如果子类重写了父类的某个方法,上转型对象调用的是重写的方法。
上转型是父类的引用指向了子类的对象,所以它指向的是父类应该拥有的属性和方法。
下转型对象
如果直接使用下转型
1 | B b = new A(); //B是A的子类 |
会出错的。
因为向下转型,父类不具有子类的方法。
但是可以对上转型对象进行下转型,这类似于+1-1的过程。
为什么要用上转型对象
方便面向接口的编程思想和面向抽象的编程思想,实现了方法的多态,降低了程序之间关联性。
Java抽象类
由abstract修饰的类、方法叫抽象类、抽象方法。因为这种类是抽象的、理论上的
,所以它不能进行实例化。
抽象类除了不能实例化对象,它作为类的其他功能依然存在,成员变量、成员方法和构造方法等和普通类一样。
在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类可以实现多个接口。
1 | abstract class 类名 { //抽象类 |
- 继承抽象类的对象,都必须实现这个抽象方法。
- 只有抽象类才能包含抽象方法。
继承抽象类的方法和继承普通类一样,在类名后面加extends
1 | public class 子类 extends 父类 { |
总结
- 抽象类不能被实例化
- 抽象类中不一定包含抽象方法,但是由抽象方法的类必定是抽象类
- 抽象方法只声明,不包含方法体
- 构造方法,类方法(用static修饰的方法)不能声明为抽象方法
- 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
- 抽象类能继承抽象类
Java接口
接口制定标准
概念
接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现具有不同的行为。
接口是解决Java无法使用多继承的一种手段。
接口是一种特殊的抽象类
,是由全局常量
和公共的抽象方法
组成。
定义接口
接口定义使用的关键字是interface
,接口定义的语法格式如下:
1 | [public] interface 接口名 [extends 父接口]{ |
注意:一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类
实现接口
接口的主要用途就是被实现类实现,一个类可以实现一个或多个接口,这解决了Java不能支持多继承的局限性。
接口的实现使用implements
关键字,类实现接口的语法格式如下:
1 | public class 类名 [extends 父类] [implements 接口1,接口2...] { |