Java学习

一个java程序的编写

模块->软件包->类

java主要是利用函数调用进行程序执行,主函数调用其他函数(类似于C++)

image-20250402105354745

1
2
3
4
5
6
7
8
9
10
11
public class functionBasic {
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = sum(a,b);
System.out.println(c);
}
public static int sum(int a, int b){
return a+b;
}
}

java类似C++的方法重载

image-20250402144705222

重载的意义在于使一个函数实现多种功能以及方便记忆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class chongzai {
public static void main(String[] args) {
System.out.println("这是重载");
fire();
fire(99);
fire(100,99);
}
//定义一个方法,发射导弹
public static void fire(){
System.out.println("发射导弹");
}
//定义导弹的重载函数
public static void fire(int a){
System.out.println("发射导弹"+a+"个");
}
//定义导弹的重载函数,位置更加精确
public static void fire(int a,int b){
System.out.println("坐标x:"+a+",y:"+b);
}
}

Java的类型转换(自动与强制)

自动类型转换

image-20250402150106025

强制类型转换

image-20250402150241186

表达式的自动类型提升

image-20250402150843567

Java的输入和输出

image-20250402151755454

image-20250402152452385

1
2
3
4
5
6
7
8
9
10
11
public class testScanner {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个整数:");
int a = sc.nextInt();
System.out.println("您输入的整数是:" + a);
System.out.println("您的名字是:");
String name = sc.next();
System.out.println("您的名字是:" + name);
}
}

java运算符和C++的区别

运算符类型 C++ 特性 Java 特性
赋值运算符 支持重载 不支持重载,仅基本类型和引用赋值
三元运算符 允许隐式类型转换 严格类型兼容
逻辑运算符 接受非布尔类型(隐式转换) 必须为 boolean 类型

java的boolean和C++的bool

boolean 在 Java 中是一个关键字,它定义了一个逻辑值类型,用来表示逻辑状态。与其他原始数据类型不同,boolean 只有两个固定的值:truefalse,用于逻辑判断、条件判断等。

boolean和C++的bool不同的是boolean不允许与其他类型进行隐式转换,也就是boolean只能等于true或者false,不能等于1或0

Java分支、循环结构和C++的区别

特性 C++ Java
if 条件类型 允许隐式转换为 bool(如 int 必须为 boolean 类型
switch 类型 整型、枚举 整型、String、枚举等
case 常量表达式 编译时常量
for-each 循环 基于范围的 for 需实现 Iterable 接口
goto 支持 不支持
标签跳转 支持(少用) 支持(明确用于多层循环)

java数组和C++区别

特性 Java 数组 C++ 数组
内存分配 堆内存,GC 管理 栈或堆,手动管理堆内存
类型安全 严格类型检查 弱类型检查(可通过指针绕过)
多维数组 数组的数组(支持不规则) 连续内存块(固定维度)
长度获取 arr.length 需手动维护或计算(栈数组用 sizeof
越界检查 抛出异常 无检查,导致未定义行为
动态调整大小 不可变,需借助集合类 堆数组可手动重新分配
语法初始化 支持直接初始化 {1, 2, 3} 栈数组支持 {} 初始化(C++11+),堆数组需 new

语法差异:

  • 声明与初始化

    • Java

      1
      2
      int[] arr1 = new int[3];     // 声明并分配空间
      int[] arr2 = {1, 2, 3}; // 直接初始化
    • **C++**:

      1
      2
      3
      int arr1[3];                // 栈数组声明(未初始化)
      int arr2[] = {1, 2, 3}; // 栈数组直接初始化(C++11+)
      int* arr3 = new int[3]; // 堆数组动态分配

java的类和对象

创建类和对象的语法和C++一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package CreatClass;

public class LearnCreat {
public static void main(String[] args) {
// 创建CreatClass类
class CreatClass {
private String name;
private int age;
private String sex;
}
//创建对象
CreatClass creatClass = new CreatClass();
creatClass.name="张三";
creatClass.age=18;
creatClass.sex="男";
System.out.println(creatClass.name);
System.out.println(creatClass.age);
System.out.println(creatClass.sex);
}
}

image-20250412132223441

java的构造器就是C++的类函数(方法)

注意:java的有参构造器创建了。默认的无参构造器就没有了,如果想用有参构造器,就必须自己写一个出来

java的this和C++的也是一样

this

回顾this的作用:解决对象属性和类函数的参数名冲突的问题

1
2
3
4
5
6
7
8
9
package yyssh.LearnClass;

public class testItem {
public static void main(String[] args) {
itemDemo s1 = new itemDemo("yanyuan", 18);
s1.print();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package yyssh.LearnClass;

public class itemDemo
{
String name;
int age;
public itemDemo(){

}
public itemDemo(String name,int age){
this.name = name; //如果这里不用this,那前面的属性name就会和参数name冲突
this.age = age;
}
public void print(){
System.out.println("姓名:"+name+"年龄:"+age);
}
}

java的封装和C++一样,都是先赋值类函数,再取值类函数

static

java的static和C++一样,下面回顾一样static,static是属于类的公共成员变量,所有的对象都可以访问,作用是统计公共数据的变化等等

java:工具类私有化构造器,使用静态函数(方法),方便调用

image-20250412154411085

1
2
3
4
5
6
7
8
9
10
11
12
package yyssh.LearnStatic;

public class staticDemo {
public static void main(String[] args) {
Student s1 = new Student();
s1.SetStudent("yanyuan", 18);
s1.print();
Student s2 = new Student();
s2.SetStudent("chenzhuang", 19);
Student.printStudentCount(); //公共成员变量直接使用类调用(变量也可以,但是不建议)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package yyssh.LearnStatic;

public class Student {
private String name;
private int age;
private static int StudentCount;
public Student(){
StudentCount++;
}
public void SetStudent(String name,int age){
this.name=name;
this.age=age;
}
public int GetStudent(){
return this.age;
}
public String GetName(){
return this.name;
}
public void print(){
System.out.println("姓名:"+this.name+"年龄:"+this.age);
}
public static void printStudentCount(){
System.out.println("学生人数:"+StudentCount);
}
}

继承

大致含义和C++的一样,都是只能继承父类的非私有成员和方法

java语法:

1
public class A extends B	//A是子类,B是父类

继承权限

private<缺省<protected<public

private 本类

缺省 本类、同一个包中的类

protected 本类、同一个包中的类、子孙类中

public 任意位置

java继承特点:单继承,不支持多继承(不能有多个父类)、支持多层继承(可以有爷类)

子类重写父类函数,名称、形参列表必须一样,访问权限要大于父类权限,私有和静态不能被重写

image-20250412162444789

super():调用父类构造器

super和this构造器都只能放在函数第一行,两者不能同时出现

多态

java的多态,要在重写函数的上一行加上@Override

image-20250412164138165

类方法:编译看父类,运行看子类

成员变量:编译、运行都看父类

多态下的一个问题,怎么调用子类独有的方法?

这个子类特有方法必须是重写父类的方法,才可以使用自动类型转换调用,如果是子类完全特有的,则只能强制类型转换

image-20250412165552220

1
2
3
4
5
6
7
8
if (a instanceof wolf){
wolf w = (wolf)a;
w.run();
}
else if {
rabbit r=(rabbit)a;
r.run();
}

final

image-20250412171637074

1
2
final int [] arr1={11,22,33};
arr1[1]=99; //这就是final修饰的变量地址不能改变,但是指向的对象内容是可用改变的
java的常量

image-20250412172352819

设计模式

image-20250412172745541

单例设计模式

饿汉式单例:

image-20250412173924522

懒汉式单例:

image-20250412174207184

枚举类

image-20250412204324418

image-20250412205158595

枚举类构造一个枚举对象也是单例类,因为他是常量,只能进行一次赋值操作

抽象类

抽象方法的特点:

  • 只能在抽象类中
  • 只有方法声明,没有方法体
  • 子类必须重写:如果一个类继承了含有抽象方法的抽象类,子类必须提供该抽象方法的实现,除非子类本身也被声明为抽象类。

image-20250412213546010

image-20250412214302944

抽象类设计模板

image-20250412221849571

1
2
3
4
5
6
7
8
9
10
11
package yyssh.LearnAbstractDemo;

public class testAbstractDemo {
public static void main(String[] args) {
People s1 = new Student();
s1.write();
People t1 =new Teacher();
t1.write();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
package yyssh.LearnAbstractDemo;

public abstract class People{
public final void write(){
System.out.println("我是一个人");
writemian();
System.out.println("我生活在地球");
System.out.println("-------------------------------------");
}
public abstract void writemian();
}

1
2
3
4
5
6
7
8
package yyssh.LearnAbstractDemo;

public class Teacher extends People{
@Override
public void writemian() {
System.out.println("我是一个老师");
}
}
1
2
3
4
5
6
7
8
package yyssh.LearnAbstractDemo;

public class Student extends People{
@Override
public void writemian() {
System.out.println("我是一个学生");
}
}

接口

image-20250412231127033

java接口的作用,就类似于C++可以继承多个父类

image-20250413164004611

image-20250413164128523

代码块

image-20250413173229750

内部类

image-20250413213704814

成员内部类

image-20250413214037804

静态内部类

不能访问外部类的成员变量

image-20250413214222416

局部内部类

image-20250413214321344

匿名内部类

image-20250413222523638

开发方式:

image-20250413222735742

使用场景:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package yyssh.innerClass;

import java.util.Comparator;
import java.util.Arrays;

public class testSort {
public static void main(String[] args) {
Student [] students = new Student[5];
students[0] = new Student(18,"yanyuan","男");
students[1] = new Student(19,"chenzhuang","男");
students[2] = new Student(20,"zhanghao","男");
students[3] = new Student(21,"zhangjie","男");
students[4] = new Student(22,"xuziyang","男");
Arrays.sort(students,new Comparator<Student>(){
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();// 升序
// return o2.getAge() - o1.getAge();// 降序
}
});
for (int i=0; i<5; i++) {
Student s = students[i];
System.out.println(s);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package yyssh.innerClass;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data

public class Student {
//设置私有的年龄、姓名、性别
private int age;
private String name;
private String sex;


}

Lambda表达式(函数式编程)

image-20250415113836816

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package yyssh.learnLambda;

public class lambdaDemo {
public static void main(String[] args) {
//正常的匿名内部类
Leap l = new Leap(){
@Override
public void leaping() {
System.out.println("leaping");
}
};
l.leaping();
//使用函数式编程lambda的匿名内部类
Swim s = ()->{
System.out.println("swimming");
};
s.swimming();
}
}

//函数式接口:只能包含一个抽象方法
@FunctionalInterface
interface Swim {
void swimming();
}

abstract class Leap {
public abstract void leaping();
}

image-20250415170237428

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package yyssh.learnLambda;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Arrays;
import java.util.Comparator;

public class lambdaOmit {
public static void main(String[] args) {
sort();
}
public static void sort(){
Student [] students = new Student[5];
students[0] = new Student(18,"yanyuan","男");
students[1] = new Student(19,"chenzhuang","男");
students[2] = new Student(20,"zhanghao","男");
students[3] = new Student(21,"zhangjie","男");
students[4] = new Student(22,"xuziyang","男");
// 正常原始写法
// Arrays.sort(students,new Comparator<Student>(){
// @Override
// public int compare(Student o1, Student o2) {
// return o1.getAge() - o2.getAge();// 升序
// }
// });
//省略写法
//因为Comparator接口只有一个抽象方法,所以可以省略接口名
Arrays.sort(students,(Student o1, Student o2)-> {
return o1.getAge() - o2.getAge();// 升序
});
//省略写法,参数类型可以全部不写
Arrays.sort(students,( o1, o2)-> {
return o1.getAge() - o2.getAge();// 升序
});
//省略写法,如果只有一个参数,可以省略参数圆括号,多个参数,不可以省略参数圆括号,这里不能省略
//省略写法,如果方法体只有一行代码,可以省略方法体的大括号和分号,如果这行代码是return,可以省略return
Arrays.sort(students,( o1, o2)-> o1.getAge() - o2.getAge());
for (int i=0; i<5; i++) {
Student s = students[i];
System.out.println(s);
}
}
}

@AllArgsConstructor
@Data
@NoArgsConstructor
class Student {
//设置私有的年龄、姓名、性别
private int age;
private String name;
private String sex;
}
静态方法引用

image-20250415213706281

这是正常方法

1
2
3
Arrays.sort(students,( o1,  o2)-> {
return o1.getAge() - o2.getAge();// 升序
});

使用静态方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package yyssh.learnLambda;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Arrays;
import java.util.Comparator;

public class lambdaOmit {
public static void main(String[] args) {
sort();
}
public static void sort(){
Student [] students = new Student[5];
students[0] = new Student(18,"yanyuan","男");
students[1] = new Student(19,"chenzhuang","男");
students[2] = new Student(20,"zhanghao","男");
students[3] = new Student(21,"zhangjie","男");
students[4] = new Student(22,"xuziyang","男");
// 正常原始写法
// Arrays.sort(students,new Comparator<Student>(){
// @Override
// public int compare(Student o1, Student o2) {
// return o1.getAge() - o2.getAge();// 升序
// }
// });
//省略写法
//因为Comparator接口只有一个抽象方法,所以可以省略接口名
Arrays.sort(students,(Student o1, Student o2)-> {
return o1.getAge() - o2.getAge();// 升序
});
//省略写法,参数类型可以全部不写
Arrays.sort(students,( o1, o2)-> {
return o1.getAge() - o2.getAge();// 升序
});
//省略写法,如果只有一个参数,可以省略参数圆括号,多个参数,不可以省略参数圆括号,这里不能省略
//省略写法,如果方法体只有一行代码,可以省略方法体的大括号和分号,如果这行代码是return,可以省略return
Arrays.sort(students,( o1, o2)-> o1.getAge() - o2.getAge());
//静态方法引用
Arrays.sort(students,Student::compare);
for (int i=0; i<5; i++) {
Student s = students[i];
System.out.println(s);
}
}
}

@AllArgsConstructor
@Data
@NoArgsConstructor
class Student {
//设置私有的年龄、姓名、性别
private int age;
private String name;
private String sex;
public static int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
}
实例方法引用

image-20250415213821803

1
2
3
4
//实例方法引用
Student t = new Student();
Arrays.sort(students,( o1, o2)->t.compareHeight(o1,o2));
Arrays.sort(students,t::compareHeight);
特定类型引用

image-20250415213917736

这里的特定类型是指lambda 表达式所实现的函数式接口的具体类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package yyssh.lambdaOmitDemo;

import java.util.Arrays;
import java.util.Comparator;

public class Demo {
public static void main(String[] args) {
String [] names = {"Alies","ailiy","Bob","曹操","张飞","CaoCao"};
//将数组进行排序
// Arrays.sort(names);
// System.out.println(Arrays.toString(names));
//不区分首字母大小写,对数组进行排序
// Arrays.sort(names, ( o1, o2)-> o1.compareToIgnoreCase(o2));
//特定类型引用
Arrays.sort(names, String::compareToIgnoreCase);
System.out.println(Arrays.toString(names));
}
}
构造器引用

image-20250415214056396

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package yyssh.lambdaOmitDemo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

public class Demo2 {
public static void main(String[] args) {
// CarFactory cf = new CarFactory() {
// @Override
// public Car getCar(String brand) {
// return new Car(brand);
// }
// };
// CarFactory cf = brand-> new Car(brand);
//构造器引用
CarFactory cf = Car::new;
Car c1 = cf.getCar("Benz");
System.out.println(c1.getBrand());
}
}

@FunctionalInterface
interface CarFactory {
Car getCar(String brand);
}

@AllArgsConstructor
@Data
@NoArgsConstructor
class Car {
private String brand;
}

常用的库

Lombok

检查模块依赖
  • 打开 IntelliJ IDEA,进入 File > Project Structure > Modules,确认每个模块的 Dependencies 选项卡中包含 Lombok。
  • 如果缺少,可以手动添加或确保 Maven/Gradle 已同步。
启用注解处理
  • 进入 Settings > Build, Execution, Deployment > Compiler > Annotation Processors,勾选 “Enable annotation processing” 和 “Obtain processors from project classpath”。
  • 这确保 Lombok 的注解处理器能被正确识别。
@AllArgsConstructor
  • 作用:生成一个包含所有字段的构造函数(即所有成员变量的初始化构造函数)。
  • 引用:import lombok.AllArgsConstructor
@Data
  • 作用@Data 是一个组合注解,它包含了以下几个 Lombok 注解的功能:

    • @Getter:为所有字段生成 getter 方法。
    • @Setter:为所有非 final 字段生成 setter 方法。
    • @ToString:生成 toString() 方法。
    • @EqualsAndHashCode:生成 equals()hashCode() 方法。
    • @RequiredArgsConstructor:生成一个带有 final 字段的构造函数(或者是 @NonNull 注解的字段)。

    这个注解的作用是为类自动生成常见的getter/setter、toStringequalshashCode 等方法,减少了很多样板代码。

  • 引用:import lombok.Data

@NoArgsConstructor
  • 作用:生成一个无参构造函数。
  • 引用:import lombok.NoArgsConstructor

java类和对象与C++的区别

特性 Java C++
类定义 所有代码必须在类中 允许全局函数和类外代码
对象存储 堆内存(GC 管理) 栈或堆(手动管理)
继承 单继承 + 接口多继承 支持多重继承
多态 所有方法默认是虚函数(除非 final 需显式声明 virtual
内存管理 自动垃圾回收 手动 new/delete
访问控制 支持包级私有 无包级私有
静态成员 类内直接初始化 需类外初始化

Java的API学习.

String

image-20250416191200852

String提供的常用方法

image-20250416191317337

ArrayList

image-20250416192538903

Java中的API和C++、python有什么异同

特性 Java C++ Python
内存管理 自动垃圾回收 手动管理(new/delete 自动垃圾回收
类型系统 静态类型,强类型检查 静态类型,弱类型检查(可强制转换) 动态类型,运行时检查
API 调用方式 通过类方法、接口 通过函数、类方法、运算符重载 通过函数、模块、动态类型
跨平台性 字节码(JVM) 需重新编译为平台特定机器码 解释执行(如 CPython)
代码复杂度 严格的面向对象结构 支持多范式(面向对象、过程式) 灵活,支持函数式编程

典型应用场景

  1. Java:适合企业级应用(如 Spring 框架的 RESTful API)、Android 开发,依赖成熟的生态系统(如 Maven、JUnit)916。
  2. **C++**:适用于高性能计算(如游戏引擎、操作系统底层 API)、资源敏感场景(如嵌入式系统)510。
  3. Python:快速原型开发(如 Flask/Django 的 Web API)、数据科学(如 NumPy、Pandas),依赖简洁语法和丰富库支持313。

Java的异常

image-20250416195452970

image-20250416195624436

使用快捷键(alt+回车)可以快速将异常抛出,异常统称exception和python是一样的,可以用这个关键字接收所有异常,java异常是层级抛出的,在最初调用的main函数进行异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package yyssh.exceptionDemo;

public class exceptionDemo1 {
public static void main(String[] args) {
try {
System.out.println(test(15,0));
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println("程序异常");
e.printStackTrace();//打印异常信息
}
System.out.println("程序结束");
System.exit(0);
}
public static int test(int a,int b) throws Exception {
int result =a/b;
if (b==0){
throw new Exception("除数不能为0");
}
return result;
}
}

image-20250416205943086

尽量定义运行时异常,编译时异常正在被全面放弃,因为编译时异常需要层级上抛需要每层进行处理或者上抛,资源消耗大

异常的解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package yyssh.exceptionDemo2;

import java.util.Scanner;

public class exceptionDemo2 {
public static void main(String[] args) {
System.out.println("程序开始");
// 抓捕用户输入错误的异常,让用户一直输入价格,直到输入正确的价格为止
while (true) {
try {
UserInputPrice();
System.out.println("用户输入成功!!!");
break;
} catch (Exception e) {
System.out.println("你的输入有问题,请输入正常的价格");
}
}
System.out.println("程序结束");
}
//定义一个方法,让用户输入商品的价格、
public static double UserInputPrice() {
Scanner sc = new Scanner(System.in);
System.out.println("请输入商品的价格:");
double price = sc.nextDouble();
return price;
}
}

java的异常和C++、python有什么异同

特性 Java C++ Python
异常传播 检查型异常必须处理或声明 异常可跨函数传播,无需声明 异常自动传播,无需声明
性能开销 较高(因堆栈跟踪生成) 低(无运行时类型检查) 较高(动态类型和堆栈跟踪)
错误恢复 支持完整的异常链(cause 属性) 仅支持基本异常信息 支持异常链(raise ... from ...

java的泛型

image-20250417120550466

自我理解:泛型就是规定了一个集合只能输入或输出一种类型(因为java是强类型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package yyssh.knowGenerics;

import java.util.ArrayList;

public class knowGenerics {
public static void main(String[] args) {
//如果不加泛型,arraylist集合可以添加任意类型的数据
ArrayList list = new ArrayList();
list.add(1);
list.add("yyssh");
list.add(true);
list.add(new Object());
for (Object o : list) {
System.out.println(o);
}
//加string泛型,只能添加String类型,就像厕所打了标签之后,男生只能进男厕所
ArrayList<String> StringList = new ArrayList<>();
StringList.add("yyssh");
for (String s : StringList) {
System.out.println(s);
}
}
}

shift+f6一键式改名

泛型类和接口

image-20250417205752890

image-20250417205935809

泛型的方法、通配符和上下限

image-20250420113150153

泛型的包装类

Java为了灌输它的万物皆对象的理念,只允许泛型传入的数据是对象,而不能传入基本数据类型,所以包装类也就应运而生,包装类就是将基本数据类型转换为对象

其实第二种方法也不是经常使用可以直接将两者进行转换看,因为java内置了一个自动装箱(自动把int转换为Integer)和自动拆箱(自动把Integer转换为int)的功能

但是这种方法没有被程序员认可,所以sun公司提供了包装类的两个好用的API

image-20250420121236023

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package yyssh.genericsPack;

import java.util.ArrayList;

public class PackClass {
public static void main(String[] args) {
ArrayList <Integer> list = new ArrayList<>();
list.add(123);
list.add(456);
for (Integer integer : list) {
System.out.println(integer);
}
Integer i =123; //自动装箱
System.out.println(i);
int j=i; //自动拆箱
System.out.println(j);
System.out.println(i==j); //Integer类的范围是-128~127,所以i==j为true,如果超出了这个范围,Integer会new一个新对象,则会返回false
String name = i.toString(); //Integer转String,其实没什么屌用,我用数据类型加“”也可以实现
System.out.println(name);
String is = i+"";
System.out.println(is);
//查看is的数据类型
System.out.println(is.getClass()); //返回String
//但是第二个方法很有用,可以将String转成int
String a = "123";
String c = "456";
Integer b = Integer.parseInt(a); //这两种方法都可以将String转成int
Integer d = Integer.valueOf(c);
System.out.println(b);
System.out.println(b.getClass());
System.out.println(d);
System.out.println(d.getClass());
}
}

java的泛型和C++、python有什么异同

特性 Java 泛型 C++ 模板 Python 类型系统
类型检查时机 编译时 编译时 运行时(类型提示为静态检查工具服务)
实现机制 类型擦除 代码实例化 动态类型 + 类型提示
支持基本类型 需装箱(如 Integer 直接支持(如 int 无泛型,直接支持所有类型
类型约束 显式边界(extends 隐式约束(操作符/方法存在性) 鸭子类型
代码复用灵活性 高(类型安全) 极高(支持元编程) 极高(动态特性)

java的集合

collection集合的特点

image-20250421151949661

collection常用方法

image-20250421154738910

collection的遍历方法:迭代器遍历

image-20250421163757699

collection的遍历方法:for循环遍历

image-20250421165236492

collection的遍历方法:lambda遍历

image-20250421165400864

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package yyssh.knowCollection;

import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.util.function.Consumer;

public class CollectionDemo1 {
public static void main(String[] args) {
//使用List接口实例化一个集合
//List接口是Collection接口的子接口,所以List接口也可以实例化
List<String> list =new ArrayList<>();
list.add("123");
list.add("yyssh");
list.add("yanyuan");
list.add("chenzhuang");
list.add("张浩");

//使用集合迭代器来进行遍历
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String s = iterator.next();
System.out.println(s);
}
System.out.println("-------------------------------------------------------");

//使用for循环遍历
for (String s : list) {
System.out.println(s);
}
System.out.println("-------------------------------------------------------");

//使用lambda遍历
//标准的匿名内部类
// list.forEach(new Consumer<String>() {
// @Override
// public void accept(String s) {
// System.out.println(s);
// }
// });
list.forEach(s-> System.out.println(s)); //这样其实已经很nb的lambda简化了
System.out.println("--------------------------------------------------------");
list.forEach(System.out::println); //实例方法引用
System.out.println(System.out.getClass());
}
}

java集合的三种遍历循环,有什么区别,同时又会造成什么问题?

在说这三种循环的区别时,先谈一下这三种循环会造成什么问题?

  • 遍历集合的同时又存在增删集合元素的行为时可能出现业务异常,这种现象被称为并发异常问题

异常产生的原因,因为在进行正序遍历时,删除一位,指针往前一位,集合补齐一位(说白了就是集合的长度是一直变化的),就会导致集合补齐的这一位逃过检查,从而造成删除不完全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.ArrayList;
import java.util.List;

public class circleDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("金龙");
list.add("木龙");
list.add("水龙");
list.add("火龙");
list.add("土龙");
list.add("龙虾");
list.add("龙王");
list.add("男人");
list.add("女人");
for (int i=0;i< list.size();i++) {
String name = list.get(i);
if (name.contains("龙")){
list.remove(i);
}
}
System.out.println(list); //输出[木龙, 火龙, 龙虾, 男人, 女人]
}
}

可以看到含有龙的字样并没有被删除完全,这里我们可以采取两种解决方案

  • 方案一:

    • 将for循环,进行i–,因为每删除一个就会漏掉一个,那我就回退一个就可以解决这个问题

    •   for (int i=0;i< list.size();i++) {
            String name = list.get(i);
            if (name.contains("龙")){
                list.remove(i);
                i--;
            }
        }
        
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12

      + 方案二:

      + 使用倒序循环,将不存在漏掉情况

      + ```java
      for (int i= list.size()-1;i>=0;i--) {
      String name = list.get(i);
      if (name.contains("龙")){
      list.remove(i);
      }
      }

这前面两个例子是为了说明在有索引的情况下是可以采用上面方案解决并发异常问题的,但是如果没有索引的话,例如Set集合,就无法采用上面的方案进行删除,只能采用迭代器自带的删除功能进行删除

1
2
3
for (String name : list){
System.out.println(name);
}
1
2
//        list.forEach( name-> System.out.println(name));   lambda简化
list.forEach(System.out::println); //实例方法引用

都无法进行索引,也无法进行并发操作,只有迭代器可以

1
2
3
4
5
6
7
8
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String name = iterator.next();
if (name.contains("龙")){
iterator.remove();
}
}
System.out.println(list);

image-20250421214202085

ArrayList底层原理

ArrayList的扩容原理是基于数组存储数据的,查询数据效率高,但是增减效率慢,第一次扩容10个长度,以后每一次扩容1.5倍

LinkedList底层原理

LinkedLIst底层是基于双链表存储数据的,查询效率慢,无论查询哪个数据都要从头或者尾(双向链表)开始找,增删速率高

java为LinkedList增加了许多对于首尾操作的方法

LinkedList的应用场景队列和栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package yyssh.applyLinkedListDemo1;

import java.util.List;
import java.util.LinkedList;

public class LinkedListDemo1 {
public static void main(String[] args) {
//使用LinkedList创建一个队列
LinkedList<String> queue = new LinkedList<>();
//入队
queue.addLast("张三");
queue.addLast("李四");
queue.addLast("王五");
queue.addLast("赵六");

//出队
for (int i=0;i<queue.size();i++){
System.out.println(queue.removeFirst());
i--;
}

System.out.println("------------------------------------------------------------------");

//使用LinkedList创建一个栈
LinkedList<String> stack = new LinkedList<>();
//入栈
stack.push("张三"); //push==addFirst
stack.push("李四");
stack.push("王五");
stack.push("赵六");

//出栈
for (int i=0;i<stack.size();i++){
System.out.println(stack.pop()); //pop==removeFirst
i--;
}
}
}

Set集合

image-20250423170935359

java的哈希表

JDK8之前,哈希表=数组+链表

JDK8之后,哈希表=数组+链表+红黑树

哈希表是一种增删改查数据效率都比较高的数据结构

image-20250423171307658

image-20250423171436677

HashSet集合对象去重操作

HashSet虽然是不重复的,但是对象之间如果数据完全相等,但对象之间的hash值不一定相等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package yyssh.hashset;

import java.util.Set;
import java.util.HashSet;

public class HashSetSingle {
public static void main(String[] args) {
//定义一个HashSet集合
Set<Student> Students = new HashSet<>();
Students.add(new Student("yanyuan", 21, 100, 1, "男", "北京", "123456789"));
Students.add(new Student("chenzhuang", 18, 91, 2, "男", "北京", "123456789"));
Students.add(new Student("zhanghao", 20, 95, 3, "男", "北京", "123456789"));
Students.add(new Student("zhangjie", 39, 88, 4, "男", "北京", "123456789"));
Students.add(new Student("chenzhuang", 18, 91, 2, "男", "北京", "123456789"));
Students.add(new Student("zhanghao", 20, 95, 3, "男", "北京", "123456789"));

//打印Students集合
for (Student s : Students) {
System.out.println(s);
}
}
}

学生类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package yyssh.hashset;

import java.util.Objects;

public class Student {
private String name;
private int age;
private int score;
private int id;
private String sex;
private String address;
private String phone;

public Student(String name, int age, int score, int id, String sex, String address, String phone) {
this.name = name;
this.age = age;
this.score = score;
this.id = id;
this.sex = sex;
this.address = address;
this.phone = phone;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && score == student.score && id == student.id && Objects.equals(name, student.name) && Objects.equals(sex, student.sex) && Objects.equals(address, student.address) && Objects.equals(phone, student.phone);
}

@Override
public int hashCode() {
return Objects.hash(name, age, score, id, sex, address, phone);
}

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
", id=" + id +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
", phone='" + phone + '\'' +
'}'+'\n';
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public int getScore() {
return score;
}

public void setScore(int score) {
this.score = score;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

public String getPhone() {
return phone;
}

public void setPhone(String phone) {
this.phone = phone;
}
}

主要在于equals和hashCode两个方法,但是sun公司都帮你写好了,直接调用就可以了,原理就是hashset集合存储数据要经过两个比较,一个是hashcode算hash值,一个是equals比较实际值

TreeSet集合自定义类型对象排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package yyssh.TreeSet;

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

public class TreeSetDemo1 {
public static void main(String[] args) {
// Set<Teacher> teachers = new TreeSet<>(new Comparator<Teacher>() {
// @Override
// public int compare(Teacher o1, Teacher o2) {
// return Double.compare(o1.getSalary(), o2.getSalary());
// }
// });
//使用lambda简化
Set<Teacher> teachers =new TreeSet<>(( o1, o2)->Double.compare(o1.getSalary(), o2.getSalary())); //升序
teachers.add(new Teacher("yanyuan", 21, "男", 9009.9));
teachers.add(new Teacher("chenzhuang", 18, "男", 10010.4));
teachers.add(new Teacher("zhanghao", 20, "男", 10009.9));
teachers.add(new Teacher("zhangjie", 39, "男", 99999.9));
teachers.add(new Teacher("huangzhenbao", 18, "男", 199999.9));
System.out.println(teachers);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package yyssh.TreeSet;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor

public class Teacher {
private String name;
private int age;
private String sex;
private double salary;

@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", salary=" + salary +
'}'+'\n';
}
}

集合的选择

  1. 如果希望记住元素的添加顺序,需要存储重复的元素,又要频繁的根据索引查询数据?
    • 用ArrayList集合(有序、可重复、有索引),底层基于数组的(常用)。
  2. 如果希望记住元素的添加顺序,且增删首位数据的情况较多?
    • 用LinkedList集合(有序、可重复、有索引),底层基于双链表的。
  3. 如果不在意元素顺序,也没有重复元素需要存储,只希望增删改查都快?
    • 用HashSet集合(无序、不重复、无索引),底层基于哈希表实现的。(常用)
  4. 如果希望记住元素的添加顺序,也没有重复元素需要存储,且希望增删改查都快?
    • 用LinkedHashSet集合(有序、不重复、无索引),底层基于哈希表和双链表。
  5. 如果要对元素进行排序,也没有重复元素需要存储?且希望增删改查都快?
    • 用TreeSet集合,基于红黑树实现。

Map集合

image-20250428195109539

Map集合的常用方法

image-20250428195353360

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package yyssh.LearnMapFunction;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapDemo1 {
public static void main(String[] args) {
Map<String, Integer> maps = new HashMap<>();
maps.put("张三", 18);
maps.put("王五", 19);
maps.put("赵六", 20);
System.out.println(maps);
System.out.println(maps.size());
Set<String> keys = maps.keySet(); //使用Set集合接收键,不重复
System.out.println(keys);
Collection<Integer> values = maps.values(); //使用Collection集合接收值,可重复
System.out.println(values);
}
}

Map集合的遍历方法

根据键找值

先获取Map集合的全部键,再通过遍历键来找值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package yyssh.MapTraversingDemo1;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapTraversingDemo1 {
public static void main(String[] args) {
Map<String, Integer> maps = new HashMap<>();
maps.put("张三", 18);
maps.put("王五", 19);
maps.put("赵六", 20);
Set<String> keys = maps.keySet(); //使用Set集合接收键,不重复
//根据键遍历map集合
for (String key : keys) {
Integer value = maps.get(key);
System.out.println(key + ":" + value);
}

}
}
把键值对看成一个整体进行遍历

利用java内置api将键值对看成一个entry对象进行遍历

image-20250428204446696

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package yyssh.MapTraversingDemo2;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapTraversingDemo2 {
public static void main(String[] args) {
Map<String, Double> maps = new HashMap<>();
maps.put("蜘蛛精", 169.8);
maps.put("紫霞",165.8 );
maps.put("至尊宝", 169.5);
maps.put("牛魔王", 183.6);

//将键值对看成一个entry对象,用Set集合接收,然后遍历
Set<Map.Entry<String, Double>> entries = maps.entrySet();
for (Map.Entry<String, Double> entry : entries) {
String key = entry.getKey();
Double value = entry.getValue();
System.out.println(key + ":" + value);
}
}
}
lambda表达式遍历

image-20250428214052427

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package yyssh.MapTraversingDemo3;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;

public class MapTraversingDemo3 {
public static void main(String[] args) {
Map<String, Double> maps = new HashMap<>();
maps.put("蜘蛛精", 169.8);
maps.put("紫霞",165.8 );
maps.put("至尊宝", 169.5);
maps.put("牛魔王", 183.6);

//使用lambda表达式遍历map集合
// maps.forEach(new BiConsumer<String, Double>() {
// @Override
// public void accept(String key, Double value) {
// System.out.println(key + ":" + value);
// }
// });
maps.forEach(( key, value)-> System.out.println(key + ":" + value));


}
}

Map集合的实现类

描述:Set集合就是基于Map集合的,Set集合就是Map集合不取值,只取键的结果

实现类 底层原理 Set集合基于Map集合
HashMap 哈希表 public HashSet() { map = new HashMap<>(); }
LinkedHashMap 基于双链表的首尾指针进行排序 HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
TreeMap 哈希表+红黑树 public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<>(comparator)); }

Stream流

image-20250507221557452

stream流的使用步骤

image-20250507221406458

获取stream流

image-20250507222550152

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package fun.yyssh.GetStream;

import java.util.*;
import java.util.stream.Stream;

public class GetStream {
public static void main(String[] args) {
//获取collection的stream
List<String> list = new ArrayList<>();
list.add("yanyuan");
list.add("chenzhuang");
Stream<String> sl = list.stream();

//获取map键的stream
Map<String,Integer> map = new HashMap<>();
Stream<String> sm = map.keySet().stream();
//获取map值的stream
Stream<Integer> sv = map.values().stream();
//map键值对的steam
Stream<Map.Entry<String,Integer>> sme = map.entrySet().stream();

//获取数组的stream
String[] arr = {"yanyuan","chenzhuang"};
Stream<String> sa = Arrays.stream(arr); //方法1
Stream<String> sa2 = Stream.of(arr); //方法2 Stream of (T....values)代表接收可变参数

}
}

java的集合和python的集合有什么异同

1. List(列表)

特性 Java Python
有序性 有序(插入顺序),可重复 有序(插入顺序),可重复
实现分类 ArrayList(数组)、LinkedList(链表)、Vector(线程安全数组) 单一列表类型(list),底层为动态数组
线程安全 Vector线程安全,其他默认不安全 默认不安全,需手动同步
操作示例 list.add(元素)list.get(索引) list.append(元素)list[索引]
特点 类型固定(泛型),需显式声明 动态类型,可混合存储不同类型元素

2. Map(字典)

特性 Java Python
键值对存储 键唯一,值可重复 键唯一且不可变(如字符串、数字、元组),值可任意类型
实现分类 HashMap(哈希表)、TreeMap(红黑树) 单一字典类型(dict),底层为哈希表
线程安全 ConcurrentHashMap线程安全,其他默认不安全 默认不安全
操作示例 map.put(key, value)map.get(key) dict[key] = valuedict.get(key)
特点 键可为任意对象(需实现hashCode()equals() 键必须为不可变类型(如列表不可作为键)

3. Set(集合)

特性 Java Python
元素特性 无序,不可重复 无序,不可重复(支持集合运算如并集、交集)
实现分类 HashSet(哈希表)、TreeSet(红黑树) 单一集合类型(set),底层为哈希表
线程安全 默认不安全 默认不安全
操作示例 set.add(元素)set.contains(元素) set.add(元素)元素 in set
特点 基于Map实现(键存储,值为空对象) 直接支持数学集合操作(如 union(), intersection()