Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。
Java 可运行于多个平台,如 Windows, Mac OS 及其他多种 UNIX 版本的系统。
java特点
简单、面向对象、分布式、健壮、安全、体系结构中立、可移植、解释型、高性能、多线程、动态
环境搭建
版本选择
选择LTS版本
Java 8是一次重大的发行版更新,引入了大量新特性和改进。其中最为显著的是Lambda表达式的引入,它允许在代码中直接定义匿名函数,大幅简化了函数的编写,并提升了效率。此外,Java 8还新增了Stream API,使得开发者可以更方便地进行流式操作。Date/Time API的改进也为日期和时间的处理提供了更多的便利。同时,Java 8还在接口中添加了默认方法和函数式接口的概念,以及方法引用(::)和Optional容器类型等特性。
Java 17则主要关注在Java语言和Java虚拟机的性能和安全性方面的改进。其中一个重要的变化是Switch表达式的增强,支持Lambda表达式和块语句,这使得Switch语句的功能更加强大和灵活。此外,Java 17还改进了类型推断机制,允许在Lambda表达式和匿名内部类中使用var关键字,进一步提升了代码的简洁性和可读性。
至于Java 21,作为自JDK17之后的新的LTS版本,也带来了许多新特性。其中包括switch模式匹配、字符串模板、顺序集合、记录模式(Record Patterns)、未命名类和实例的main方法(预览版)以及虚拟线程等。这些新特性进一步增强了Java的编程能力和应用范围。
总的来说,从Java 8到Java 17再到Java 21,每个版本都在不断地优化和改进,为开发者提供了更加高效、安全和灵活的编程环境。具体选择哪个版本进行学习或开发,需要根据项目的实际需求和个人的技术水平进行权衡。
步骤
macos端2024/3/29测试,官网直接安装Jdk即可,自动配置环境变量
安装链接(jdk21 for Mac):
https://www.oracle.com/cn/java/technologies/downloads/#jdk21-mac
相关命令
查看java版本:
java -version
ShellScript列出所有安装的 JDK 版本及其路径:
/usr/libexec/java_home -V
ShellScript查看JAVA_HOME
环境变量:
echo $JAVA_HOME
ShellScript检查 PATH
环境变量中是否包含了 JDK 的 bin
目录:
echo $PATH
ShellScript卸载jdk:
sudo rm -rf /Library/Java/JavaVirtualMachines/jdk1.8.0_XXX.jdk
ShellScript删除 Java Web 插件和相关的缓存文件:
sudo rm -rf /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin
sudo rm -rf /Library/Application\ Support/Oracle/Java
ShellScript运行
编辑源文件:hello.java
编译:Javac hello.java(运行后新增hello.class,为编译后的字节码文件)
java hello(将hello.class文件放到虚拟机JVM里运行,执行hello类)
ps:
1、public类有且唯一,其他类不限,文件名必须是public类名
2、每个类单独生成一个.class编译文件
基础语法
注释
单行
//abc
Java多行
/*abc*/
Java文档注释
/** * 这是一个文档注释示例
* 它通常包含有关类、方法或字段的详细信息
*/
public class MyClass {
// 类的成员和方法
}
Java通常出现在类、方法、字段前,用于生成代码文档,可以被javadoc工具解析提取生成为api文档
javadoc -d 目的文件夹名 -javadoc标签1 - Javadoc标签2 …… 源文件名.java
Java简单的例子:
/**
* 我是主说明
*
* @author buer
* @version 1.0
*/
public class hello {
/**
* 默认构造器,虽然在这个只包含静态方法的类中不会被使用,但为了消除警告而显式定义。
*/
public hello() {
// 这里没有特殊的初始化代码,因为类只包含静态方法
}
/**
* 主方法,程序的入口点
*
* @param args 命令行参数数组
*/
public static void main(String[] args) {
System.out.println("hello,java");
}
}
Java转义符
\t 对齐
\n 换行
\\ \
\" "
\' '
\r 回车
Java关键字
保留字不能用于常量、变量、和任何标识符的名称
class | 类 |
public | 公共的 |
default | 默认的 |
new | 创建 |
static | 静态 |
标识符
定义
Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符
规则
1、以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始
2、不是关键字
3、大小写敏感
ps
还有字面常量null、false、ture,不是关键字,也不能作为标识符
变量
规则
type identifier [ = value][, identifier [= value] ...] ;
Java类型 变量名 = 值(可用,号分隔多个同时声明的变量)
实例
int a, b, c; // 声明三个int型整数:a、 b、c
int d = 3, e = 4, f = 5; // 声明三个整数并赋予初值
byte z = 22; // 声明并初始化 z
String s = "runoob"; // 声明并初始化字符串 s
double pi = 3.14159; // 声明了双精度浮点型变量 pi
char x = 'x'; // 声明变量 x 的值是字符 'x'。
Java局部变量
定义:
在方法、构造函数或块内部声明的变量
性质:
1、它们在声明的方法、构造函数或块执行结束后被销毁
2、局部变量在声明时需要初始化,否则会导致编译错误
public void Fun() {
int localVar = 10; // 局部变量
// ...
}
Java实例变量
定义:
在类中声明,但在方法、构造函数或块之外
性质:
1、它们属于类的实例,每个类的实例都有自己的副本
2、如果不明确初始化,实例变量会被赋予默认值(数值类型为0,boolean类型为false,对象引用类型为null)
public class Fun {
int instanceVar; // 实例变量
}
Java静态变量(类变量)
定义:
类变量是在类中用 static 关键字声明的变量
性质:
1、它们属于类而不是实例
2、所有该类的实例共享同一个类变量的值
3、类变量在类加载时被初始化,而且只初始化一次
public class Fun {
static int classVar; // 类变量
}
Java参数变量
参数是方法或构造函数声明中的变量,用于接收调用该方法或构造函数时传递的值,参数变量的作用域只限于方法内部。
public void Fun(int a ){
//在fangFa方法中,a就是参数变量
}
Java总结:
public class Fun {
// 成员变量
private int instanceVar;
// 静态变量
private static int staticVar;
public void method(int paramVar) {
// 局部变量
int localVar = 10;
// 使用变量
instanceVar = localVar;
staticVar = paramVar;
System.out.println("成员变量: " + instanceVar);
System.out.println("静态变量: " + staticVar);
System.out.println("参数变量: " + paramVar);
System.out.println("局部变量: " + localVar);
}
public static void main(String[] args) {
Fun v = new Fun();
v.method(20);
}
}
Java运算符
算术运算符
操作符 | 描述 | 例子 |
---|---|---|
+ | 加法 – 相加运算符两侧的值 | A + B 等于 30 |
– | 减法 – 左操作数减去右操作数 | A – B 等于 -10 |
* | 乘法 – 相乘操作符两侧的值 | A * B等于200 |
/ | 除法 – 左操作数除以右操作数 | B / A等于2 |
% | 取余 – 左操作数除以右操作数的余数 | B%A等于0 |
++ | 自增: 操作数的值增加1 | B++ 或 ++B 等于 21 |
— | 自减: 操作数的值减少1 | B– 或 –B 等于 19 |
关系运算符
运算符 | 描述 | 例子 |
---|---|---|
== | 检查如果两个操作数的值是否相等,如果相等则条件为真。 | (A == B)为假。 |
!= | 检查如果两个操作数的值是否相等,如果值不相等则条件为真。 | (A != B) 为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是那么条件为真。 | (A> B)为假。 |
< | 检查左操作数的值是否小于右操作数的值,如果是那么条件为真。 | (A <B)为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。 | (A> = B)为假。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。 | (A <= B)为真。 |
位运算符
操作符 | 描述 | 例子 |
---|---|---|
& | 如果相对应位都是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 |
逻辑运算符
操作符 | 描述 | 例子 |
---|---|---|
&& | 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 | (A && B)为假。 |
| | | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 | (A | | B)为真。 |
! | 称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。 | !(A && B)为真。 |
赋值运算符
操作符 | 描述 | 例子 |
---|---|---|
= | 简单的赋值运算符,将右操作数的值赋给左侧操作数 | 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个操作数,并且需要判断布尔表达式的值。
该运算符的主要是决定哪个值应该赋值给变量。
variable x = (expression) ? value if true : value if false
Javainstanceof 运算符
该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)。
instanceof运算符使用格式如下:
( Object reference variable ) instanceof (class/interface type)
Java如果运算符左侧变量所指的对象,是操作符右侧类或接口(class/interface)的一个对象,那么结果为真。
流程控制
条件判断(if……else)
- if 语句至多有 1 个 else 语句,else 语句在所有的 else if 语句之后。
- if 语句可以有若干个 else if 语句,它们必须在 else 语句之前。
- 一旦其中一个 else if 语句检测为 true,其他的 else if 以及 else 语句都将跳过执行。
选择结构(switch……case1:case2:……)
switch(expression){
case value :
//语句
break; //可选
case value :
//语句
break; //可选
//你可以有任意数量的case语句
default : //可选
//语句
}
Java- 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 语句。
循环结构
while
while( 布尔表达式 ) {
//循环内容
}
Java只要布尔表达式为 true,循环就会一直执行下去。
do while
对于 while 语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。
do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。
do {
//代码语句
}while(布尔表达式);
Java布尔表达式在循环体的后面,所以语句块在检测布尔表达式之前已经执行了。 如果布尔表达式的值为 true,则语句块一直执行,直到布尔表达式的值为 false。
for
for(初始化; 布尔表达式; 更新) {
//代码语句
}
Java- 最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
- 然后,检测布尔表达式的值。如果为 true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句。
- 执行一次循环后,更新循环控制变量。
- 再次检测布尔表达式。循环执行上面的过程。
for增强
Java5 引入了一种主要用于数组的增强型 for 循环。
Java 增强 for 循环语法格式如下:
for(声明语句 : 表达式)
{
//代码句子
}
Java声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
表达式:表达式是要访问的数组名,或者是返回值为数组的方法。
break
break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。
break 跳出最里层的循环,并且继续执行该循环下面的语句。
continue
continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
在 for 循环中,continue 语句使程序立即跳转到更新语句。
在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。
数组
规则
- 引用数据类型
- 创建后,在内存中开辟一整块固定连续的空间,长度不可变
- 初始化后数组元素默认值:整形0、浮点型0.0、字符型0、布尔型false、引用型null
- 内存解析,栈>指针>堆
一维数组
import java.util.Arrays;
public class MyCommons {
public static void main(String[] args) {
//静态初始化
//int[] arr;
//arr=new int[]{1,2,3,4};
int[] arr=new int[]{1,2,3,4};//简写
//动态初始化
int[] arr2=new int[4]
//System.out.printf(arr);直接输出会隐式调用tostring方法,输出乱码(类型简写和数值哈希值)
System.out.println(Arrays.toString(arr));
}
}
Java二维数组
一位数组的元素是数组
int[][] arr=new int[][]{{1,2,3},{4,5,6},{7,8,9},{10,11,12}}
arr[0][1]//第一项的第二个,2
Java动态数组
import java.util.ArrayList; // 导入ArrayList类
ArrayList<String> myList = new ArrayList<String>();//字符型数组
ArrayList<Integer> myList = new ArrayList<Integer>();//整型数组
ArrayList<Integer> myList = new ArrayList<>();
//在Java 7及以上版本中,可以使用菱形操作符(<>)来代替显式类型实参
myList.add(1); // 向ArrayList中添加元素
Java处理数组
public class MyCommons {
public static void main(String[] args) {
int[] arr=new int[]{1,2,9,4,0,7,6,4,6,8};
int num=0;//最小值arr[0]
for(int i=0;i<arr.length;i++){
//最大值
//if(arr[i]>num){
// num=arr[i];
//}
//最小值
//if(arr[i]<=num){
// num=arr[i];
//}
num+=arr[i];//和
//反转:i<arr.length/2 arr[i]<->arr[arr.length-1-i]
}
System.out.println(num);
//System.out.println((double)num/arr.length);平均值
}
}
JavaArryes工具类
add():将指定的元素添加到此列表的末尾。
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
add(int index, E element):在列表的指定位置插入指定的元素。
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add(1, "Orange"); // 插入后列表为 ["Apple", "Orange", "Banana"]
remove(int index):删除列表中指定位置的元素。
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.remove(0); // 删除后列表为 ["Banana"]
get(int index):返回列表中指定位置的元素。
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
String fruit = list.get(0); // fruit 将被赋值为 "Apple"
size():返回列表中的元素个数。
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
int size = list.size(); // size 将被赋值为 2
contains(Object o):判断列表中是否包含指定的元素。
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
boolean hasApple = list.contains("Apple"); // hasApple 将被赋值为 true
Collections.sort 数组排序
import java.util.ArrayList;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(3);
numbers.add(1);
numbers.add(2);
Collections.sort(numbers);
for (int num : numbers) {
System.out.print(num + " ");
} // 输出:1 2 3
}
}
Java练习
100内的质数
import java.util.ArrayList;//引入类
public class ZhiShu {
public static void main(String[] args) {
ArrayList<Integer> myList = new ArrayList<>();//声明动态整数数组
for(int a=2;a<=100;a++){//遍历2-100
boolean n=true;//标识
for(int b=2;b<a;b++){//遍历并比较2-a之间
if(a%b==0){
n=fasle;//不是质数就更改标识
break;
}
}
if(n){
myList.add(a);//给数组添加元素
}
}
System.out.println(myList);//输出
}
}
Java简单记账
import java.util.Scanner;
public class JiZhang {
private double balance;
public void addFun(double num){//收入方法
balance+=num;
System.out.printf("收入"+num+"元,当前余额:"+balance);
}
public void subFun(double num){//支出方法
balance=balance-num;
System.out.printf("支出"+num+"元,当前余额:"+balance);
}
public void cxFun(){//查询方法
System.out.printf("当前余额:"+balance);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
JiZhang jiZhangInstance = new JiZhang(); // 创建JiZhang类的实例
boolean sta=true;
while (sta){
System.out.print("记账系统\n1.查询余额\n2.收入\n3.支出\n4.退出");
String sce=scanner.nextLine();
switch (sce){
case "1":
jiZhangInstance.cxFun();
break;
case "2":
System.out.print("请输入收入金额:");
double income = scanner.nextDouble();
jiZhangInstance.addFun(income);
break;
case "3":
System.out.print("请输入支出金额:");
double expense = scanner.nextDouble();
jiZhangInstance.subFun(expense);
break;
case "4":
sta=false;
break;
default: // 如果用户输入了无效的选择
System.out.println("无效的选择,请重新输入。");
}
scanner.nextLine(); // 消耗掉输入后的换行符
}
}
}
Java面向对象编程
类及类的内部成员
属性、方法
public class Phone {//创建类
String color = "红色";//设计类的属性
public void Messages(String txt) {
//设计类的方法,void指不需要方法返回,如果需要返回值,将void替换为返回值的数据类型,结尾return
//方法必须在类里,不能独立存在
System.out.printf("手机发出了一条短息,内容是:" + txt);
}
}
public class PhoneText {
public static void main(String[] args) {
Phone iphone = new Phone();//初始化,创建类的对象(实例化)
System.out.printf("外观:"+iphone.color);//通过创建的对象,调用其内部声明的属性和方法
iphone.Messages("你好,对象"); }
}
Java构造器
构造器(也称为构造函数)是一种特殊类型的方法,用于初始化对象的状态。当使用new
关键字创建类的实例时,会自动调用构造器
规则:
权限修饰符 类名(形参列表){}
Java例子:
public static void main(String[] args) {
// 使用无参构造器创建对象
Person person1 = new Person();
System.out.println(person1); // 输出: Person{name='Unknown', age=0}
// 使用带参构造器创建对象
Person person2 = new Person("Alice", 25);
System.out.println(person2); // 输出: Person{name='Alice', age=25}
}
Java- 与类同名:构造器的名称必须与类名完全相同。
- 没有返回类型:构造器没有返回类型,甚至不能是
void
。 - 自动调用:当你使用
new
关键字创建一个对象时,Java会自动调用该类的构造器。 - 重载:一个类可以有多个构造器,只要它们的参数列表不同(这称为构造器的重载)。
- 初始化:构造器通常用于初始化对象的属性或执行必要的设置。
作用:
- 搭配上new创建对象
- 初始化对象的成员变量
属性赋值
位置:
- 默认初始化
- 显式初始化
- 构造器中初始化
- 通过obj.Fun()赋值
- 通过obj.name赋值
执行顺序:
1-2-3-4/5
代码块
//构造代码块:
{
System.out.print("我是代码块");
}
//特点:优先于构造方法执行,每new一次就执行一次
//静态代码块
static{
System.out.print("我是静态代码块");
}
//特点:优先于构造代码块和构造方法执行,只执行一次
Java内部类
类里面的类
内部类访问外部类成员变量:
public class A{
int a;//外部成员变量
static class B{
int b;//内部成员变量
void Bfun(){
this.b;//调用内部变量
A.this.a;//调用外部变量
}
}
Java静态成员内部类
public class A{
static class B{
}
}
A.B name=new A.B()
Java非静态成员内部类
public class A{
class B{
}
}
A.B name=new A().new B()
Java局部内部类
public class A{
void run(){
class B{//局部内部类
void eat(){}
}
new B().eat()//间接调用
}
}
class Text{
A name=new A();
name.run();//调用
}
Java匿名内部类
interface Greeting {
void sayHello();
}
public class Main {
public static void main(String[] args) {
//这里,创建了一个Greeting接口的匿名内部类实例,并覆盖了sayHello方法
Greeting greeting = new Greeting() {
@Override
public void sayHello() {
System.out.println("Hello, World!");
}
};
// 调用匿名内部类实现的方法
greeting.sayHello();
}
}
Java包装类
Java包装类(Wrapper Classes)是Java提供的一种特殊类,它们将基本数据类型(如int, double, char等)包装为对象,使得基本数据类型可以像对象一样被操作。每个基本数据类型都有对应的包装类,如下所示:
byte
对应的包装类是Byte
short
对应的包装类是Short
int
对应的包装类是Integer
long
对应的包装类是Long
float
对应的包装类是Float
double
对应的包装类是Double
char
对应的包装类是Character
boolean
对应的包装类是Boolean
包装类的主要用途有:
- 作为集合类元素:Java集合类(如ArrayList, HashSet等)只能存储对象,不能存储基本数据类型。因此,当我们需要将基本数据类型存储到集合中时,就需要使用对应的包装类。
- 提升基本数据类型的操作能力:包装类提供了一系列方法,用于对基本数据类型进行各种操作,比如类型转换、比较大小等。
- 自动装箱和拆箱:Java 5.0之后引入了自动装箱和拆箱的特性,使得在基本数据类型和包装类之间转换时更加方便。例如,当我们将一个int值赋给一个Integer对象时,Java会自动进行装箱操作;当我们从一个Integer对象获取int值时,Java会自动进行拆箱操作。
枚举类
public enum Day{//使用enum关键字定义枚举类
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
}
public class Main { //使用
public static void main(String[] args) {
Day today = Day.MONDAY;
switch (today) {
case MONDAY:
System.out.println("Today is Monday.");
break;
case TUESDAY:
System.out.println("Today is Tuesday.");
break;
// 其他情况的处理...
default:
System.out.println("Today is some other day.");
}
for (Day day : Day.values()) {
System.out.println(day);
}
}
}
//在这个例子中,我们创建了一个Day类型的变量today,并将其设置为MONDAY。然后,我们使用switch语句根据today的值执行不同的操作。最后,我们使用for-each循环遍历Day枚举类的所有实例,并打印它们。
Java- 常量性:枚举类的实例在JVM中是唯一的,不能被实例化多次。
- 类型安全:枚举常量具有类型信息,这使得它们在编译时就能进行类型检查。
- 可遍历性:枚举类实现了
java.lang.Enum
接口,因此可以使用values()
方法获取枚举类的所有实例,或者使用ordinal()
方法获取实例在枚举声明中的位置。
面向对象的特征
封装
面向对象的开发原则要遵循:高内聚、低耦合
- 内聚意味重用和独立。体现为类的内部数据操作细节自己完成,不允许外部干涉
- 耦合意味多米诺效应、牵一发而动全身。体现为仅暴露少量的方法给外部使用,尽量方便外部调用
权限修饰符
- private:
- 私有的。只能被定义它的类本身访问。
- 它是限制最严格的访问修饰符,用于隐藏类的内部实现细节。
- 成员变量、方法、构造器、内部类都可以使用private修饰。
- default(默认,无修饰符):
- 包内访问权限。无需任何关键字,只写成员变量名或方法名即可。
- 它意味着该成员可以被同一个包内的其他类访问。
- 如果不特别声明任何访问修饰符,则使用默认访问级别。
- protected:
- 受保护的。可以被同一个包内的其他类以及不同包中的子类访问。
- 它提供了比默认访问级别稍宽的访问权限,常用于实现继承中的某些特性。
- public:
- 公共的。可以被任何类访问。
- 它是访问级别最宽的修饰符,通常用于对外暴露类的API。
这些权限修饰符可以应用于类、接口、方法、变量等,但它们的使用场景和效果有所不同。例如:
- 类和接口只能使用
public
或default
(无修饰符)。 - 成员变量、方法、构造器和内部类可以使用所有四种权限修饰符。
- 局部变量不能使用访问权限修饰符(如
public
、private
、protected
)和非访问修饰符(如static
)进行修饰,可以使用final
修饰符。final
修饰符用于修饰不可更改的变量,即该变量的值在初始化后不能被重新赋值。
在选择使用哪种权限修饰符时,应考虑封装性、继承性和安全性等因素。
通常,为了遵循良好的封装原则,应尽可能将成员变量设置为private
继承
规则
class 父类 {
}
class 子类 extends 父类 {
}
Java类型
特点
- 子类拥有父类非 private 的属性、方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
关键字
extends
默认
class 父类 {
}
class 子类 extends 父类 {
}
Javaimplements
mplements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)
public interface A {
public void eat();
public void sleep();
}
public interface B {
public void show();
}
public class C implements A,B {
}
Javasuper和this
通过super关键字来实现对父类成员的访问,用来引用当前对象的父类
class Animal {
void eat() {
System.out.println("animal : eat");
}
}
class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}
Javafinal
- final 可以用来修饰变量(包括类属性、对象属性、局部变量和形参)、方法(包括类方法和对象方法)和类。
- final 含义为 “最终的”。
- 使用 final 关键字声明类,就是把类定义定义为最终类,不能被继承,或者用于修饰方法,该方法不能被子类重写:
声明类:
final class 类名 {//类体}
声明方法:
修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}
Java构造器的继承
- 子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。
- 如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
class SuperClass {
private int n;
SuperClass(){
System.out.println("SuperClass()");
}
SuperClass(int n) {
System.out.println("SuperClass(int n)");
this.n = n;
}
}
// SubClass 类继承
class SubClass extends SuperClass{
private int n;
SubClass(){ // 自动调用父类的无参数构造器
System.out.println("SubClass");
}
public SubClass(int n){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass(int n):"+n);
this.n = n;
}
}
Java多态
方法的重写和重载
重写(override)
在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法
子类对继承过来的方法进行重写、覆盖
重载(overload)
一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,
最常用的地方就是构造器的重载
//以下两个参数类型顺序不同
public String test(int a,String s){
System.out.println("test3");
return "returntest3";
}
public String test(String s,int a){
System.out.println("test4");
return "returntest4";
}
Java对象的多态性
父类类型的变量可以引用子类对象,并且可以在运行时确定实际调用的是哪个子类的方法
在Java中,当我们声明一个父类类型的引用变量并让它指向一个子类对象时,我们称之为向上转型(upcasting)。这种转型是安全的,因为子类对象包含父类所有的成员(包括属性和方法),所以父类引用可以访问子类对象中的这些成员。
然而,当我们通过这个父类引用调用一个被子类重写的方法时,实际执行的是子类中的方法,而不是父类中的方法。这种机制称为动态方法分派(dynamic method dispatch),它发生在运行时,Java虚拟机根据对象的实际类型来确定应该调用哪个方法。
public class duoTai {
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型:Animal引用指向Dog对象
animal.makeSound(); // 输出 "777"
//animal1.eat();无法直接运行
Dog dog=(Dog)animal;//向下转型,将animal转换为Dog类型
dog.eat();//888
}
}
class Animal {
public void makeSound() {
System.out.println("666");
}
}
class Dog extends Animal {
public void makeSound() { //重写了makeSound方法
System.out.println("777");
}
void eat(){
System.out.println("888");
}
}
Java在这个例子中,我们有一个Animal
类以及两个子类Dog
和Cat
。每个类都有一个makeSound
方法,而Dog
和Cat
类重写了这个方法以提供不同的行为。在main
方法中,我们创建了两个Animal
类型的引用animal1
和animal2
,但分别让它们指向Dog
和Cat
对象。当我们调用makeSound
方法时,实际执行的是相应子类中的方法,这体现了多态性。
这种多态性让代码更加灵活,因为我们可以在不改变Animal
类代码的情况下添加新的子类并实现新的行为。同时,这也允许我们在不知道具体子类类型的情况下处理对象,只要它们都是某个父类的类型。
抽象
抽象方法
- 使用abstract修饰的方法,没有方法体,只有声明
- 定义一种规范,告诉子类必须要给该方法提供具体的实现
抽象类
包含抽象方法的类
可以做到严格限制子类设计,子类间更通用
public class chouXiang extends Animal02{
public void run(){//必须调用,不然会报错
}
public static void main(String[] args) {
}
}
abstract class Animal02{
int age;
public abstract void run();
public void eat(){
System.out.print("eat");
}
}
Java使用要点
- 有抽象方法的类只能定义成抽象类
- 抽象类不能实例化,即不能用 new 来实例化抽象类。
- 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来 new 实例,只能用来被子类调用。
- 抽象类只能用来被继承。
- 抽象方法必须被子类实现
其它关键字的使用
接口
一组规范,所有的类都要遵守
[权限修饰符] interface 接口名称 [extends 父类接口1,父类接口2] {
// 定义常量
// 抽象方法
}
interface Aanimal{//定义 动物 接口,抽象方法 跑 和 吃
void run();
void eat();
}
interface Cute{//定义 可爱 接口,抽象方法 看起来喜欢
void looklike();
}
class Cat implements Aanimal,Cute{//猫类 实现 动物 和 可爱 接口,必须有 跑 和 吃 和 看起来喜欢方法
public void run(){
System.out.print("跑");
}
public void eat(){
System.out.print("吃");
}
public void looklike(){
System.out.print("看起来喜欢");
}
}
Java- 权限修饰符只能是public或者默认
- 接口名和类名相似
- 接口可以多继承
- 接口内只能定义常量,总是用public static final定义,不写也是
- 接口内只能声明抽象方法,public abstract,不写也是
- java8之后可以声明静态方法和默认方法,java9之后可以声明私有方法
object类
类似于js原型链,每个类的源头都默认继承object类
java.lang.Objact
Java常用的方法
toString()
- 常用程度:★★★★★
- 用途:返回对象的字符串表示,通常用于调试和日志记录。
- 规则:建议重写此方法以提供对象状态的简洁描述。默认实现返回类名、@符号和哈希码的组合。
equals(Object obj)
- 常用程度:★★★★☆
- 用途:判断两个对象是否相等。
- 规则:通常需要重写此方法以比较对象的实际内容而非引用。重写时应遵循自反性、对称性、传递性和一致性等原则。
hashCode()
- 常用程度:★★★★☆
- 用途:返回对象的哈希码值,用于支持哈希表等数据结构的快速查找。
- 规则:当重写
equals
方法时,通常也需要重写hashCode
方法,以确保相等的对象具有相同的哈希码。
getClass()
- 常用程度:★★★☆☆
- 用途:获取对象所属类的
Class
对象,用于反射或类型检查等操作。 - 规则:此方法返回表示该对象的运行时类的
Class
实例。通常不需要重写。
注解
- @Override:
- 作用:用于指示一个方法声明打算重写父类中的方法。如果方法签名与父类中的方法不一致,编译器会报错。
- 示例:
@Override public void myMethod() { ... }
- @Deprecated:
- 作用:用于标记一个已过时的方法或类。当其他代码使用这个已过时的方法或类时,编译器会发出警告。
- 示例:
@Deprecated public void myDeprecatedMethod() { ... }
- @SuppressWarnings:
- 作用:用于告诉编译器忽略指定的警告类型。这可以避免在编译时产生不必要的警告信息。
- 示例:
@SuppressWarnings("unchecked") public void myMethod() { ... }
- @FunctionalInterface:
- 作用:用于标记一个接口是函数式接口,即该接口只有一个抽象方法。这有助于编译器检查接口是否符合函数式接口的要求。
- @SafeVarargs:
- 作用:用于标记一个方法或构造函数使用了可变参数(varargs),并且不会产生类型安全问题。编译器会给出警告,但不会阻止使用。
- @Retention:
- 作用:用于指定注解的保留策略,即注解在什么时候生效。可能的值有
SOURCE
(仅保留在源码中,编译时丢弃)、CLASS
(保留在class文件中,但JVM会忽略)和RUNTIME
(保留在class文件中,且JVM会在运行时保留,因此可以通过反射读取)。
- 作用:用于指定注解的保留策略,即注解在什么时候生效。可能的值有
- @Documented:
- 作用:用于指定注解是否应被包含在JavaDoc文档中。
- @Inherited:
- 作用:用于指定注解是否可以被继承。如果一个类使用了某个带有
@Inherited
注解的注解,那么它的子类也会自动继承这个注解。
- 作用:用于指定注解是否可以被继承。如果一个类使用了某个带有
- @Repeatable:
- 作用:用于指定一个注解是否可以在同一个元素(如类或方法)上多次使用。这通常是通过定义一个容器注解来实现的。
单例模式
class BankTest{
public static void main(String[] args){
Bank name1=Bank.getfun();
}
}
//饿汉式
class Bank{
private Bank(){}//类构造器私有化
private static Bank name=new Bank();//在类内部创建实例,也必须是static
public static Bank getfun(){//使用方法获取实例,必须是static
return name;
}
}
//懒汉式
class Bank{
private static Bank name=null;
public static Bank getfun(){
if(name==null){
name=new Bank();
}
return name;
}
}
Java应用
异常处理
异常
这里的异常不是指代码编译后的报错
抛出机制
不同异常用不同的类表示,一旦发生,创建该异常的对象并且抛出(throw),然后程序员捕获(catch)这个异常对象,如果没有捕获,会导致程序终止
体系结构
- java.lang.Throwable
- java.lang.Error 错误(一般不编写针对性代码处理):虚拟机无法解决的严重问题,如系统内部错误、资源耗尽等。
- StackOverflowError
- OutOfMenmoryError
- java.lang.Exception 异常(可以编写代码处理):
- 编译时异常(执行javac时,受检异常)
- ClassNotFoundException
- FileNotFoundException
- IOException
- 运行时异常(执行java时,非受检异常)
- ArrayIndexOutOfBoundsException(数组角标越界)
- NullPointerException(空指针)
- ClassCastException
- NumberFormatException
- InputMismatchException
- ArithmeticException
- 编译时异常(执行javac时,受检异常)
- java.lang.Error 错误(一般不编写针对性代码处理):虚拟机无法解决的严重问题,如系统内部错误、资源耗尽等。
处理方式
try-chtch-finally(抓抛模型)
try{
•••••//可能产生异常的代码
}catch(异常类型1 e){
//当产生异常类型1型异常时的处置措施
System.out.println("异常1原因: " + e.getMessage());
}catch(异常类型2 e){
//当产生异常类型2型异常时的处置措施
System.out.println("异常2详细信息: " + e.printStackTrace());
}finally{
//无论是否发生异常,都无条件一定执行的语句
//和直接在try-catch-finally结构下面直接写的不同,直接写的语句在有报错的情况下不会执行
System.out.println("清理资源...");
}
Javathrow+异常类型
当方法内部有代码可能抛出检查型异常,而该方法本身不处理这些异常时
public void Fun() throws 异常类型1, 异常类型2 {
//可能抛出异常的代码
}
Javaclass Parent {
public void doSomething() throws IOException {
// ... 可能抛出IOException的代码 ...
}
}
class Child extends Parent {
@Override
public void doSomething() throws FileNotFoundException {
// FileNotFoundException是IOException的子类
// ... 可能抛出FileNotFoundException的代码 ...
}
}
Java在这个例子中,Child类重写了Parent类的doSomething方法,并且声明它可能抛出一个更具体的异常FileNotFoundException,这是IOException的子类。这是合法的,因为子类方法不会比父类方法抛出更多类型的异常。如果子类方法尝试声明抛出与父类方法不相关的异常,编译器会报错。
自定义异常
除了Java内置的异常类,程序员还可以根据需要自定义异常类。自定义异常类通常继承自Exception
或其子类。通过自定义异常,可以更好地描述和处理程序中的特定错误情况。
public class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
// 使用自定义异常
try {
throw new CustomException("自定义异常发生");
} catch (CustomException e) {
System.out.println("捕获到自定义异常: " + e.getMessage());
}
Java多线程
创建线程
继承Thread类
public class MyThread extends Thread {
@Override
public void run() {
// 线程执行的代码
System.out.println("MyThread is running");
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
}
Java- void start()——开启线程
- void run()——设置线程任务
- String getName()——获取当前运行的线程名字
- void setName(String name)——给线程设置名字
- static Thread currentThread()——获取正在执行的线程对象
- static void sleep(Long millis)——线程睡眠
- ——————————————————————————————
- void setPriority(int newPriority)——设置线程优先级(更容易优先,不是一定,newPriority默认5,最小1最大10)
- int getPrioity()——获取线程优先级
- void setDaemon(boolean on)——设置守护线程(伴随着被守护线程的结束而结束)
- static void yield()——礼让线程,让当前线程让出cpu使用权(尽量平衡,交替执行)
- void join()——插入线程 或 插队线程(a.join把线程a插到当前线程之前)
实现Runnable接口
public class MyRunnable implements Runnable {
@Override
public void run() {
// 线程执行的代码
System.out.println("MyRunnable is running");
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start(); // 启动线程
}
}
Java线程安全(同步)
synchronized修饰符
通过给方法或代码块加上synchronized修饰符,可以确保同一时间只有一个线程能够执行该方法或代码块。这有助于防止多个线程同时修改共享数据
//1-同步代码块
synchronized(锁对象){
//线程可能出现不安全的代码
}
//锁对象:代表锁的一个对象,一般用this,指代当前对象实例,也就是调用这些方法的对象
//2-同步方法
修饰符 synchronized 返回值类型 方法名(){
方法体
return 结果
}
Java线程状态
状态 | 发生条件 |
NEW(新建) | 线程刚被创建,但是并未启动。还没调用start方法。 |
Runnable(可运行) | 线程可以在问虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理噐。 |
Blocked(锁阻塞) | 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。 |
Waiting(无限等待) | 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAl方法才能够唤醒。 |
Timed Waiting(计时等待) | 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Jhread.sleep、 Object.wait. |
Terminated(被终止) | 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。或者调用过时方法stop() |
wait()和notify()
- sleep(time)和wait(time)有啥区别?
- a.sleep(time);线程睡眠,在睡眠的过程中,线程是不会释放锁,此时其他线程抢不到锁,设置的时间一旦超时,自动醒来,继续执行 。
- b.wait(time):线程等待,在等待的过程中会释放锁,其他线程就有可能抢到锁如果在等待的过程中被唤醒或者时间超时,会和其他的线程重新抢锁,如果抢到了继续执行,抢不到,锁阻塞。
- wait()和notify():
- a.wait():空参wait.线程进入到无限等待状态,会释放锁需要其他线程调用。notify()(一次唤醒一条等待的线程,唤醒是随机的)或者notifyAII方法(将所有等待线程全唤醒),被唤醒之后,会和其他的线程里新抢锁,抢到了,继续执行;抢不到,锁阻塞。
- b.notify():notify会唤醒正在等待的线程,一次只能唤醒—条等待的线程;如果要是多条线程在等待,notify会随机一条唤醒;
- c.notifyAII():晚醒所有等待的线程
- wait和notify两个方法的用法:
- 两个方法都需要锁对象调用,所以两个方法需要用到同步代码块,同步方法中
- 两个方法必须是同一个锁对象调用
- 可以理解为用同一个锁对象,将多条线程分到了一组中,这样notify就知道唤醒的是自己本组的等待线程
死锁
简单实例代码:
public class delLockText{
final Object lock1=new Object();
final Object lock2=new Object();
public static void main(String[] args) {
delLockText delLockText=new delLockText();
Thread thread1=new Thread(delLockText.new Thread1());
Thread thread2=new Thread(delLockText.new Thread2());
thread1.start();
thread2.start();
}
class Thread1 extends Thread{
@Override
public void run() {
synchronized (lock1){
System.out.println("Thread1获取lock1");
synchronized (lock2){
System.out.println("Thread1获取lock2");
}
}
}
}
class Thread2 extends Thread{
@Override
public void run() {
synchronized (lock2){
System.out.println("Thread2获取lock2");
synchronized (lock1){
System.out.println("Thread2获取lock1");
}
}
}
}
}
Javalock锁
主要方法和特点:
- lock():获取锁。如果锁被其他线程持有,则当前线程将阻塞,直到获得锁。
- tryLock():尝试获取锁,如果锁被其他线程持有,则立即返回false,不会阻塞当前线程。
- unlock():释放锁。调用此方法的前提是当前线程持有该锁,否则会抛出
IllegalMonitorStateException
。 - tryLock(long time, TimeUnit unit):尝试获取锁,如果在指定的时间内没有获得锁,则返回false。
- newCondition():返回与此锁关联的
Condition
实例,用于线程间的等待/通知机制。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
JavaCallable<V>接口
public class MyCS implements Callable<String>{
@Override
public String call() throws Exception {
return “涛哥和金莲...的故事”;
}
}
public class Test {
public static void main(Stringl] args){
MyCS my_cs = new MyCS();
//FutureTask (Callable<V> callable)
FutureTask<String> futureTask = new FutureTask<>(my_cs);
//创建Thread对象->Thread(Runnabletarget)
Thread t1 = new Thread (futureTask);
t1. start;
//调用get方法获取ca11方法返回值
System.out.println(futureTask.get);
}
}
Javav call()——设置线程任务,类似于Runable的run方法
- 相同点:都是设置线程任务
- 不同点:
- call 有返回值,且有异常可以throws
- run没有返回值,有异常不能throws
volatile关键字
volatile用于修饰变量,确保多线程对变量的操作具有可见性,即当一个线程修改了一个volatile变量的值,其他线程能够立即看到这个修改。
public volatile int sharedVariable = 0;
Java线程池
- 创建线程对象:工具类-Executors
- 获取线程对象:Executors中的静态方法
- static ExecutorService newFixedThreadPool(int nThreads)
- 参数:指定线程池中最多创建的线程对象数量
- 返回值ExecutorService时线程池,用来管理线程对象
- 执行线程任务:ExecutorService中的方法
- Future<?> submit(Runnable task)提交一个runnable任务用于执行
- Future<T> submit(Callable<T> task)提交一个callable任务用于执行
- submit方法的返回值:Future接口
- 用于接收run或call方法返回值,但是run没有返回值,所以可以不用Future接收
- Future有一个方法V get() 用于获取call返回值
- ExecutorService中的方法:
- void shutdown()启动有序关闭,之前提交的任务执行,不会接受新任务
public class Text01 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor_service= Executors.newFixedThreadPool(2);
//MyRunnable
executor_service.submit(new MyRunnable());
//MyCallable
Future future=executor_service.submit(new MyCallable());
System.out.println(future.get());
//关闭线程池
executor_service.shutdown();
}
}
//MyRunnable
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程,执行了");
}
}
//Callable
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "执行";
}
}
Java定时器Timer
构造:Timer()
方法:void schedule(TimerTask task,Date firstTime,long period)
- task:抽象类,Runnable的实现类
- firstTime:执行的起始时间
- period:执行间隔(毫秒)
public class DemoOlTimer {
public static void main (String[] args) {
Timer timer = new Timer ();
timer.schedule (new TimerTask {
@Override
public void run () {
system.out.println("起床了~~~");
}
},new Date(),2000L);
}
}
Java集合
动态的容器
- 单列集合:元素只有一个组成部分
- 双列集合:元素有两个组成部分,key,value
接口
- Collection:这是集合框架的根接口,它定义了集合的基本操作,如添加、删除、检查元素是否存在等。
- List:有序的集合(元素可重复)。
- Set:无序的集合(元素不重复)。
- Queue:队列,一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。
- Deque:双端队列,支持在两端插入和移除元素。
- Map:存储键值对的集合。
类
- ArrayList:基于动态数组实现的List。
- LinkedList:基于链表实现的List。
- HashSet:基于哈希表实现的Set。
- TreeSet:基于红黑树实现的Set,可以对元素进行排序。
- PriorityQueue:基于优先级堆的队列,元素根据其自然顺序或者创建的Comparator进行排序。
- ArrayDeque:基于数组实现的双端队列。
- HashMap:基于哈希表实现的Map。
- TreeMap:基于红黑树实现的Map,可以对键进行排序。
- LinkedHashMap:HashMap的子类,维护了一个运行于所有条目的双向链表。此链表定义了迭代顺序,通常是按照将元素插入到映射中的顺序(插入顺序)进行迭代。
Collection接口
定义:
单列集合的顶级接口
使用:
创建:Collection<E> name=new 实现类对象<E>()
- <E>泛型,决定集合中能存储什么类型的数据,可以统一元素类型
- 泛型中只能写引用数据类型,如果不写默认object,什么类型都可以存储了
- 等号前面的<>必须写,后面的可省略
常见方法:
- add(Object obj): 向集合中添加一个元素。
- addAll(Collection c): 将指定集合中的所有元素添加到此集合中。
- remove(Object obj): 从集合中移除一个元素。
- removeAll(Collection c): 移除集合c中的所有元素。
- retainAll(Collection c): 仅保留集合c中的元素,其他元素将被移除。
- clear(): 清空集合中的所有元素。
- contains(Object obj): 判断集合中是否包含元素obj。
- containsAll(Collection c): 判断集合中是否包含集合c中的所有元素。
- isEmpty(): 判断集合是否为空。
- size(): 获取集合中元素的个数。
- toArray(): 将集合转换为数组。
迭代器
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class iteratorCS {
public static void main(String[] args) {
//Collection<String> arr=new ArrayList<>();
ArrayList<String> arr=new ArrayList<>();
arr.add("001");
arr.add("002");
arr.add("003");
arr.add("004");
Iterator<String> iterator= arr.iterator();
while (iterator.hasNext()){//检查集合中是否还有更多的元素
String t=iterator.next();//返回集合中的下一个元素
//System.out.println(t);
if("003".equals(t)){//匹配003并删除
arr.remove("003");//从集合中删除上一次通过next()方法返回的元素
System.out.println(arr);
}
}
for(String i:arr){//for-each遍历
//System.out.println(i);
}
}
}
Java