常用CMD命令

盘符名称+冒号
盘符切换,E:切换到E盘

dir
显示当前目录中的内容

cd+文件夹名称
进入该文件夹

cd..
切换上级目录

cd 文件目录\文件目录
进入多级目录

cd
回到盘符目录

cls
清屏

exit
退出cmd窗口

Java入门

Java常见类型及用途:

java SE——用于桌面程序开发(小众

java ME——用于嵌入式系统开发(已经凉掉了

java EE——服务端开发(最常见

JRE和JDK

jdk:Java开发工具包

  • jre:Java运行环境
    • jvm虚拟机:Java,java程序运行的地方
    • 核心类库:java已经写好的东西,可以直接拿来用
  • Java开发工具:javac、java、jdb、jhat

java基础概念

java注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
*这
*是
*文
*档
*注
*释
*/

//这是单行注释

/*这是
多行
注释*/

关键字

被java赋予了特定含义的英文单词

关键字全部小写。

class类

1
2
3
public class HelloWorld{

}

class:用于(创建/定义)一个类

类是java最基本的组成单元

例子中的HelloWorld是类名

字面量

实数以及小数可以直接打印,“ ”用于打印字符串,‘’用于打印单个字符(单个汉字也属于单个字符),null无法直接打印,只能通过打印字符串的形式来打印。true false可直接打印。

制表符

\t在打印的时候把前面字符串的长度补齐到8,或者8的整数倍。至少补1个空格,最多补8个空格。

\t属于单个字符,因此用‘ ’“ ”打印效果相同

示例:

1
2
3
4
5
6
public class HelloWorld {
public static void main(String[] args) {
System.out.println("name" + '\t' + "age");
System.out.println("tom" + '\t' + "23");
}
}

最终打印结果为:

![image-20260119172719459](JAVA.assets/image-20260119172719459.png null)

变量

变量定义格式

数据类型 变量名 = 数据值;

变量的使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int a = 10;
System.out.println(a); //输出打印10

int a = 10;
int b = 20;
System.out.println(a + b); //参与计算10 + 20 = 30,最终输出结果为30

int a = 10;
System.out.println(a); //输出10
a = 20;
System.out.println(a); //输出结果变为20

int a = 10;
int a = 20;//错误,不可定义相同名称的变量

变量注意事项

  • 只能存一个值
  • 变量名不允许重复定义
  • 一条语句可以定义多个变量
  • 变量在使用之前一定要进行赋值
  • 变量的作用域范围

进制

二进制:由01组成,代码中以0b开头

十进制:由0~9组成,前面不加任何前缀

八进制:由0~7组成,代码中以0开头

十六进制:由0~9还有a~f组成,代码中以0x开头

1
2
3
4
5
6
7
8
public class HelloWorld {
public static void main(String[] args) {
System.out.println(17); //十进制
System.out.println(017); //八进制
System.out.println(0b123);//语法错误❌️
System.out.println(0x123);//十六进制
}
}

数据类型

java语音的数据类型分为:基本数据类型,引用数据类型

基本数据类型分为四类八种:

![image-20260202175143252](JAVA.assets/image-20260202175143252.png null)

注意:byte的取值范围为-128~127

整数和小数取值范围大小关系

double>float>long>int>short>byte

long类型和float类型数据尾部需要假如L、F标识(大小写均可

字符串类型:string用于打印字符串

标识符

标识符命名规则——硬性要求

  • 由数字、字母、下划线_和美元符$组成
  • 不能以数字开头
  • 不能是关键字
  • 区分大小写

标识符命名规则——软性建议

命名要符合见名知意

小驼峰命名法:方法、变量

规范1:标识符是一个单词的时候,全部小写

范例1:name

规范2:标识符由多个单词组成的时候,第一个单词首字母小写,其他单词首字母大写

范例2:firstName

大驼峰命名法:类名

规范1:标识符是一个单词的时候,首字母大写

范例1:Student

规范2:标识符由多个单词组成的时候,每个单词的首字母大写

范例2:GoodStudent

运算符

有小数参与的计算结果可能不准确

只有整数参与的计算结果只可能是整数

隐式转换和强制转换

数字进行运算时,数据类型不一样不能运算,需要转成一样的,才能运算。

类型转换的分类:

  • 隐式转换:取值范围的数值→取值范围的数值(把一个取值范围小的数值,转换成取值范围大的数据
    • 取值范围小的和取值范围大的进行运算,小的会先提升为大的,再进行运算
    • byte short char三种类型的数据在运算的时候,都会直接提升为int,然后再进行运算
  • 强制转换:取值范围的数值→取值范围的数值
    • 如果把一个取值范围大的数据,赋值给一个取值范围小的变量是不允许直接赋值的,如果一定要这么做就需要加入强制转换
    • 格式:目标数据类型 变量名 = (目标数据类型)被强转的数据;。例:double a = 12.3; int b = (int)a;

byte > short > int > long > float > double

如果要强制转换的数据值超过转换目标类型的取值范围就会发生错误

算数运算符

字符串的“+”操作

  • 当“+”操作中出现字符串时,这个“+”是字符串连接符,而不是算数运算符
    • "123" + 123结果为"123123"
  • 连续进行“+”操作时,从左到右这个执行
    • 1 + 99 + "年黑马"结果为"100年黑马"

字符相加

byte short char三种类型的数据在运算的时候都会直接先提升为int类型然后在进行运算

1
2
3
char c = 'a';
int result = c + 0;
//这里result的结果为97,即字符a的ASCLL码值(97)加上后边的数字0

字符+字符 字符+数字时,会把字符对应的ASCLL码值相加

A的ASCLL为65

a的ASCLL为97

1
2
System.out.println(1 + 'a');//98
System.out.println('a' + "abc");//"aabc"因为有字符串参与运算所以执行拼接操作而不是算数运算操作

整数操作只能得到整数,要想得到小数,必须有浮点数参与运算。

赋值运算符

扩展的赋值运算符隐含了强制类型转换

1
2
3
4
short s = 1;
s += 1;//把左边和右边进行相加,得到结果2,再赋值给左边的变量
//等同于:s = (short)(s + 1);此处会有隐藏的强制类型转换,因为s为short类型而数字1是int类型,结果是int类型,若没有隐含的强制类型转换int类型赋值给short类型的s将会报错
System.out.println(s);

三元运算符

三元运算符必须使用(直接打印或者赋值给其他变量,不可单独成一句)

其他的运算符

运算符 含义 运算规则
& 逻辑与 同1为1,有一个0即为0
| 逻辑或 有一个1即为1,其余为0
<< 左移 向左移动,低位补0
>> 右移 向右移动,高位补0或1(具体看原数高位为0还是1)
>>> 无符号右移 向右移动,高位补0

面向对象

类和对象

  • 类名首字母建议大写,需要见名知意,驼峰模式。
  • 一个Java文件中可以定义多个class类,但只能有一个类是public修饰的,而且public修饰的类名必须成为代码文件名。实际开发中建议还是一个文件定义一个class类。
  • 成员变量的完整定义格式是:修饰符 数据类型 变量名称 = 初始化值;一般无需制定初始化值,存在默认值

封装

对象代表什么,就得封装对应的数据,并提供数据对应的行为。

继承

权限修饰符 可被访问范围
private 只能本类中访问
缺省 本类、同一个包中的类
protected 本类,同一个包中的类、子孙类
public 任意位置
修饰符 本类里 同一个包中的类 子孙类 任意类
private ✅️


缺省 ✅️ ✅️

protected ✅️ ✅️ ✅️
public ✅️ ✅️ ✅️ ✅️

一般只用私有和公开

方法重写

@Override//方法重写的校验注解(标志):写在重写方法上方,要求方法名称和形参列表必须与被重写方法一致,否则报错!更安全、可读性好、更优雅

子类构造器

当new一个对象的时候子类会先执行父类的构造方法再回头执行自己的构造方法。

super

1
2
3
4
5
public class Test { 
public static void main(String[] args) {
Teacher t = new Teacher("张三", "java", "男");
}
}
1
2
3
4
5
6
7
8
//子类
public class Teacher extends People {
private String skill;
public Teacher(String name, String skill, char sex) {
super(name, sex);//可以在构造函数中就把子类继承父类这部分数据也完成初始化赋值,即name和sex数据都为继承自父类的数据,若不加此句代码,将无法把name和sex数据赋值,也就无法正常打印使用
this.skill = skill;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
//父类
public class People {
private String name;
private char sex;
//无参构造
public People() {
}
//有参构造,子类通过super直接调用此构造函数为name和sex赋值
public People(String name, char sex) {
this.name = name;
this.sex = sex;
}
}

this()调用兄弟构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Student {
//构造方法1
public Student() {}
//构造方法2
public Student (String name, char sex, int age) {
this(name, sex, age, "阳光幼儿园");
//当创建对象并且通过构造函数给成员变量赋初始值的时候,若只赋了name、sex、age这三个值,则会调用此构造方法,此构造方法再通过this()调用构造方法三,并把“阳光幼儿园”赋值给schoolName,至此四个变量均完成初始化赋值操作
}
//构造方法3
public Student(String name, char sex, int age, String schoolName) {
this.name = name;
this.sex = sex;
this.age = age;
this.schoolName = schoolName;
}
}

注意:this()super()不能同时出现在同一个构造方法当中

多态

什么是多态?

多态实在继承/实现情况下的一种现象,表现为:对象多态、行为多态

多态的前提:

继承/实现关系;存在父类引用子类对象;存在方法重写

多态的的注意事项

多态是对象、行为的多态,Java中的属性(成员变量)不谈多态

因此:对于方法而言:编译看左,运行看右;对于变量:编译看左,运行也看左

1
2
3
4
5
6
7
8
9
10
11
public class Test {
public static void main(String[] args) {
Animal a1 = new Wolf();
a1.run();//正确打印"🐺跑的贼快!!!"
System.out.println(a1.name);//打印结果为"动物会跑~~~"

Animal a2 = new Tortoise();//对于方法run,编译的时候看左:a2为Animal对象,运行的时候看右边Tortoise
a2.run();
System.out.println(a2.name);//但对于name变量来说编译和运行都看左(Animal)所以打印的是Animal下的“动物”
}
}
1
2
3
4
5
6
public class Animal {
String name = "动物";
public void run() {
System.out.println("动物会跑~~~");
}
}
1
2
3
4
5
6
7
public class Tortoise extends Animal {
String name = "乌龟";
@Override
public void run() {
System.out.println("🐢跑得贼慢...");
}
}
1
2
3
4
5
6
7
public class wolf {
String name = "狼";
@Override
public void run() {
System.out.println("🐺跑的贼快!!!");
}
}

多态下的类型转换问题

  • 自动类型转换:父类 变量名 = new 子类(); 例:People p = new Teacher();
  • 强制类型转换:子类 变量名 = (子类)父类变量; 例:Teacher t = (Teacher)p;

强制类型转换的一个注意事项

  • 存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错
  • 运行时,如果发现对象的真是类型与强转后的类型不同,就会报类型转换异常(ClassCastEXception)的错误出来
1
2
People p = new Teacher();
Student s = (Student)p;//java.lang.ClassCastException

强转前,Java建议:

  • 使用instanceof关键字,判断当前对象的真实类型,再进行强转p instanceof Student如果p为Student类型此句返回true否则返回false

重载和重写的区别

特性 重载 (Overload) 重写 (Override)
位置 同一个类中 子类与父类之间(继承关系)
方法名 必须相同 必须相同
参数列表 必须不同(个数、类型、顺序) 必须相同
返回值类型 可以不同 必须相同(或其子类)
访问修饰符 无限制 子类范围必须大于或等于父类
抛出异常 无限制 子类不能抛出比父类更宽泛的异常
多态性 编译时多态(静态) 运行时多态(动态)

面向对象高级

认识final

final关键字是最终的意思,可以修饰:类、方法、变量。

  • 修饰类:该类被称为最终类,特点是不能被继承了。
  • 修饰方法:该方法被称为最终方法,特点是不能被重写了
  • 修饰变量:该变量有且仅能被赋值一次

final修饰变量的注意

  • final修饰基本类型的变量,变量存储的数据不能被改变
  • final修饰引用类型的变量,变量存储的地址不能改变,但地址所指向的内容是可以改变的

常量

  • 使用了static final修饰的成员变量就被称为常量
  • 作用:常用于记录系统的配置信息
1
2
3
public class Constant {
public static final String SCHOOL_NAME = "传送教育"//final也可以放在static前面,但是一般放在后边
}

注意!常量名的命名规范:建议使用大写英文单词,多个单词使用下划线连接起来。

使用常量记录系统配置信息的优势、执行原理

  • 代码可读性更好,可维护性也更好
  • 程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的

单例实际模式

  • 作用:确保某个类只能创建一个对象。
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
//饿汉式单例类 (唯一对象在用之前就已被创建)
//写法1
public class A {
//定义一个类变量记住类的一个对象,构造器被私有化,因此外界无法构造对象,需要在类内创建一个(唯一的)对象
private static A a = new A();
//私有构造器,只有把构造器私有,不能被外界访问到才有成为单例类的可能
private A() {}
//定义一个类方法返回对象
public static A getObject() {
return a;
}
}
//外界访问方式
A a1 = A.getObject();

//写法2
public class A {
//定义一个类变量记住类的一个对象,构造器被私有化,因此外界无法构造对象,需要在类内创建一个(唯一的)对象,但是此对象不私有,可直接被外界访问,为防止外界改变a指针的指向,需要用final修饰以防止对象a的指向改变
public static final A a = new A();
//私有构造器,只有把构造器私有,不能被外界访问到才有成为单例类的可能
private A() {}
//因为外界可以直接访问对象a,因此不需要额外方法对外界提供a
}
//外界访问方式
A a1 = A.a;


//懒汉式单例类(第一次使用对象时,对象才开始被创建)
public class B {
//定义一个静态变量用于存储对象
private static B b;
//私有化构造器
private B() {}
//提供一个静态方法,保证返回的是同一个对象
public static B getObject() {
if (b == null) {
b = new B();
}
return b;
}
}

枚举类

  • 枚举是一个特殊类
  • 枚举类中的第一行,只能写枚举类的对象名称,且要用逗号隔开
  • 这些名称,本质是常量,每个常量都记住了枚举类的一个对象

枚举类的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
修饰符 enum 枚举类名 {
名称1, 名称2, …;
其他成员…
}

//例子
public enum A {
X, Y, Z;

}

//上边枚举类例子反编译后的完整形式
public final class A extends java.lang.Enum<A> {
public static final A X = new A();
public static final A Y = new A();
public static final A Z = new A();

public static A[] values();
public static A valueOf(java.lang.String);
}

枚举类的特点

  • 枚举都是最终类,不可被继承,枚举类都是继承java.lang.Enum类的
  • 枚举类的第一行只能罗列一些名称,这些名称是常量,并且每个常量会记住枚举类的一个对象。
  • 枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象
  • 编译器为枚举类新增了几个方法
1
2
3
4
5
6
A a1 = A.X;
A a2 = A.Y;
System.out.println(a1.name());//结果:X,用于返回枚举对象的名称
System.out.println(a2.name());//Y
System.out.println(a1.ordinal());//结果:0
System.out.println(a2.ordinal());//1,这个方法用于返回枚举对象的索引下标

抽象类

  • 在java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法
  • abstract修饰类,这个类就是抽象类
  • abstract修饰方法,这个方法就是抽象方法
1
2
3
4
5
6
7
8
修饰符 abstract class 类名 {
修饰符 abstract 返回值类型 方法名称(形参列表);
}

public abstract class A {
//抽象方法:必须abstract修饰,只有方法签名,不能有方法体
public abstract void test();
}

注意事项、特点

  • 抽象类中不一定要有抽象方法,有抽象方法的类必须是抽象类
  • 普通类有的成员:成员变量、方法、构造器,抽象类都可以有
  • 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现
  • 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须是抽象类

抽象类的应用场景和好处是什么?

  • 父类知道每个子类倒要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们抽出这样的抽象类,就是为了更好的支持多态

模版方法设计模式

  • 提供一个方法作为完成某个功能的模版,模版方法封装了每个实现步骤,但允许子类提供特定步骤的实现
  • 模版方法设计模式可以:提高代码的复用、并简化子类设计

写法

  1. 定义一个抽象类
  2. 在里面定义两个方法
    • 一个是模版方法:把共同的实现步骤放里面
    • 一个是抽象方法:把不确定的实现步骤,交给具体的子类来完成

建议使用final关键字修饰模版方法,为什么?

  • 模版方法是给子类直接使用的,不能被子类重写
  • 一旦子类重写了模版方法,模版方法就失效了

接口

  • Java提供了一个关键字interface定义出接口
    1
    2
    3
    4
    public interface 接口名 {
    //成员变量(常量)
    //成员方法(抽象方法)
    }
  • 注意:接口不能创建对象
  • 接口是用来被类实现(implements)的,实现接口的类称为实现类,一个类可以同时实现多个接口
    1
    2
    3
    修饰符 class 实现类类名 implements 接口1, 接口2, 接口3, ... {
    //实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类。
    }
    jdk8之前,接口中只能定义成员变量和成员方法。

接口的好处

  • 弥补了类单继承的不足,一个类同时可以实现多个接口,使类的角色更多,功能更强大
  • 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现(更利于程序的解耦合)。

jdk8开始,接口新增了哪些方法?

  • 默认方法:使用default修饰,使用实现类的对象调用。
  • 静态方法:static修饰,必须用当前接口名调用
  • 私有方法:private修饰,jdk9开始才有的,只能在接口内部被调用
  • 他们都会默认被public修饰

增强了接口的能力,边用项目的维护拓展

接口的注意事项

  1. 接口与接口可以多继承:一个接口可以同时继承多个接口【重点】
    • 类与类:单继承 一个类只能继承一个父类
    • 类与接口:多实现,一个类可以同时实现多个接口
    • 接口与接口:多继承,一个接口可以同时继承多个接口
  2. 一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现【了解】
  3. 一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的方法,实现类会优先用父类的
  4. 一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可

抽象类与接口对比

相同点:

  1. 都是抽象,都可以有对象方法,都不用创建对象
  2. 都是派生子类形式:抽象类是被子类继承使用,接口是被实现类实现
  3. 一个类继承抽象类,或者实现接口,都必须重写他们的抽象方法,否则自己要成为抽象类或者报错
  4. 都能支持多态,都能实现解耦合

不同点:

  1. 抽象类中可以定义类的全部普通成员,接着看只能定义常量,抽象方法(JDK8新增的三种方式)
  2. 抽象类只能被类单继承,接口可以被类多实现
  3. 一个类继承抽象类就不能再继承其他类,一个类实现了接口还可以继承其他类或者而实现其他接口
  4. 抽象类体现模版思想:更利于做父类,实现代码的复用性
  5. 接着看更适合做功能的解耦合:解耦合性更强更灵活

代码块

代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类)。

代码块分为两种:

  • 静态代码块:
    • 格式:static{}
    • 特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次。
    • 作用:完成类的初始化,例如:对静态变量的初始化赋值
  • 实例代码块:
    • 格式:{}
    • 特点:每次创建对象时,执行实例代码块,并在构造器前执行
    • 作用:和构造器一样,都是用来完成对象的初始化的,例如:对实例变量进行初始化赋值

内部类

成员内部类

  • 就是类中的一个普通成员,类似前面我们学过的普通的成员变量、成员方法

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Outer {
    //成员内部类
    public class Inner {

    }
    }

    //创建对象格式
    外部类名.内部类名 对象名 = new 外部类(...).new 内部类(...);
    Outer.Inner in = new Outer().new Inner();//例子
  • 成员内部类:无static修饰,属于外部类的对象持有

  • 成员内部类中可以直接访问外部类的静态成员,也可以直接访问外部类的实例成员

  • 成员内部类实例方法中,可以直接拿到当前寄生的外部类对象:外部类名.this

静态内部类

  • static修饰的内部类,属于外部类自己持有。

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Outer {
    //静态内部类
    public static class Inner {

    }
    }

    外部类名.内部类名 对象名 = new 外部类.内部类(...);
    Outer.Inner in = new Outer.Inner();//例子
  • 静态内部类中是否可以直接访问外部类的静态成员?可以

  • 静态内部类中是否可以直接访问外部类的实例成员?不可以

局部内部类(了解)

  • 局部内部类是定义在方法中、代码块中、构造器等执行体中。

匿名内部类

  • 是一种特殊的局部内部类;
  • 所谓匿名:指的是程序员不需要为这个类声明名字,默认有一个隐藏的名字。
1
2
3
4
5
6
7
8
9
10
new 类或接口(参数值……) {
类体(一般是方法重写);
};

new Animal() {
@Override
public void cry() {

}
}
  • 特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
  • 作用:用于更方便的创建一个子类对象
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
public class Test {
public static void main(String[] args) {
Swim s1 = new Swim() {
@Override
public void swimming() {
System.out.println("学生游泳贼快~~~");
}
};
start(s1);

start(new Swim() {
@Override
public void swimming() {
System.out.println("老师游泳贼溜~~~");
}
});
}
public static void start(Swim s) {
System.out.println("开始……");
s.swimming();
System.out.println("结束……");
}
}

interface Swim {
void swimming();
}

函数式编程

Lambda表达式

  • JDK8开始新增的一种语法形式,它表示函数

  • 可以用于替代某些匿名内部类对象,从而让程序更简洁,可读性更好。

  • 1
    2
    3
    4
    5
    (被重写方法的形参列表) —> {
    被重写方法的方法体代码。
    }

    注意:Lambda表达式只能替代函数式接口的匿名内部类!!!

什么是函数式接口?

  • 有且仅有一个抽象方法的接口
  • 注意:将来我们见到的大部分函数式接口,上面都可能会有一个@FunctionalInterface的注解,该注解用于约束当前接口必须是函数式接口

Lambda表达式的省略规则

  • 作用:用于进一步简化Lambda表达式的写法。

具体规则:

  • 参数类型全部可以省略不写
  • 如果只有一个参数,参数类型省略的同时“()”也可以省略,但多个参数不能省略“()”
  • 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略分号“;”如果这行代码是return语句,也必须去掉return

静态方法引用

  • 类名::静态方法

使用场景

  • 如果某个Lambda表达式里只是调用一个静态方法,并且“→”前后参数的形式一致,就可以使用静态方法引用。
1
2
3
4
5
6
7
8
9
10
11
public class Student {
private int age;
public static int compareByAge(Student o1,Student o2) {
return o1.getAge() - o2.getAge();
}
}
=================================================
public class Demo1 {
Arrays.sort(students, (o1, o2) -> Student.compareByAge(o1, o2));
Arrays.sort(student, Student::compareByAge);//与上边一行代码相同
}

实例方法引用

  • 对象名::实例方法

使用场景

  • 如果某个Lambda表达式只是通过对象名称调用一个实例方法,并且“→”前后参数的形式一致,就可以使用实例方法引用。

特定类的方法引用

  • 特定类的名称::方法

使用场景

  • 如果某个Lambda表达式里只是调用一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。

构造器引用

  • 类名::new

使用场景

  • 如果某个Lambda表达式里只是在创建对象,并且“→”前后参数情况一致,就可以使用构造器引用

常用api

String创建字符串对象的方式

  • 方式一:Java程序中的所有字符串文字(例如“abc”)都为此类的对象

    1
    2
    String name = "小黑";
    String schoolName = "黑马程序员";
  • 方式二:调用String类的构造器初始化字符串对象

    构造器 说明
    public String() 创建一个空白字符串对象,不含有任何内容
    public String(String original) 根据传入的字符串内容,类创建字符串对象
    public String(char[] chars) 根据字符数组的内容,来创建字符串对象
    public String(byte[] bytes) 根据字节数组的内容,来创建字符串对象
  • String提供的常用方法

    方法名 说明
    public int length() 获取字符串的长度返回(就是字符个数)
    public char charAt(int index) 获取某个索引位置处的字符返回
    public char[] toCharArray(): 将当前字符串转换成字符数组返回
    public boolean equals(Object anObject) 判断当前字符串与另一个字符串的内容一样,一样返回true
    public boolean equalsIgnoreCase(String anotherString) 判断当前字符串与另一个字符串的内容是否一样(忽略大小写)
    public String substring(int beginIndex, int endIndex) 根据开始和结束索引进行截取,得到新的字符串(包前不包后)
    public String substring(int beginIndex) 从传入的索引处截取,截取到末尾,得到新的字符串返回
    public String replace(CharSequence target, CharSequence replacement) 使用新值,将字符串中的旧值替换,得到新的字符串
    public boolean contains(CharSequence s) 判断字符串中是否包含某个字符串
    public boolean startsWith(String prefix) 判断字符串是否以某个字符串内容开头,开头返回true,反之返回false
    public String[] sqlit(String regex) 把字符串按照某个字符串内容分割,并返回字符串数组回来

ArrayList

什么是集合?

  • 集合是一种容器,用来装数据的,类似于数组

有数组,为什么还要有集合?

  • 数组定义完成并启动后,长度就固定了
  • 集合大小可变,功能丰富,开发中用的更多
构造器 说明
public ArrayList() 创建一个空的集合对象
常用方法名 说明
public boolean add(E e) 将指定的元素添加到此集合的末尾
public void add(int index, E element) 在此集合的指定位置插入指定元素
public E get(int index) 返回指定索引处的元素
public int size() 返回集合中的元素个数
public E remove(int index) 删除指定索引处的元素,返回被删除的元素
public boolean remove(Object o) 删除指定的元素,返回删除是否成功
public E set(int index, E element) 修改指定索引处的元素,返回被修改的元素

跳出循环

1
2
3
4
5
6
7
8
9
10
11
OUT:

for(int i = 0; i < n; i++) {

for(int j = 0; j < i; j++) {

break OUT;

}

}

可直接跳出外层循环,OUT可以是任何字符串

java加强

集合框架

异常

java的异常体系

Java.lang.Throwable

  • Error

    代表系统级别错误(属于严重问题),也就是说系统一旦出现问题,sun公司会把这些问题封装成Error对象给出来(说白了,Error是给sun公司自己用的,不是给我们程序员用的,因此我们开发人员不用管他)

  • Exception

    • RuntimeException

      运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常(如:数据索引越界异常)

    • 其他异常

      编译时异常:编译阶段就会出现错误提醒的。(如:日期解析异常)

异常的基本处理

  • 抛出异常(throws)

    在方法上使用throws关键字,可以将方法内部出现的异常破除去给调用者处理。

    1
    2
    3
    方法 throws 异常1, 异常2, 异常3...{

    }
  • 获取异常(try…catch)

    直接捕获程序出现的异常

    1
    2
    3
    4
    5
    6
    7
    try {
    // 监控可能出现异常的代码
    }catch(异常类型1 变量) {
    // 异常处理
    }catch(异常类型2 变量) {
    // 异常处理
    }...

作用

异常是用来定位程序bug的关键信息

可以作为方法内部的一种特殊返回值,以便通知上层调用者,方法的执行问题

自定义异常

  • Java无法再这个世界上全部的问题都提供异常类来代替,如果企业自己的某种问题,像通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。
自定义运行时异常 自定义编译时异常
定义一个异常类继承RuntimeException 定义一个异常类继承Exception
重写构造器 重写构造器
通过throw new异常类(xxx)来创建异常对象并抛出 通过throw new 异常类(xxx)创建异常对象并抛出
特点:编译阶段不报错,运行时才可能出现,提醒不属于激进型 特点:编译阶段就报错,提醒比较激进

泛型

  • 定义类、接口、方法时,同时声明了一个或多个类型变量(如:<E>)称为泛型类、泛型接口,泛型方法,他们统称为泛型

    1
    2
    3
    public class ArrayList<E> {
    ...
    }
  • 作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的异常

  • 泛型的本质:把具体的数据类型作为参数传给泛型变量

泛型类

1
2
3
修饰符 class 类名<类型变量,类型变量, ...> {

}
1
2
3
public class ArrayList<E> {
...
}
  • 注意:类型变量建议用大写的英文字母,常用的有:E、T、K、V等

泛型方法

1
2
3
4
5
6
7
8
9
10
11
12
13
修饰符 <类型变量, 类型变量, ...> 返回值类型 方法名(形参列表) {

}

// ✅️是泛型方法
public static <T> void test(T t) {

}

// ❌️不是泛型方法,因为这个E不是由这个方法自己定义的,而是由这个方法所在的泛型类定义的
public E get(int index) {
return (E) arr[index];
}

通配符

  • 就是“?”,可以在“使用泛型”的时候代表一切类型;E T K V是在定义泛型的时候使用

泛型的上下限

  • 泛型上限:? extends Car ?能接收的必须是Car或者其子类
  • 泛型下限:? super Car ?能接收的必须是Car或者其父类

泛型支持的数据类型

  • 泛型不支持基本数据类型,只支持对象数据类型(引用数据类型)

    因此出现了包装类,可以把基本数据类型包装成对象进而被泛型使用

包装类

  • 包装类就是把基本类型的数据包装成对象的类型。
基本数据类型 对应的包装类(引用数据类型)
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double
boolean Boolean

基本类型的数据包装成对象的方案

  • public Integer(int value) // 已过时
  • public static Integer valueOf(int i)

**自动装箱:**基本数据类型可以自动装换成包装类型

**自动拆箱:**包装类型可以自动装换为基本数据类型

包装类具备的其他功能

  • 可以把基本数据类型的数据转换成字符串类型

    public static String toString(doublie d)

    public String toString()

  • 可以把字符串类型的数值转换成数值本身对应的真实数据类型

    public static int parseInt(String s)

    public static Integer valueOf(String s) // 建议使用这个 方便

集合框架

集合体系结构

Collection<E>(接口)

  • List<E>(接口)
    • ArrayList<E>(实现)
    • LinkedList<E>(实现)
  • Set<E>(接口)
    • HashSet<E>(实现)
      • LinkedHashSet<E>(实现)
    • TreeSet<E>(实现)

Collection集合特点

  • List系列集合:添加的元素是有序、可重复、有索引
    • ArrayList、LinkedList:有序、可重复、有索引
  • Set系列集合:添加的元素是无序、不重复、无索引
    • HashSet:无序、不重复、无索引
    • LinkedHashSet:有序、不重复、无索引
    • TreeSet:按照大小默认升序排列、不重复、无索引

Collection是单列集合代表,Map是双列集合代表

Collection的常用功能

为啥要先学Collection的常用方法?

  • Collection是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的
方法名 说明
public boolean add(E e) 把给定的对象添加到当前集合中
public void clear() 清空集合中所有的元素
public boolean remove(E e) 把给定的对象在当前集合中删除
public boolean contains(Object obj) 判断当前集合中是否包含给定的对象
public boolean isEmpty() 判断当前集合是否为空
public int size() 返回集合中元素的个数。
public Object[l toArray() 把集合中的元素,存储到数组中

Collection的遍历方法

  • 迭代器是用来遍历集合的专用方式(数组没有迭代器),在java中迭代器的代表是Iterator。

Collection集合获取迭代器的方法

Iterator<E> iterator()返回集合中的迭代器对象,该迭代器对象默认指向当前集合的第一个元素

  • Iterator迭代器中的常用方法

boolean hasNext()询问当前位置是否有元素存在,存在返回true,不存在返回false

E next()获取当前位置的元素,并同时将迭代器对象指向下一个元素处

Collection的遍历方式二:增强for循环

1
2
3
4
5
6
7
8
9
for (元素的数据类型 变量名 : 数组或集合) {

}

Collection<String> c = new ArrayList<>();
...
for (String s : c) {
System.out.prinln(s);
}
  • 增强for可以用来变量集合或者数组
  • 增强for遍历集合,本质就是迭代器遍历集合的简化写法

Collection集合的遍历方式三:Lambda表达式

  • 得益于jdk 8开始的新技术Lambda表达式,提供了一种更简单、更直接的方式来遍历集合

需要使用Collection的如下方法来完成

default void forEach(Consumer<? super T> action)结合lambda遍历集合

1
2
3
4
5
6
7
8
9
10
11
12
13
Collection<String> lists = new ArrayList<>();
...
lists.forEach(new Consumer<String>(){
@Override
public void accept(String s) {
System.out.println(s);
}
});

lists.forEach(s -> {
System.out.println(s);
});
// lists.forEach(s -> System.out.println(s));