JAVA开发学习笔记-上
简介
JAVA开发分类
- JAVA SE: JAVA语言标准版,用于桌面应用的开发
- JAVA ME: JAVA的小型版,用于嵌入式电子设备或者小型移动设备开发
- JAVA EE: JAVA语言的企业版,用于Web方向的网站开发,服务器应用
JAVA用途:
- 桌面应用开发:税务管理软件,IDEA,Clion,Pycharm
- 企业级应用开发:微服务,springcloud
- 移动应用开发:鸿蒙,Android,医疗设备
- 科学计算:MATLAB
- 大数据开发:hadoop
- 游戏开发:我的世界
开发基础概念
- JDK:java development kit
- JRE: java runtime environment
- JVM: java virtual machine
- JDK>JRE>JVM
JAVA变量命名:
- 小驼峰:方法名、变量名-name、firstName
- 大驼峰:类名-Student、GoodStudent
项目结构
1
2
3
4* project
* module
* package
* class
数组
- 定义
- 数据类型 []数组名:int[] array
- 数据类型 数组名[]: int array[]
- 初始化
- 静态初始化
- 静态初始化:数据类型[] 数组名 = new 数据元素[]{元素1,元素2,元素3}; 如 int[] array = new int[]{1,2,3,4,5};
- 简写格式: int[] arr = {1,2,3,4}
- 动态初始化
- 定义:初始化时只指定数组长度,由系统为数组分配初始值
- 格式:数据类型[] 数组名 = new 数据类型[数据长度]
- 数组的内存图:
- 栈:方法运行时使用的内存,比如main方法运行,进入栈中执行(开始执行时进栈,执行完毕后出栈)
- 堆:存储对象或数组,new创建的都存储在堆内存中。
- 方法区:存储可以运行的class文件
- 本地方法栈:JVM在使用操作系统功能的时候使用,和我们开发无关
- 寄存器:给CPU使用,和我们开发无关。
- 数组的直接复制,实际复制的是地址。(类似引用数据类型)
- 静态初始化
方法
- 方法是程序中最小的执行单元、重复的代码、具有独立功能的代码抽取到方法中,可以提高代码的复用性和可维护性。
- 方法定义(写在main外面,class里面):
- 无参方法定义和调用:public static void methodName(){}
- 有参方法定义和调用
- public static void methodName(paramType name){}
- 有返回值
- public static returnType methodName(paramType name){return xxx;}
- 方法注意事项:
- 方法不调用就不执行。
- 方法与方法之间是平级关系,不能相互嵌套。
- 方法的编写顺序和执行顺序无关。
- Return直接结束方法。
- 重载:同类中同方法名但传参不同(个数、类型、顺序),和返回值无关。
面向对象
学习获取已有对象并使用/学习如何自己设计对象并使用。
类和对象
类是对象共同特征的描述,对象是类的具体实例。
必须先设计类、再实例化对象
1
2
3
4
5
6
7public class 类名{
1. 成员变量
2. 成员方法
3. 构造器(后面学习)
4. 代码块(后面学习)
5. 内部类(后面学习)
}初始化:
- 类名 对象名 = new 类名();
使用对象:
- 访问属性: 对象名.成员变量
- 访问行为: 对象名.方法名(…)
类的几个补充注意事项:
- javaBean类与测试类:
- 用来描述一类事物的类,专业叫做javabean类,在javabean类中是不写main方法的。
- 之前编写main方法的类叫做测试类。我们可以在测试类中创建javabean类的对象并进行赋值调用。
- 类名首字母建议大写,需要见名知意,驼峰模式。
- 一个java文件中可以定义多个class类,且只能一个类是public修饰,而且public修饰的类名必须成为代码文件。实际开发中建议还是一个文件定义一个class类。
- 成员变量完整格式为:修饰符 数据类型 变量名称 = 初始化值;一般无需指定初始化值,存在默认值。
- javaBean类与测试类:
面向对象三大特征:封装、继承、多态
- 封装:如何正确的设计对象的属性和方法。
- 原则:对象代表什么,就得封装对应的数据,并提供数据对应的行为,(人画圆属于圆对象)。
- 好处:1. 让编程变得简单;2. 降低学习成本。
- 关键字:
- private:权限修饰、可以修饰成员,只能在类内被访问,被外部使用需要对应的set和get操作
- 继承:见下文
- 多态:见下文
this关键字
通过this来区分成员变量和区部变量,通过this来给成员变量进行赋值,this指向当前的类的地址值。
成员变量和局部变量
- 局部变量定义在方法里,成员变量定义在方法外
- 使用遵循就近原则:谁离的近就用谁。
构造方法
功能:在创建对象时,对成员变量进行赋值。
1
2
3修饰符 类名(参数){
方法体;
}特点:
- 方法名和类名相同,大小写也要一致;
- 没有返回值类型,连void都没有
- 没有具体的返回值(不能由return带回结果数据)
执行时机:
- 创建对象的时候由虚拟机调用,不能手动调用构造方法
- 每创建一次对象,就会调用一次构造方法。
注意事项:
- 定义
- 如果我们没有写任何的构造方法,虚拟机会自动创建空参构造方法。
- 如果定义了构造方法,虚拟机将不再创建空参构造方法。
- 重载
- 带参构造方法和无参构造方法,方法名相同但是参数名不同,这叫做构造方法的重载。
- 推荐使用方式
- 无论是否使用,都建议定义带参构造方法和无参构造方法。
- 定义
标准JavaBean
- 类名需要见名知意、大驼峰命名
- 成员变量使用private修饰
- 构造方法至少提供两个:无参构造方法和全参构造方法
- 成员方法、
- 提供每一个成员的set和get方法
- 如果还有其他行为,也需要写上
- 快捷生成:Command+N快速生成标准JavaBean,插件PTG
对象内存图
- 栈:方法运行时使用的内存,比如main方法运行,进入栈中执行(开始执行时进栈,执行完毕后出栈)
- 堆:存储对象或数组,new创建的都存储在堆内存中,并产生地址。
- 方法区:存储可以运行的class字节码文件。(从jdk8开始取消了方法区,新增了元空间,把原来方法区的多种功能进行拆分,有的功能放到了堆中,有的功能放到了元空间中)
- 本地方法栈:JVM在使用操作系统功能的时候使用,和我们开发无关
- 寄存器:给CPU使用,和我们开发无关。
一个对象的内存图:Student s = new Student();
- 加载class文件
- 申明局部变量s
- 在堆空间中开辟一个空间
- 默认初始化
- 显示初始化
- 构造方法初始化
- 将堆内存中的地址值赋值给局部变量
基本数据类型:整数、浮点数、布尔值、字符型。
引用数据类型:除基本数据类型的其他类型。
- 基本数据类型的数据值存储在自己的空间中
- 引用数据类型的数据值存储在其他的空间中,自己空间中存储的是地址值。
API和字符串
API
- API: application programming interface,应用程序编程接口,可以指别人已经编写好的东西,不需要自己编写,直接用即可。
- JAVA API:JDK中提供的各种功能的Java类。
- 已经学习过的API:
- Scanner
- Random
- 其他的API:查询JDK-API帮助文档(帮助开发人员更好的使用API和查询API的一个工具)
字符串
String
- String是JAVA定义好的类,定义在java.lang中,无需导包。
- String的内容是不会发生改变的,它的对象在创建后不能被更改。
- 字符串拼接或赋值后产生新的字符串。
- 创建字符串的两种方式。
- 直接复制。 String name = “xxxxx”;当使用双引号直接复制时,系统会检查该字符串是否在串池中存在,如果存在则复用,不存在时创建新的。
- 使用new创建新的String对象;new一次开辟一次空间,不会复用已存在的字符串空间。
- 空串创建
- 字符串创建
- 字符数组创建
- 字节数组创建
- StringTable(串池):只有字符串直接赋值的内容存在串池,从JDK7开始,从方法区挪到了堆内存。
- ==的比较:
- ==号比基本数据类型时,比较的是数据值
- ==号比引用数据类型时,比较的是地址值
- 字符串比较:
- String1.equals(String2);
- String1.equalsIgnoreCase(String2);
- 字符串遍历:string1.charAT(index):返回index位置的对应索引字符。
- 字符串拼接:可以直接使用+运算符
- 字符串翻转:倒序遍历即可。
- 字符串截取:substring(start, end) 或substring(start)
- 字符串替换:replace(old, new)
StringBuilder
- StringBuilder创建后的内容是可变的,提高字符串操作效率
- 构造方法:
- Public StringBuilder();
- Public StringBuilder(str);
- 常用方法
- append(任意类型): 添加数据,并返回对象本身
- Reverse():翻转字符串内容
- length():返回长度
- toString():把StringBuilder转换为String
- 链式编程:在调用一个方法时,不需要用变量接受他的结果,可以继续调用其他方法。(连续调用方法)。
StringJoiner(JDK8及以后支持)
- 构造方法:
- StringJoiner(间隔符)
- StringJoiner(间隔符,开始符,结束符)
- 常用方法:
- add(CharSequence):添加数据,并返回对象本身
- length():返回长度
- toString():把StringJoiner转换为String
拓展原理:
- 字符串拼接的底层原理:
- 无变量参与,JVM虚拟机在编译时进行优化,复用串池中的字符串
- 有变量参与,本质是调用StringBuilder后toString在堆中重新开辟内存
- StringBuilder提高效率:所有要拼接的内容都往StringBuilder中放,节约内存
- StringBuilder可变长度
- 默认为16长度,支持自动扩容。
- 默认扩容容量*2+2,超出默认扩容则创建自动容量
集合
与数组的差异
- 数组长度不可变,集合长度可自动扩容(自动伸缩,可长可短)。
- 数组既可以存储基本类型和引用数据类型,但集合只能存储引用数据类型,如果集合要存储基本数据类型则需要存储其包装类。
ArrayList
- 初始化: ArrayList
name = new ArrayList<>(); - 常用方法:
- 增:add()
- 删:remove(value) or remove(index)
- 改:set(index, value)
- 查:get(index)
- 大小:size()
- 初始化: ArrayList
面向对象进阶
static
- static表示静态,是Java中的一个修饰符,可以修饰成员变量,成员变量。
- 被static修饰的成员变量叫做静态变量,该变量被所有对象共享,不属于对象属于类,静态变量是随着类的加载而加载的,优先于对象出现。调用方式为类名调用(class.paramName)或对象名调用(instance.paramName)。
- static内存图:jdk8后static变量存储在堆内存中
- 被static修饰的成员方法叫做静态方法,多用在测试类和工具当中,Javabean在类中很少会用,调用方式为类名调用(class.MethodName)或对象名调用(instance.paramName)
类
- JavaBean类:用来描述一类事务的类。比如Student,Teacher,Dog,Cat.
- 测试类:用来检查其他类是否书写正确,带有main方法,是程序的入口。
- 工具类:不是用来描述一类事物的,而是帮我们做一些事情的类。
- 类名见名知义:public class xxxUtil { }
- 私有化构造方法 private xxxUtil{}
- 方法定义为静态 public static int methodName(){}
- 注意事项
- 静态方法只能访问静态变量和静态方法
- 非静态方法可以访问静态变量和静态方法,也可以访问非静态成员变量和非静态成员方法
- 静态方法中是没有this关键字的。
继承
Java中提供一个extends关键字,让一个类和另一个类建立起继承关系。比如:public class Student extends Person {},Student类称为子类(派生类),Person类称为父类(基类或超类)
好处:面向对象的三大特征之一
- 继承把多个子类中重复的代码抽取到父类中了,提高了代码的复用性;
- 同时子类可以在父类的基础上,增加其他的功能,使得子类更加强大。
- 当类与类之间,存在共性的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码。
当类与类之间,存在共性的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码。
继承的特点:
- Java中只支持单继承,一个类只能继承一个直接父类。
- Java不支持多继承,但支持多层继承(间接父类)。
- 每一个类都直接或者间接的继承于Object类
- 子类只能访问父类中非私有的成员
子类能继承父类中的哪些内容:
成员类型 public private 构造方法 public不能 private不能 成员变量 public能 private能继承,但是不能用 成员方法 虚方法表 能 非虚方法表 不能 虚方法表:非private、非static、非final,父类会将虚方法表在继承时继承给子类,子类对应加入自己的虚方法,并向下传递。只有虚方法才能被子类继承。object类有五个虚方法。
内存分析工具:
- jps:打印内存中类的id
- jhsdb hsdb:调出内存分析工具
- 查看类的方法:Ctrl + command +f12
继承需要学习的点
- 成员变量
- 成员变量访问特点:就近原则:谁离我近,我就用谁。
- 出现了重名的成员变量:name、this.name、super.name
- 成员方法:
- 成员方法访问特点:就近原则:谁离我近,我就用谁。
- 方法重写:当父类的方法不能满足子类的需求时,需要进行方法重写,需要加上@Override,方法重写的本质是覆盖虚方法表中的方法
- 需要子类的方法声明和父类中一模一样
- 子类重写父类方法时,访问权限子类必须大于等于父类(空着不写<protected<public)
- 子类重写父类方法时,返回值类型子类必须小于等于父类(子类<父类)
- 建议:重写的方法尽量和父类保持一致
- 只有被虚方法表中的方法才能被重写
- 成员变量
继承中的构造方法:
- 父类中的构造方法不会被子类继承。
- 子类中所有构造方法默认先访问父类中的无参构造,再执行自己,原因是:
- 子类有时候会用到父类中的数据,所以以此进行继承变量的初始化操作。
- 子类初始化之前,一定要调用父类构造方法完成父类数据空间的初始化。
- 如何调用父类构造方法:
- 子类构造方法的第一句语句默认都是super(),不写也存在,且必须在第一行。
- 如果想调用父类有参构造,必须手动写super进行调用。
this、super使用总结
- this:理解为一个变量,表示当前方法调用者的地址。
- Super:代表父类存储空间。
其他:
- 打印对象的内存信息ClassLayout
- External tools:showbytecodes
多态
- 封装:对象代表什么,就得封装对应的数据,并提供数据对应的行为。
- 继承:通过抽象共性特征建立起父子类的对应关系,这就是继承。
- 多态:同种类型的对象,表现出的不同形态,即对象的多种形态。
- 表现形式:父类类型 对象名称=子类对象。
- 前提:
- 有继承关系
- 有父类引用指向子类对象,如Person s = new Student();
- 有方法重写
- 好处:使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。
- 多态调用成员的特点:
- 变量调用:编译看左边,运行也看左边。
- 方法调用:编译看左边,运行看右边。
- 多态的优势:
- 在多态形式下,右边对象可以实现解耦合,便于拓展和维护。
- 定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。
- 多态的弊端:
- 不能调用子类的特有方法,原因是因为多态必须要重写方法。换句话说,多态只能调用重写的子类方法。
- 如果需要调用需要强制类型转换,转换为子类类型
- 加instanceof判断对象类型: 对象名 instanceof 类名
- jdk14后,可以将instanceof判断+转换合并在一起,调用方法为 对象名 instanceof 类名 新对象名
包和Final
- 包
- 包就是文件夹。用来管理各种不同功能的Java类,方便后期代码维护。
- 包名的规则:公司域名反写+包的作用,需要全部英文小写,见名知意。 com.itheima.domain
- 全类名/全限定名:包名+类名,如com.itheima.domain.Student
- 使用其他类时,需要使用全类名。比如 new com.itheima.domain.Student(),但可以导包,用import 将包名前缀进行优化;导包规则如下:
- 使用同一个包中的类时,不需要导包。
- 使用java.lang中的类时,不需要导包。
- 其他情况都需要导包。
- 如果同时使用两个包中的同名类,需要用全类名。
- Final
- 修饰方法时,表明该方法时最终方法,不能被重写。
- 修饰类时,表明该类时最终类,不能被继承。
- 修饰变量时,表明该变量叫做常量,只能被复制一次
- 常量
- 实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。
- 常量的命名规范:
- 单个单词:全部大写
- 多个单词:全部大写,单词之间用下划线隔开。
- 细节:
- final修饰的变量是基本类型,那么变量存储的数据值不能发生改变。
- final修饰的变量是引用类型,那么变量存储的地址值不能法神改变,对象内部的可以改变。
权限修饰符和代码块
权限修饰符
是用来控制一个成员能够被访问的范围的。
可以修饰成员变量,方法,构造方法,内部类。
权限大小:private<空/缺省/默认<protected<public
修饰符 同一个类中 同一个包中其他类 不同包下的子类 不同包下的无关类 private 1 空/缺省/默认 1 1 protected 1 1 1 public 1 1 1 1 实际开发中,一般只用private和public
- 成员变量私有
- 方法公开(特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有)
代码块
- 局部代码块:写在方法中的单独的代码块,不是整个方法的括号,用于提前结束变量的生命周期。
- 构造代码块:写在类中成员位置,一般用于抽取多个构造方法中的重复代码,优先于构造方法执行。
- 静态代码块: static{},需要通过static修饰,随着类的加载而加载,并且自动触发,只执行一次,通常在类的初始化时使用。
抽象类和抽象方法
抽象方法:将共性的行为(方法)抽取到父类之后,由于每一个子类执行的内容是不一样,所以,在子类中不能确定具体的方法体。该方法就可以定义为抽象方法。
如果一个类中存在抽象方法,那么该类就必须声明为抽象类。
抽象类的定义格式
抽象方法的定义格式: public abstract 返回值类型 方法名(参数列表);
抽象类的定义格式: public abstract class 类名{}
注意事项
- 抽象类不能实例化,即抽象类不能实例化出对象
- 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
- 抽象类可以有构造方法
- 抽象类的子类
- 要么重写抽象类中的所有抽象方法
- 要么是抽象类
- 意义:强制子类必须按照特定的格式来进行方法实现。
接口
接口本身是对行为的抽象
接口用关键字interface来定义 public interface 接口名{}
接口不能实例化
接口和类是实现关系,通过implements关键字表示 ,public class 类名 implements 接口名{}
接口的子类(实现类)
- 要么重写接口中的所有抽象方法
- 要么是抽象类
注意点
- 接口与类的关系,可以单实现/多实现 public class 类名 implements 接口1,接口2{}
- 实现类还可以在继承一个类的同时实现多个接口,如public class 类名 extends 父类 implements 接口1,接口2{}
接口中的成员的特点
- 成员变量
- 只能是常量
- 默认修饰符:public static final
- 构造方法
- 没有
- 成员方法
- Jdk7以前,接口中只能定义抽象方法,默认修饰符:public static final
- Jdk8特性:接口中可以定义有方法体的方法。(默认、静态)
- Jdk9特性:接口中可以定义私有方法。
- 成员变量
接口和类的关系
- 类与类: 继承关系,只能单继承,不能多继承,但是可以多层继承
- 类与接口: 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
- 接口与接口: 继承关系,可以单继承,也可以多继承
Jdk8开始接口中新增的方法:
- Jdk7以前,接口中只能定义抽象方法,默认修饰符:public static final
- Jdk8特性
- 接口中可以定义有方法体的方法。(默认)
- 目的:为了解决接口升级的问题
- 格式:public default 返回值类型 方法名 参数列表(){}
- 注意事项
- 默认方法不是抽象方法,所以不强制被重写,但是如果被重写,重写的时候去掉default关键字;
- Public可以省略,default不能省略;
- 如果实现了多个接口,多个接口存在相同名字的默认方法,子类就必须对该方法进行重写。
- 接口中可以定义有方法体的方法。(静态)
- 目的:?
- 格式:public static 返回值类型 方法名 参数列表(){}
- 注意事项
- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用。
- public可以省略,static不能省略。
- 接口中可以定义有方法体的方法。(默认)
- Jdk9特性:接口中可以定义私有方法。
- 目的:希望只为接口调用的方法不被外部类访问调用。
- 调用规范:
- 接口中普通的私有方法服务于default默认方法;
- 接口中static的私有方法服务于static普通方法;
- 格式:
- private 返回值类型 方法名(参数列表){}
- private static 返回值类型 方法名 (参数列表){}
接口的应用
- 接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。
- 当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。
适配器设计模式:解决接口与接口实现类之间的矛盾问题。
- 设计模式(Design pattern):是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。简单理解就是解决各种问题的套路。
- 适用场景:interface中有很多方法,但实际类中只需要使用一个。
- 步骤:创建abstract类型的中间类XXXAdapter类,对所有的接口方法空实现,然后让真正的类继承Adapter类
内部类
- 初始内部类
- 类的五大成员:属性、方法、构造方法、代码块、内部类
- 定义:在一个A类的内部里面,再定义一个B类,B类就叫做内部类
- 规则:内部类表示的事物是外部类的一部分,内部类单独出现没有任何意义
- 内部类的访问特点:
- 内部类可以直接访问外部类的成员,包括私有;
- 外部类要访问内部类的成员,必须创建对象;
- 成员内部类
- 写在成员位置的,属于外部类的成员。
- 注意点:
- 成员内部类可以被一些修饰符所修饰,比如private、默认、protected、public、static等
- 在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量。
- 创建并获取成员内部类的两种方式
- 在外部类中编写方法,对外提供内部类对象
- 外部类名.内部类名 对象名 = new 外部类对象.new 内部类对象()
- 成员内部类如何获取外部类的成员变量
- 外部类.this.变量名,如Outer.this.name
- 静态内部类
- 定义:内部类前面带有static修饰的,即为静态内部类,静态内部类也是成员内部类的一种
- 静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。
- 创建静态内部对象的格式
- 外部类名.内部类名 对象名 = new 外部类名.内部类名();
- 调用非静态方法的格式:先创建对象,用对象调用
- 调用静态方法的格式:外部类名.内部类名.方法名()
- 局部内部类
- 定义:将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
- 特点:外部是无法直接使用,需要在方法内部创建对象并使用。
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
- 匿名内部类
- 本质:隐藏了名字的内部类
- 格式:new 类名或接口名(){重写方法;};
- 继承、实现
- 方法重写
- 创建对象
- 使用场景:
- 方法名(类/接口),这里的参数可以直接创建并使用匿名内部类
- 接口多态,将匿名内部类赋值为接口类型的对象
- 方法调用,匿名类创建后直接通过点来调用对应的对象的方法
- Javap可以用于反编译
常用API
Math
- 需要用的时候看文档就可以了,没有太多新东西。
System
- exit():终止当前的java虚拟机
- currentTimeMilis(): 返回当前系统的时间毫秒值(时间原点:1970.1.1 8:00)
- arrayCopy():数组拷贝
Runtime:
- getRuntime():当前系统的运行环境对象
- exit():停止虚拟机
- availableProcessors():获得CPU的线程数
- maxMemory():JVM能从系统中获取总内存大小(byte)
- totalMemory():JVM已经从系统中获取总内存大小(byte)
- freeMemory():JVM剩余内存大小(byte)
- exec(): 运行cmd命令
Object和Objects
- Object是java中的顶级父类。所有的类都直接或间接的继承于Object类。
- Object类中的方法可以被所有子类访问,所以我们要学习Object类和其中的方法。
- Object只有空参构造,没有有参的构造方法,因为所有的类没有任意一个共同特征。
- 成员方法
- toString():返回对象的字符串表示形式,格式为:包名.对象名@地址值,PTG插件可快速重写
- equals():比较两个对象是否相等,本质上是比较地址值是否相等,如有需要可以进行重写
- clone():对象浅克隆,即把A对象的属性值完全拷贝给B对象,也叫对象拷贝,对象复制。
- Clone在java.lang中,且为protected类型,如果需要则必须重写方法且需要实现克隆接口
- 浅克隆/浅拷贝:基本数据类型拷贝值、引用数据类型拷贝地址
- 深克隆:基本数据类型拷贝值、字符串复用、引用数据类型重新创建对象将原地址内容拷贝,可以借助gson通过序列化和反序列化实现对象深克隆。
- 对象工具类Objects:
- equals(Object a, Object b): 先做非空判断,比较两个对象
- isNull(Object obj):判断对象是否为null,为null返回True,否则返回False
- nonNull(Object obj):判断对象是否不是null,为null返回False,否则返回True
BigInteger
- 对象一旦创建,里面的数据不能发生改变。
- BigInteger(int num, Random rand):获取随机大整数,范围:[0~2的num次方-1)
- BigInteger(String val): 获取指定的大整数
- BigInteger(String val, int radix):获取指定进制的大整数
- BigInteger.valueOf(long val):通过静态方法获取BigInteger的对象,内部有优化
- 能表示的范围比较小,只能在long的范围内进行取值,】、如果超出long就不行了
- 在内部对常用的数字,对-16~16进行了优化,不会重复创建,会直接复用
- 只要进行计算,都会产生一个新的BigInteger对象
- 其他方法加减乘除等可根据需求查询,此处不再赘述
- 底层存储方法
- 对于计算机而言,其实是没有数据类型的概念的,都是0和1
- 数据类型是编程语言自己规定的
BigDecimal
- 用于较大的小数计算,按需学习,此处不再赘述。
正则表达式&爬虫
- 按需学习,此处不再赘述。
包装类
- 定义:基本数据类型对应的引用数据类型。
- 基本数据类型与包装类对应关系
- 创建对象类方法:构造方法+静态方法
Arrays
- 操作数组的工具类,按需学习,此处不再赘述。
函数式编程与lambda表达式
- 函数式编程:忽略面向对象的复杂语法,强调做什么,而不是谁去做。
- 面向对象:先找对象,让对象做事情
- Lambda表达式就是函数式编程思想的体现
- 格式:()->{}
- ():对应着方法的形参
- ->:固定格式
- {}:对应着方法的方法体
- 注意点:lambda表达式可以用来简化匿名内部类的书写,但只能简化函数式接口的匿名内部类写法,所谓函数式接口,即有且仅有一个抽象方法的接口,接口上方可以加@Functionalinterface注解。
- 省略写法:省略核心为:可推导、可省略。
- 参数类型可以省略不写
- 如果只有一个参数,参数类型可以省略,同时()也可以省略。
- 如果lambda表达式的方法体只有一行,大括号、分号、return可以省略不写,可以同时省略
集合进阶
- 集合体系结构
- 单列集合:Collection(interface):
- List(interface):添加的元素是存取有序、可重复、有索引
- ArrayList(implement class)
- LinkedList(implement class)
- Vector(implement class):已淘汰
- Set(interface):添加的元素是存取无序、不重复、无索引
- HashSet(implement class)
- LinkedHashSet(implement class)
- TreeSet(implement class)
- HashSet(implement class)
- List(interface):添加的元素是存取有序、可重复、有索引
- 双列集合:Map
- 单列集合:Collection(interface):
Collection
Collection:是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的
- 常用方法
- add(E e):把给定的对象添加到当前集合中
- clear():清空集合中所有的元素
- remove(E e): 把给定的对象在当前集合中删除
- contains(Object obj):判断当前集合中是否包含给定的对象
- isEmpty():判断当前集合是否为空
- size():返回集合中元素的个数/集合的长度
- 遍历方式
- 迭代器遍历:不依赖索引,且迭代器是集合专用的遍历方式
- 常用方法
- Iterator
iterator():返回迭代器对象,默认指向当前集合的0索引 - boolean hasNext():判断当前位置是否有元素,有返回true,否则False
- E next():获取当前位置的元素,并将迭代器对象移向下一个位置
- Iterator
- 细节注意点
- 报错NoSuchElementException
- 迭代器遍历完毕,指针不会复位
- 循环中只能用一次next方法
- 迭代器遍历时,不能用集合的方法进行增加或者删除,需要用迭代器方法remove()进行删除
- 常用方法
- 增强for遍历
- 增强for的底层就是迭代器,为了简化迭代器的代码书写的
- 是JDK5之后出现的,其内部原理就是一个迭代器
- 所有的单列集合和数组才能用增强for进行遍历
- for(元素的数据类型 变量名:数组或者集合){循环体},快捷生成为xxx.for
- lambda表达式遍历
- 迭代器遍历:不依赖索引,且迭代器是集合专用的遍历方式
- 常用方法
List集合(ArrayList、LinkedList、Vector):存取有序、可重复、有索引
- Collection的方法List都继承了
- List集合因为有索引,所以多了很多索引操作的方法。
- void add(int index,E element):在此集合中的指定位置插入指定的元素
- E remove(int index):删除指定索引处的元素,返回被删除的元素
- E set(int index, E element):修改指定索处的元素,返回被修改的元素
- E get(int index):返回指定索引处的元素
- 遍历方法:
- Collection的三种遍历方式:迭代器遍历、增强for遍历、lambda表达式遍历
- 普通for遍历:因为List集合存在索引
- 列表迭代器遍历:ListIterator(),继承于Iterator(),在遍历的过程中如果需要添加元素,则需要使用列表迭代器
数据结构(栈、队列、数组、链表、二叉树、二叉查找树、平衡二叉树、红黑树)
- 数据结构是计算机底层存储、组织数据的方式。
- 数据是如何存储及组织的?
- 数据如何存入?
- 数据如何取出?
- 栈:后进先出,先进后出。
- 队列:先进先出、后进后出。
- 数组:连续存储,通过地址值和索引定位,查询速度快&删除效率低&修改效率极低。
- 链表:元素游离,节点独立,内存中不连续,节点中包含数据值和下一个节点地址,查询速度慢,但链表增删相对较快,特别是首尾操作极快,有单向和双向链表。
- 数据结构是计算机底层存储、组织数据的方式。
ArrayList集合基层原理
- 利用空参创建的集合,在底层创建一个默认长度为0的数组。
- 添加第一个元素时,底层会创建一个新的长度为10的数组。
- 存满时,会扩容1.5倍
- 如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准。
LinkedList集合
- 双向链表,查询慢,增删快,但是如果操作的是首尾元素的话,速度也很快。
- 特有方法:
- addFirst(E e):向集合头插入元素
- addLast(E e):向集合尾插入元素
- getFirst():获取集合的头部元素
- getLast():获取集合的尾部元素
- removeFirst():删除集合的头部元素
- removeLast():删除集合的尾部元素
泛型类、泛型方法、泛型接口
泛型
- 泛型是JDK5中引入的特性,可以在编译阶段约束的数据类型,并进行检查。
- 泛型的类型: <数据类型>,但仅支持引用数据类型,支持该类及子类传递
- 集合在没有指定泛型时,可以给集合中添加任意数据类型,但存在调用时无法使用特有行为的缺点,建议是通过泛型约束统一数据类型。而且在运行时期可以存在的问题提前到了编译器,可以提前发现异常。
- Java中的泛型其实是伪泛型,仅在编译时期有效,目的是为了向下兼容
泛型类:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
- 格式:修饰符 class 类名<类型>{}, 类型可以写为E、T、K、V等
泛型方法:当方法中形参的类型不确定时:
- 可以使用类名后面定义的泛型
,所有方法适用 - 也可以在方法声明上定义自己的泛型,只有本法能用
- 格式 修饰符<类型> 返回值类型 方法名(类型变量名){},
- 如public static
void show(){};
- 可以使用类名后面定义的泛型
泛型接口
- 格式: 修饰符 interface 接口名<类型> {},如public interface List
{} - 使用方式
- 实现类给出具体类型: public class 类名 implements 接口名<具体类型>{}
- 实现类延续泛型,创建对象时再确定:格式如下:
1
2public class 类名<类型> implements 接口名<类型>{}
类名<具体类型> = new 类名<具体类型>();
- 格式: 修饰符 interface 接口名<类型> {},如public interface List
泛型的继承和统配符:
- 泛型不具备继承性,但是数据具备继承性
- 泛型通配符?:可以在传参不确定时,限制泛型可接受的参数类型
- ?extends E:表示可以传递E或者E所有子类类型
- ? super E: 表示可以传递E或者E所有的父类类型
Set
- Set系列特点:
- 无序:存取顺序不一致
- 不重复:可以去除重复
- 无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素
- 实现类特点:
- HashSet: 无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:可排序、不重复、无索引
- Set接口中的方法基本上与Collection的API一致
- add
- clear
- remove
- contains
- isEmpty
- size
- set的读取:lambda表达式、 iterator、增强for循环
- HashSet
- 底层原理:底层采用哈希表存储数据,哈希表
- 哈希表:对于增删改查性能都比较好
- 在JDK8之前,以数组+链表构造;
- 在JDK8及之后,以数组+链表+红黑树构造;
- 哈希值:对象的整数表示形式
- 根据hashCode方法算出来的int类型的整数
- 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
- 一般情况下会重写hashCode和equals方法,利用对象内部的属性值计算哈希
- 对象的哈希值特点:
- 如果没有重写HashCode方法,不同对象计算出来的哈希值是不同的
- 如果已经重写HashCode方法,不同对象只要属性值相同,计算出来的哈希值是一样的
- 在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一致(哈希碰撞)
- LinkedHashSet:有序、不重复、无索引
- 有序指的是保证存储和去除的元素顺序一致。
- 除了底层哈希表,每个元素又额外多了一个双链表机制(记录上节点和下一个节点的地址),来记录存储的顺序。
- TreeSet:不重复,无索引,可排序
- 可排序
- 对于数值类型,如Integer、Double,按照元素的默认规则(从小到大)排序
- 对于字符、字符串类型:按照字符在ASCII码表中的数字升序进行排序
- 对于自定义对象类型,有两种排序方式
- 自定义JavaBean类实现Comparable接口,实现compareTo方法
- 比较器排序,在创建TreeSet对象时,传递比较器Comparator指定规则
- 底层是基于红黑树的数据结构
- 可排序
本文链接: https://blog.yd0ng.top/2025/03/19/JAVA%E5%9F%BA%E7%A1%80%E7%AC%94%E8%AE%B0-%E4%B8%8A/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!