1、Java概述
1.1 什么是Java
- Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。
2、Java三大版本
- Java SE(J2SE,Java 2 Platform Standard Edition,标准版)
Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java 应用程序。Java SE 包含了支持 Java Web 服务开发的类,并为Java EE和Java ME提供基础。 - Java EE(J2EE,Java 2 Platform Enterprise Edition,企业版)
Java EE 以前称为 J2EE。企业版本帮助开发和部署可移植、健壮、可伸缩且安全的服务器端Java 应用程序。Java EE 是在 Java SE 的基础上构建的,它提供 Web 服务、组件模型、管理和通信 API,可以用来实现企业级的面向服务体系结构(service-oriented architecture,SOA)和 Web2.0应用程序。2018年2月,Eclipse 宣布正式将 JavaEE 更名为 JakartaEE。 - Java ME(J2ME,Java 2 Platform Micro Edition,微型版)
Java ME 以前称为 J2ME。Java ME 为在移动设备和嵌入式设备(比如手机、PDA、电视机顶盒和打印机)上运行的应用程序提供一个健壮且灵活的环境。Java ME 包括灵活的用户界面、健壮的安全模型、许多内置的网络协议以及对可以动态下载的连网和离线应用程序的丰富支持。基于 Java ME 规范的应用程序只需编写一次,就可以用于许多设备,而且可以利用每个设备的本机功能。
1.2 特点
- Java语言具有简单性、面向对象、分布式、健壮性、安全性、跨平台性、可移植性、多线程与动态性等特点。Java语言可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统等 。Java 快速、安全、可靠。从笔记本电脑到数据中心,从游戏控制台到超级计算机,从手机到互联网,Java 无处不在!
1.3 JVM、JRE和JDK的关系
1.3.1 JDK
- JDK Java开发工具包(包含JRE,开发工具编译工具等…)
1.3.2 JRE
- JRE Java运行环境(JVM+核心类库)
2、JavaSE基础
2.1 Java关键字( Java8)
2.2.1 访问权限控制(3个)
修饰符名称 | 访问范围 |
private | 在本类中可以访问 |
protected | 在同一个包内的类和子类可以访问 |
public | 在所有类中都可以访问 |
2.2.2 类、方法、变量修饰符(14个)
修饰符名称 | 作用 |
abstract | 表示类或者成员方法是抽象的 |
class | 声名一个类 |
enum | 声名一个枚举 |
extends | 继承(表示一个类继承另外一个类方法和属性) |
final | 修饰的变量是不可变的(只能赋值一次) |
interface | 声名一个接口(接口是全抽象的) |
native | 原生方法(非Java实现) |
new | 用于创建一个实例对象 |
static | 表示具有静态属性 |
strictfp | 用于限制浮点数的计算精度和舍入(了解) |
synchronized | 表示一段代码是同步执行的 |
transient | 声名不用序列化的成员域 |
volatile | 表示两个或者多个变量需要同步执行 |
2.2.3 程序控制语句(12)
关键字 | 作用 |
break | 用于结束当前循环执行 |
continue | 跳过本次循环体执行(就是跳过循环体逻辑的执行) |
case | 用于switch语句中的其中一个分支 |
default | 默认:例如在switch语句中的默认分支(默认值) |
do | 在do-while循环语句中 |
else | 用于if条件语句中语句不成立时的分支 |
for | 一种循环结构引用词 |
if | 条件结构引用词 |
instanceof | 用于测试一个对象是否是指定类型的实例 |
return | 用于结束方法的执行,可以返回方法的返回类型的值 |
switch | 分支语句结构引用词 |
while | 创建一个while循环 |
2.2.4 错误处理(6个)
关键字 | 作用 |
assert | 断言,用于进行程序调试 |
catch | 用于异常处理中,捕获异常 |
finally | 用于异常处理中肯定会执行的语句块 |
throw | 抛出一个异常 |
throws | 在方法声名时抛出该方法未处理的异常给该方法的调用者 |
try | 定义具有异常的语句块(用于捕获语句块异常) |
2.2.5 包(2个)
关键字 | 作用 |
import | 引用指定的类或者包 |
package | 包 |
2.2.6 基本数据类型(8个)
关键字 | 类型 |
char | 字符型 |
byte | 字节型 |
short | 短整型 |
int | 整数形 |
float | 单精度 |
double | 双精度 |
long | 长整形 |
boolean | 布尔型 |
2.2.7 变量引用(3个)
关键字 | 作用 |
this | 指向当前实例对象的引用 |
super | 当前对象父类型的引用或父类构造方法的引用 |
void | 声名一个方法是没有返回值的(没有返回类型) |
2.2.8 保留关键字(2个)
关键字 | 作用 |
goto | 保留关键字,没有具体含义 |
const | 保留关键字,没有具体含义 |
2.2 Java注释
1、单行注释
格式://注释内容
2、多行注释
格式:/*注释内容*/
3、文档注释
格式:/**注释内容*/
2.3 Java转义字符
定义:转义字符以反斜杠( \ )开头,后面跟一个字符或者多个字符。
2.4 Java流程控制语句
2.4.1 顺序流程
定义
- 顺序结构是程序中最简单最基本的流程控制,没有特定的语法结构,按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的
例如
public class Test01
{
public static void main(String[] args)
{
System.out.println("开启");
System.out.println("1");
System.out.println("2");
System.out.println("3");
System.out.println("...");
System.out.println("结束");
}
}
2.4.2 分支结构
定义
- 可以根据不用条件执行不同分支
1、if 分支结构
方式一:if条件为真执行代码块
public static void main(String[] args)
{
System.out.println("开始");
if (1 == 1)
{
System.out.println("true");//代码块
}
System.out.println("结束");
}
方式二:if条件为真执行代码块,为假执行else分支代码块
public static void main(String[] args)
{
System.out.println("开始");
if (1 == 2)
{
System.out.println("true");//为真代码块
} else
{
System.out.println("false");//为假代码块
}
System.out.println("结束");
}
方式三:多个条件
public static void main(String[] args)
{
System.out.println("开始");
if (1 == 2)
{
System.out.println("条件一");
} else if(1 == 1)
{
System.out.println("条件二");
} else
{
System.out.println("前面条件如果不成立就执行该语句块");
}
System.out.println("结束");
}
2、switch 分支结构
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//接收数据
System.out.println("请输入一个数字(1-7):");
int weekday = sc.nextInt();
//switch语句实现选择
switch(weekday) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期日");
break;
default:
System.out.println("你输入的数字有误");
break;
}
}
2.4.3 循环结构
定义:循环语句就是在满足一定条件的情况下反复执行某一个操作。包括while循环语句、do···while循环语句和for循环语句。
1、for 循环
循环条件:添加为真就一直循环执行体结构
public static void main()
{
//要求:使用for循环执行10次 Hello Word! 输出。
for(int x=0; x < 10; x++) //关系表达式:从 0-9 = 10次
{
System.out.println("Hello Word!");
}
}
2、do ~ while 循环
循环条件:开启执行一次do语句块,然后根据条件为真继续执行语句块
public static void main()
{
do
{
System.out.println("do~while 执行体!");
} while(true); //关系表达式
}
3、while 循环
循环条件:为真就一直循环语句结构体
public static void main(String[] args)
{
while(true) //关系表达式
{
System.out.println("while 条件为真执行!");
}
}
4、三种循环区别
- do…while循环至少会执行一次循环体。
- for循环和while循环只有在条件成立的时候才会去执行循环体
- for循环语句和while循环语句的小区别:
- 使用区别:控制条件语句所控制的那个变量,在for循环结束后,就不能再被访问到了,而while循环结束还可以继续使用,如果你想继续使用,就用while,否则推荐使用for。原因是for循环结束,该变量就从内存中消失,能够提高内存的使用效率。
5、控制循环
**break:**跳出单层循环
public static void main(String[] args)
{
for(int x=1; x<=10; x++)
{
if(x = 5) break; //x=5时跳出当前循环
System.out.println("x= "+x); //输出 1234,x=5就就跳出该循环了
}
}
**continue:**结束一次循环(不执行该次循环体逻辑,然后继续下一次循环),继续下一次循环
public static void main(String[] args)
{
for(int x=1; x<=9; x++)
{
if(x = 5) continue; //x=5时结束本次循环,继续执行下一次循环
System.out.println("x= "+x); //输出 12346789,x=5时,5这次循环结束了所以没有执行
}
}
**return:**直接结束整个方法,从而结束循环
public static void main(String[] args)
{
for(int x=1; x<=9; x++)
{
if(x = 5) return; //x=5时直接结束方法
System.out.println("x= "+x); //输出 1234
}
}
2.5 Java表达式
定义:
- 用运算符把常量或者变量连接起来符号java语法的式子就可以称为表达式。
类型和值
- 表达式值的数据类型即为表达式的类型。
- 对表达式中操作数进行运算得到的结果是表达式的值。
运算顺序
- 应按照运算符的优先级从高到低的顺序进行;
- 优先级相同的运算符按照事先约定的结合方向进行;
例如
- a + b
3.14 + a
(x + y) * z + 100
boolean b= i < 10 && (i%10 != 0);
2.6 Java运算符
**定义:**运算符指明对操作数的运算方式。
2.6.1 算术运算符
运算符 | 运算 | 例子 | 结果 |
+ | 正号 | +7 | 7 |
- | 负号 | -7 | -7 |
+ | 加号 | 6+6 | 12 |
- | 减号 | 6-6 | 0 |
* | 乘号 | 3*3 | 9 |
/ | 除号 | 3/3 | 1 |
% | 取模运算 | 8%5 | 3 |
++ | 自增(前):先运算后取值 | x=2; y=++x; | x=3; y=3; |
++ | 自增(后):先取值后运算 | x=2; y=x++; | x=3; y=2; |
– | 自减(前):先运算后取值 | x=2; y=–x; | x=1; y=1; |
– | 自减(后):先取值后运算 | x=2; y=x++; | x=1; y=2; |
+ | 字符串相加 | "Hello "+“Word!” | “Hello Word!” |
注意事项:
- 1、前++;先+1,后运算 后++;先运算,后+1;
2.6.2 比较运算符
注意:比较运算符的返回结果都是boolean
类型
运算符 | 运算 | 例子 | 结果(true/false) |
== | 相等于 | 7==7 | true |
!= | 不等于 | 7!=7 | false |
> | 大于 | 7>7 | false |
< | 小于 | 7<7 | false |
>= | 大于等于 | 7>=7 | true |
<= | 小于等于 | 7>=7 | true |
instanceof | 检查对象是否是同一个类型实例 | “Hello” instanceof String | true |
2.6.3 赋值运算符
运算符 | 运算 | 例子 | 结果 |
= | 等于 | int x=1; x=3; | x=3 |
+= | 加等于 | int x=1; x+=3; | x=4 |
-= | 减等于 | int x=1; x-=3; | x=-2 |
*= | 乘等于 | int x=2; x*=3; | x=6 |
/= | 除等于 | int x=3; x/=3; | x=1 |
%= | 取模等于 | int x=1; x%=3; | x=1 |
2.6.4 逻辑运算符
注意事项:
- & 与 &&以及|与||的区别:
&:左边无论真假,右边都会进行运算;
&&:如果左边为假,则右边不进行运算;
|:左边无论真假,右边都会进行运算;
||:如果左边为假,则右边不进行运算; - (^)与或(|)的不同之处是:当左右都为true时,结果为false。
运算符 | 运算 | 例子 | 结果 |
& | 逻辑与 | true & true | true |
&& | 逻辑与 | true && false | false |
| | 逻辑或 | false | false | false |
|| | 逻辑或 | true || false | true |
! | 逻辑非 | !true(相当于取反) | false |
2.6.5 位运算符
运算符 | 运算 | 例子 |
<< | 左移 | 3 << 2 = 12 -->> 3 * 2 * 2=12 |
>> | 右移 | 3 >> 1 = 1 --> 3 / 2=1 |
>>> | 无符号右移 | 3 >>> 1 = 1 --> 3 / 2=1 |
& | 与运算 | 6 & 3 = 2 |
| | 或运算 | 6 | 3 = 7 |
^ | 异或运算 | 6 ^ 3 = 5 |
~ | 反码 | ~6 = -7 |
2.6.6 三元运算符
运算符 | 运算 | 例子 | 结果 |
(条件表达式) ? 表达式1 : 表达式2; | 三元表达式 | (7=7) ? “yes” : “no”; | “yes” |
2.6.7 运算符优先级
注意事项:
- 优先级按照从高到低的顺序书写,也就是优先级为1的优先级最高,优先级14的优先级最低。使用优先级为 1 的小括号可以改变其他运算符的优先级。
2.7 Java变量
定义
- 变量是内存中的一小块区域(在某个范围内值可以改变)
2.7.1 成员变量
位置:在类的内部定义的变量称作成员变量(方法的外部定义)
分类:静态成员变量、实例成员变量
**静态变量:**在方法外定义的变量,用static
修饰。
- 静态变量亦称为类变量,在类中使用
static
修饰的变量。 - 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
- 静态变量除了被声明为常量外很少使用。常量是指声明为public/private,final和static类型的变量。常量初始化后不可改变。
- 静态变量储存在静态存储区。经常被声明为常量,很少单独使用static声明变量。
- 静态变量在第一次被访问时创建,在程序结束时销毁。
- 默认值和实例变量相似。数值型变量默认值是0,布尔型默认值是false,引用类型默认值是null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
- 类变量被声明为public static final类型时,类变量名称一般建议使用大写字母。如果静态变量不是public和final类型,其命名方式与实例变量以及局部变量的命名方式一致。
public class User
{
//定义一个静态变量(类变量)
private static final String USERNAME = "这是一个静态变量";
}
**实例变量:**非静态的变量,没有使用static
修饰。
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
- 当一个对象被实例化之后,每个实例变量的值就跟着确定;
- 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
- 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
- 实例变量可以声明在使用;
- 访问修饰符可以修饰实例变量;
- 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;
public class User
{
//定义一个实例变量(成员变量),默认值为null
private String username;
}
静态变量和实例变量的区别
- 调用方式
- 静态变量也称为类变量,可以直接通过类名调用。也可以通过对象名调用。这个变量属于类。
- 成员变量也称为实例变量,只能通过对象名调用。这个变量属于对象。
- 存储位置
- 静态变量存储在方法区长中的静态区。
- 成员变量存储在堆内存。
- 生命周期
- 静态变量随着类的加载而存在,随着类的消失而消失。生命周期长。
- 成员变量随着对象的创建而存在,随着对象的消失而消失。
- 与对象的相关性
- 静态变量是所有对象共享的数据。
- 成员变量是每个对象所特有的数据。
2.7.2 局部变量
位置:在方法内定义的变量称作局部变量(方法内定义)
- 局部变量:类的方法中的变量。
- 局部变量声明在方法、构造方法或者语句块中;
- 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;
- 访问修饰符不能用于局部变量;
- 局部变量只在声明它的方法、构造方法或者语句块中可见;
- 局部变量是在栈上分配的。
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。
public class User
{
public void method()
{
//定义一个局部变量
String x = "这是一个局部变量!";
}
}
2.7.3 成员变量和局部变量的区别
- 作用域
- 成员变量:针对整个类有效。
- 局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)
- 存储位置
- 成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
- 局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。
- 生命周期
- 成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:当方法调用完,或者语句结束后,就自动释放。
- 初始值
- 成员变量:有默认初始值。
- 局部变量:没有默认初始值,使用前必须赋值。
使用原则
- 在使用变量时需要遵循的原则为:就近原则,首先在局部范围找,有就使用;接着在成员位置找。
2.8 Java常量
定义
- 常量定义:在程序执行的过程中,其值不可以发生改变的量。常量不同于常量值,它可以在程序中用符号来代替常量值使用,因此在使用前必须先定义。
- 常量值定义:常量和常量值是不同的概念,常量值又称为字面常量,它是通过数据直接表示的。
- 关系:常量值是常量的具体和直观的表现形式,常量是形式化的表现。通常在程序中既可以直接使用常量值,也可以使用常量。
分类
- 字符串常量 用双引号括起来的内容(“HelloWorld”)
- 整数常量 所有整数(12,-23)
- 小数常量 所有小数(12.34)
- 字符常量 用单引号括起来的内容(‘a’,’A’,’0’)
- 布尔常量 较为特有,只有true和false
- 空常量 null(数组部分讲解)
举例
- Java语言使用
final
关键字来定义常量
public class User
{
final String CODE = "code";
final String MSG = "message";
final String Data = "data";
}
注意
- 在定义常量时就需要对该常量进行初始化。
- final 关键字不仅可以用来修饰基本数据类型的常量,还可以用来修饰对象的引用或者方法。
- 为了与变量区别,常量取名一般都用大写字符。
2.9 Java数据类型
定义
- Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同大小的内存空间。
2.9.1 基本数据类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iRYRK20w-1654959712377)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220514174952589.png)]
- 字符型
- char
- 数值型
- byte
- short
- int
- long
- float
- double
- 布尔型
- boolean
2.9.2 引用数据类型
- 类(class)
- 接口(interface)
- 数组([])
2.9.3 计算机存储单元
- 定义:变量是内存中的小容器,用来存储数据。那么计算机内存是怎么存储数据的呢?无论是内存还是硬盘,计算机存储设备的最小信息单元叫**“位(bit)”,我们又称之为“比特位”,通常用小写的字母b表示**。而计算机最小的存储单元叫“字节(byte)”,通常用大写字母B表示,字节是由连续的8个位组成。
- 常用存储单元关系
- 1B= 8b
1KB = 1024B
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB - 一字节等于 8 比特位
- 1KB等于1024B(字节)
2.9.4 数据类型转换
定义
- 数据类型的转换是在所赋值的数值类型和被变量接收的数据类型不一致时发生的,它需要从一种数据类型转换成另一种数据类型。
1、隐式转换(自动类型转换)
- 定义
- 在运算过程中,由于不同的数据类型会转换成同一种数据类型,所以整型、浮点型以及字符型都可以参与混合运算。自动转换的规则是从低级类型数据转换成高级类型数据。
- 转换规则
- 数值型数据的转换:byte→short→int→long→float→double。
- 字符型转换为整型:char→int。
- 转换条件
- 自动类型转换的实现需要同时满足两个条件:①两种数据类型彼此兼容,②目标类型的取值范围大于源数据类型(低级类型数据转换成高级类型数据)。例如 byte 类型向 short 类型转换时,由于 short 类型的取值范围较大,会自动将 byte 转换为 short 类型。
2、显式转换(强制转换)
- 定义
- 当两种数据类型不兼容,或目标类型的取值范围小于源类型时,自动转换将无法进行,这时就需要进行强制类型转换
- 语法格式
- 目标类型 变量名 = (目标类型) (被转换的数据);
举例:int b = (byte)(a + b);
- 注意
- 如果超出了被赋值的数据类型的取值范围得到的结果会与你期望的结果不同
- 不建议强制转换,因为会有精度的损失。
2.10 Java反射(重点)
定义
- Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
用途
- 通过反射,Java 代码可以发现有关已加载类的字段,方法和构造函数的信息,并可以在安全限制内对这些字段,方法和构造函数进行操作。
- 很多人都认为反射在实际Java中开发应用中并不广泛,其实不然。当我们在使用 IDE(如 IDEA/Eclipse)时,当我们输入一个对象或者类并调用它的属性和方法时,一按 (“.”)点号,编译器就会自动列出她的属性或方法,这里就会用到反射。
2.10.1 Class类
Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。
获得类相关的方法
方法 | 用途 |
asSubclass(Class clazz) | 把传递的类的对象转换成代表其子类的对象 |
Cast() | 把对象转换成代表类或是接口的对象 |
getClassLoader() | 获得类的加载器 |
getClasses() | 返回一个数组,数组中包含该类中所有公共类和接口类的对象 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象 |
forName(String className) | 根据类名返回类的对象 |
getName() | 获得类的完整路径名字 |
newInstance() | 创建类的实例 |
getPackage() | 获得类的包 |
getSimpleName() | 获得类的名字 |
getSuperclass() | 获得当前类继承的父类的名字 |
getInterfaces() | 获得当前类实现的类或是接口 |
获得类中属性相关的方法
方法 | 用途 |
getField(String name) | 获得某个公有的属性对象 |
getFields() | 获得所有公有的属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
获得类中注解相关的方法
方法 | 用途 |
getAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的公有注解对象 |
getAnnotations() | 返回该类所有的公有注解对象 |
getDeclaredAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的所有注解对象 |
getDeclaredAnnotations() | 返回该类所有的注解对象 |
获得类中构造器相关的方法
方法 | 用途 |
getConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
获得类中方法相关的方法
方法 | 用途 |
getMethod(String name, Class…<?> parameterTypes) | 获得该类某个公有的方法 |
getMethods() | 获得该类所有公有的方法 |
getDeclaredMethod(String name, Class…<?> parameterTypes) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
类中其他重要的方法
方法 | 用途 |
isAnnotation() | 如果是注解类型则返回true |
isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果是指定类型注解类型则返回true |
isAnonymousClass() | 如果是匿名类则返回true |
isArray() | 如果是一个数组类则返回true |
isEnum() | 如果是枚举类则返回true |
isInstance(Object obj) | 如果obj是该类的实例则返回true |
isInterface() | 如果是接口类则返回true |
isLocalClass() | 如果是局部类则返回true |
isMemberClass() | 如果是内部类则返回true |
2.10.2 Field类
定义: Field代表类的成员变量(成员变量也称为类的属性)。
方法 | 用途 |
equals(Object obj) | 属性与obj相等则返回true |
get(Object obj) | 获得obj中对应的属性值 |
set(Object obj, Object value) | 设置obj中对应属性值 |
2.10.3 Method类
**定义:**Method代表类的方法。
方法 | 用途 |
invoke(Object obj, Object… args) | 传递object对象及参数调用该对象对应的方法 |
2.10.4 Constructor类
**定义:**Constructor代表类的构造方法。
方法 | 用途 |
newInstance(Object… initargs) | 根据传递的参数创建类的对象 |
2.10.5 反射常用类和方法测试
被反射的对象
public class Book{
private final static String TAG = "BookTag";
private String name;
private String author;
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
public Book() {
}
private Book(String name, String author) {
this.name = name;
this.author = author;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
private String declaredMethod(int index) {
String string = null;
switch (index) {
case 0:
string = "I am declaredMethod 0 !";
break;
case 1:
string = "I am declaredMethod 1 !";
break;
default:
string = "I am declaredMethod -1 !";
}
return string;
}
}
反射实例
public class ReflectClass {
private static final Logger log = LoggerFactory.getLogger(ReflectClass.class);
// 创建对象
@Test
public void reflectNewInstance() {
try {
Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
Object objectBook = classBook.newInstance();//创建Book类对象
Book book = (Book) objectBook;
book.setName("Java高级特性-反射-创建对象");
book.setAuthor("JourWon");
log.info(book.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 反射私有的构造方法
@Test
public void reflectPrivateConstructor() {
try {
Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
Constructor<?> declaredConstructorBook = classBook.getDeclaredConstructor(String.class, String.class);
// 暴力反射
declaredConstructorBook.setAccessible(true);
Object objectBook = declaredConstructorBook.newInstance("Java高级特性-反射-反射私有的构造方法", "JourWon");
Book book = (Book) objectBook;
log.info(book.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 反射私有属性
@Test
public void reflectPrivateField() {
try {
Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
Object objectBook = classBook.newInstance();
Field fieldTag = classBook.getDeclaredField("TAG");
fieldTag.setAccessible(true);
String tag = (String) fieldTag.get(objectBook);
log.info(tag);
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 反射私有方法
@Test
public void reflectPrivateMethod() {
try {
Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
Method methodBook = classBook.getDeclaredMethod("declaredMethod", int.class);
methodBook.setAccessible(true);
Object objectBook = classBook.newInstance();
Sting string = (String) methodBook.invoke(objectBook, 0);
ReflectClass.
log.info(string);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
输出结果:
[main] INFO com.jourwon.reflect.ReflectClass - Book{name='Java高级特性-反射-创建对象', author='JourWon'}
[main] INFO com.jourwon.reflect.ReflectClass - Book{name='Java高级特性-反射-反射私有的构造方法',author='JourWon'}
[main] INFO com.jourwon.reflect.ReflectClass - BookTag
[main] INFO com.jourwon.reflect.ReflectClass - I am declaredMethod 0 !
总结:
- 在阅读Class类文档时发现一个特点,以通过反射获得Method对象为例,一般会提供四种方法,getMethod(parameterTypes)、getMethods()、getDeclaredMethod(parameterTypes)和getDeclaredMethods()。getMethod(parameterTypes)用来获取某个公有的方法的对象,getMethods()获得该类所有公有的方法,getDeclaredMethod(parameterTypes)获得该类某个方法,getDeclaredMethods()获得该类所有方法。带有Declared修饰的方法可以反射到私有的方法,没有Declared修饰的只能用来反射公有的方法。其他的Annotation、Field、Constructor也是如此。
2.11 Java注解
2.11.1 什么是注解
注解也叫元数据,即一种描述数据的数据。例如我们常见的@Override和@Deprecated,注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解
2.11.2 注解的用途
- 生成文档,通过代码里标识的元数据生成javadoc文档。
- 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。
- 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
- 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例
2.11.3 注解的分类
- Java自带的标准注解,包括@Override(标明重写某个方法)、@Deprecated(标明某个类或方法过时)和@SuppressWarnings(标明要忽略的警告),使用这些注解后编译器就会进行检查
- 元注解,元注解是用于定义注解的注解,包括@Retention(标明注解被保留的阶段)、@Target(标明注解使用的范围)、@Inherited(标明注解可继承)、@Documented(标明是否生成javadoc文档)
- 自定义注解,可以根据自己的需求定义注解
2.11.4 元注解
- 要想真正掌握怎么使用注解,还需要先学习一下元注解。
- 元注解是用于修饰注解的注解
- 元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。
1、@Retention
Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。
它的取值如下:
- RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
- RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。如Java内置注解,@Override、@Deprecated、@SuppressWarnning等
- RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。如SpringMvc中的@Controller、@Autowired、@RequestMapping等。
2、@Documented
- 顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。
3、@Target
1、Target 是目标的意思,@Target 指定了注解运用的地方。
2、你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。
3、类比到标签,原本标签是你想张贴到哪个地方就到哪个地方,但是因为 @Target 的存在,它张贴的地方就非常具体了,比如只能张贴到方法上、类上、方法参数上等等。@Target 有下面的取值
- ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
- ElementType.CONSTRUCTOR 可以给构造方法进行注解
- ElementType.FIELD 可以给属性进行注解
- ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
- ElementType.METHOD 可以给方法进行注解
- ElementType.PACKAGE 可以给一个包进行注解
- ElementType.PARAMETER 可以给一个方法内的参数进行注解
- ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
4、@Inherited
- Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类使用了@Inherited 注解,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。
- 说的比较抽象。代码来解释。
5、@Repeatable
- Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。
Repeatable使用场景:在需要对同一种注解多次使用时,往往需要借助@Repeatable。
Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。
Repeatable使用场景:在需要对同一种注解多次使用时,往往需要借助@Repeatable。
2.11.5 声名注解
这里总共定义了4个注解来演示注解的声明
- 定义一个可以注解在Class,interface,enum上的注解
- 定义一个可以注解在METHOD上的注解
- 定义一个可以注解在FIELD上的注解
- 定义一个可以注解在PARAMETER上的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnTargetType {
/**
* 定义注解的一个元素 并给定默认值
* @return
*/
String value() default "定义在类接口枚举类上的注解元素value的默认值";
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnTargetMethod {
/**
* 定义注解的一个元素 并给定默认值
* @return
*/
String value() default "定义在方法上的注解元素value的默认值";
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnTargetField {
/**
* 定义注解的一个元素 并给定默认值
* @return
*/
String value() default "定义在字段上的注解元素value的默认值";
}
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnTargetParameter {
/**
* 定义注解的一个元素 并给定默认值
* @return
*/
String value() default "定义在参数上的注解元素value的默认值";
}
测试class
@MyAnTargetType
public class AnnotationTest {
@MyAnTargetField
private String field = "我是字段";
@MyAnTargetMethod("测试方法")
public void test(@MyAnTargetParameter String args) {
System.out.println("参数值 === " + args);
}
public static void main(String[] args) {
// 获取类上的注解MyAnTargetType
MyAnTargetType t = AnnotationTest.class.getAnnotation(MyAnTargetType.class);
System.out.println("类上的注解值 === " + t.value());
MyAnTargetMethod tm = null;
try {
// 根据反射获取AnnotationTest类上的test方法
Method method = AnnotationTest.class.getDeclaredMethod("test", String.class);
// 获取方法上的注解MyAnTargetMethod
tm = method.getAnnotation(MyAnTargetMethod.class);
System.out.println("方法上的注解值 === " + tm.value());
// 获取方法上的所有参数注解 循环所有注解找到MyAnTargetParameter注解
Annotation[][] annotations = method.getParameterAnnotations();
for (Annotation[] tt : annotations) {
for (Annotation t1 : tt) {
if (t1 instanceof MyAnTargetParameter) {
System.out.println("参数上的注解值 === " + ((MyAnTargetParameter) t1).value());
}
}
}
method.invoke(new AnnotationTest(), "改变默认参数");
// 获取AnnotationTest类上字段field的注解MyAnTargetField
MyAnTargetField fieldAn = AnnotationTest.class.getDeclaredField("field").getAnnotation(MyAnTargetField.class);
System.out.println("字段上的注解值 === " + fieldAn.value());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.11.6 总结
- 本文首先讲述了为什么要引入注解,注解是什么,注解的用途和分类,了解什么是元注解,怎么自定义注解,最后演示了使用注解和切面进行日志记录的案例。本人知识水平有限,只进行了Java注解的简单介绍,如有不正确的地方还请大神指教,希望对注解有更深入的了解掌握的话,可以自行进行更深入的学习。
2.12 Java8新特性-Lambda表达式
2.12.1 简介
- Lambda表达式(也称闭包),是Java8中最受期待和欢迎的新特性之一。在Java语法层面Lambda表达式允许函数作为一个方法的参数(函数作为参数传递到方法中),或者把代码看成数据。Lambda表达式可以简化函数式接口的使用。函数式接口就是一个只具有一个抽象方法的普通接口,像这样的接口就可以使用Lambda表达式来简化代码的编写。
2.12.2 Lambda表达式使用前提
- 对应接口只能有一个方法(简称函数式接口)
2.12.3 Lambda表达式特征
- **可选类型声明:**不需要声明参数类型,编译器可以统一识别参数值。
- **可选的参数圆括号:**一个参数无需定义圆括号,但多个参数需要定义圆括号。
- **可选的大括号:**如果主体包含了一个语句,就不需要使用大括号。
- **可选的返回关键字:**如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
2.12.4 Lambda表达式优点缺点
- 优点
- 使用Lambda表达式可以简化接口匿名内部类的使用,可以减少类文件的生成,可能是未来编程的一种趋势。
- 缺点
- 使用Lambda表达式会减弱代码的可读性,而且Lambda表达式的使用局限性比较强,只能适用于接口只有一个抽象方法时使用,不宜调试。
2.12.5 Lanbda函数式接口
- 只有函数式接口,才可以转换为lambda表达式
- 有且只有一个抽象方法的接口被成为函数式接口!
- 函数式接口可以显式的被@FunctionalInterface所表示,当被标识的接口不满足规定时,编译器会提示报错
2.12.6 Lambda表达式案例
1、案例一 - 无参无返回值
public class LambdaTest01
{
public static void main(String[] args)
{
// 1、传统方法调用接口 需要new接口实现类完成
ITest01 i1 = new MyDemo();
i1.test();
// 2.匿名内部类使用
ITest01 i2 = new ITest01()
{
@Override
public void test() {
System.out.println("使用匿名内部类完成接口调用!");
}
};
i2.test();
// 3.无参无返回Lambda表达式(必须是函数式接口,接口里面只有一个方法就是函数式接口)
ITest01 i3 = () -> {
System.out.println("无参无返回Lambda表达式!");
};
i3.test();
// 4.无参无返回且只有一行实现时可以去掉{}让Lambda更简洁
ITest01 i4 = () -> System.out.println("无参无返回且只有一行实现时可以去掉{}让Lambda更简洁!");
i4.test();
}
}
// 接口
interface ITest01
{
void test();
}
// 接口实现类
class MyDemo implements ITest01
{
// 从写接口方法
@Override
public void test()
{
System.out.println("我是ITest01接口的实现类-》从写了接口方法:test()");
}
}
输出结果
我是ITest01接口的实现类-》从写了接口方法:test()
使用匿名内部类完成接口调用!
无参无返回Lambda表达式!
无参无返回且只有一行实现时可以去掉{}让Lambda更简洁!
2、案例二 - 有参有返回值
public class LambdaTest02
{
public static void main(String[] args)
{
// 1.有参数没有返回值
Test01 t1 = (x) -> System.out.println(x);
t1.eat("吃屎啊!");
// 2.多个参数
Test02 t2 = (x, y) -> System.out.println(x+"在"+y);
t2.eat("狗东西", "吃屎!");
// 3.有多个参数有返回值
Test03 t3 = (x,y) -> (x+y);
int sum = t3.sum(111, 111);
System.out.println("两数之和:"+sum);
}
}
/*
* 定义测试接口
* */
interface Test01
{
void eat(String eatWhat);
}
interface Test02
{
void eat(String personName, String eatWhat);
}
interface Test03
{
int sum(int x, int y);
}
运行结果
吃屎啊!
狗东西在吃屎!
两数之和:222
2.12.7 Java8内置的函数式接口
**常用接口:**Java8提供了一个java.util.function包,包含了很多函数式接口。
1、Function 接口
T:是参数类型
R:返回类型
@FunctionalInterface //有这个注解代表这是一个函数式接口
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
Function接口的唯一抽象方法是apply,作用是接收一个指定类型的参数,返回一个指定类型的结果
public class FunctionTest1 {
public static void main(String[] args) {
FunctionTest1 ft = new FunctionTest1();
//使用lambda表达式实现apply方法,返回入参+10。形式上如同传递了一个方法作为参数
int res = ft.compute(1, v -> v + 10);
System.out.println(res);//11
}
public int compute(int x, Function<Integer, Integer> function) {
//使用者在使用本方法时,需要去编写自己的apply,
//传递的funtion是一个行为方法,而不是一个值
return function.apply(x);
}
}
2、Consumer接口
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Consumer接口中accept方法的作用是接收指定参数类型,无返回值,重点在于内部消费
public class FunctionTest02
{
public static void main(String[] args)
{
Consumer<String> consumer = str -> System.out.println("无返回值内置函数式接口: "+str);
consumer.accept("测试01!");
}
}
默认方法andThen作用是连续消费,从本Consumer开始,从外到内,针对同一入参。
public class FunctionTest02
{
public static void main(String[] args)
{
Consumer<String> consumer = str -> System.out.println("测试一: "+str);
Consumer<String> consumer2 = str -> System.out.println("测试二: " + str);
//连续消费
consumer.andThen(consumer2).accept("测试内容!");
}
}
3、Predicate接口
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
Predicate中的test方法,传入指定类型参数,返回布尔类型的结果,用于判断,断言
//判断一个数是否是偶数
Predicate<Integer> predicate = b -> n % 2 == 0;
System.out.println(predicate.test(3));//false
默认方法and顾名思义,将本Predicate和and参数中的Predicate对同一入参进行test的结果进行【与】操作。
negate方法对test的结果进行【非】操作
or方法对两个Predicate的test结果进行【或】操作
静态方法isEqual将其入参与test方法的入参进行equals比较
System.out.println(Predicate.isEqual(1).test(1));//true
4、Supplier接口
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Supplier意为供应,只有一个方法get,不接收任何参数,只返回指定类型结果
Supplier<String> sup = () -> "hello world";
System.out.println(sup.get());
2.13 Java面向对象
2.13.1 面向对象(OOP)概述
- OOP面向对象编程
- OOD面向对象的设计
- OOA面向对象分析
1、什么是面向对象吗?
- 面向对象就是例如把一个人当做一个对象,将这个人的特征抽象出来**(就是现实的事物抽象出来)**,把现实生活的事物以及关系,抽象成类,通过继承,实现,组合的方式把万事万物都给容纳了。实现了对现实世界的抽象和数学建模,这是一次飞跃性的进步。
2、面向过程和面向对象的区别
面向过程
- 优点:性能比面向对象好,因为类调用时需要实例化,开销比较大,比较消耗资源。
- 缺点:不易维护、不易复用、不易扩展
面向对象
- 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护
- 缺点:性能比面向过程差
3、面向对象的三大特征五大原则
三大特征
- 封装
- 隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。
- 继承
- 提高代码复用性;继承是多态的前提。
- 多态
- 父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。
五大原则
- 单一责任原则(SRP)
- 类的功能要单一,不能包罗万象,跟杂货铺似的。
- 开放封闭原则(OCP)
- 一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万个不乐意。
- 里氏替换原则(LSP)
- 子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~
- 依赖倒闭原则(DIP)
- 高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的抽象是中国人,而不是你是xx村的。
- 接口分离原则(ISP)
- 设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。
4、总结
- 抽象会使复杂的问题更加简单化。
- 从以前面向过程的执行者,变成了张张嘴的指挥者。
- 面向对象更符合人类的思维,面向过程则是机器的思想
2.14 Java集合框架
2.14.1 简介
- 集合框架
- 用于存储数据的容器。
- 任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
- 特点
- 对象封装数据,对象多了也需要存储。集合用于存储对象。
- 对象的个数确定可以使用数组,对象的个数不确定的可以用集合。因为集合是可变长度的。
- 集合和数组的区别
- 数组是固定长度的;集合可变长度的。
- 数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
- 数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
- 数据结构
- 就是容器中存储数据的方式。
- 使用集合框架的好处
- 容量自增长;
- 提供了高性能的数据结构和算法,使编码更轻松,提高了程序速度和质量;
- 允许不同 API 之间的互操作,API之间可以来回传递集合;
- 可以方便地扩展或改写集合,提高代码复用性和可操作性。
- 通过使用JDK自带的集合类,可以降低代码维护和学习新Api成本。
2.14.2 Iterator接口(迭代器)
**作用:**用于遍历集合的接口
1、Iterator接口中的三个方法
修饰与类型 | 方法与描述 |
boolean |
|
E |
|
void |
|
2、使用迭代器遍历集合
public static void main(String[] args)
{
// List集合是元素可重复的
List<String> list = new ArrayList<>();
list.add("集合元素1");
list.add("集合元素2");
list.add("集合元素3");
list.add("集合元素1");
list.add("集合元素1");
//实例化集合迭代器
Iterator<String> it = list.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
//for循环遍历
for (Iterator it2 = list.iterator(); it.hasNext(); )
{
System.out.println(it2.next());
}
}
运行结果
集合元素1
集合元素2
集合元素3
2.14.3 Collection接口
所有集合类都位于java.util包下。Java的集合类主要由两个接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。
- Collection一次存一个元素,是单列集合;
- Map一次存一对元素,是双列集合。Map存储的一对元素:键–值,键(key)与值(value)间有对应(映射)关系。
Collection集合主要有List和Set两大接口
- List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。
- Set:无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性。
1、List集合
- List集合是有序的并且元素可重复的。
- List的主要实现:ArrayList, LinkedList, Vector。
持续更新中!