Java 笔记
简介
- 跟着b站大学https://www.bilibili.com/video/BV1T7411m7Ta学习java的读书笔记
- 使用的是
Java 8
Java语言开发环境的搭建
Java虚拟机——JVM
JVM(java Virtual Machine) : Java虚拟机, 是运行所有Java程序的假想计算机, 是Java程序的运行环境, 是Java最具吸引力的特性之一, 我们编写的Java代码, 都运在
JVM
之上跨平台:任何软件的运行, 都必须要运行在操作系统之上, 而我们用Java编写的软件可以在任何的操作系统上, 这个特性称为Java语言的跨平台性, 该特性是由JVM实现的, 我们编写的程序运行在JVM上, 而JVM运行在操作系统上
如图, java的虚拟机本身不具备跨平台功能的, 每个操作系统下都由不同版本的虚拟机
JRE 和 JDK
JRE
(Java Runtime Environmen)
: 是Java程序的运行时环境, 包含JVM
和运行时所需要的核心类库
JDK(
Java Development Kit
): 是Java程序开发工具包, 包含JRE
和开发人员使用的工具关系
概念
注释
// 单行注释 |
关键字
- 有特殊含义、被保留的、不能随意使用的字符
常量
在程序运行的过程中不会改变的量
- 字符串常量,
" "
双引号引起来的部分, 例如"abd"、 "Hello"、“123”
- 整数常量, 例如:
100, 200, 0, -250
- 浮点数常量, 例如:
2.5, -3.14
- 字符串常量, 例如:
'A', ’b‘, '9', '中'
- Java中的一个char类型标识一个utf-16编码的代码单元, 也就是两个字节, 因此, 不像C语言中文无法代表一个字符
- char真实的含义是描述了UTF-16编码中的一个代码单元, 而不是一个字符
- 布尔常量,
true, false
- 空常量,
null
, 代表没有任何数据
数据类型
基本数据类型
- 整数型:
byte
short
int
long
- 浮点型:
float
double
- 浮点型可能只是一个近似值, 并非精确值, 例如
1/3
是无法精确表示的
- 浮点型可能只是一个近似值, 并非精确值, 例如
- 字符型:
char
- 布尔型:
boolean
引用数据类型
- 字符串、数组、类、接口、Lambda
流程控制
这部分和C/C++几乎一样, 我直接跳掉了
方法
定义
参数
:进入方法的数据(可以没有)返回值
: 方法执行后的数据结果(可以没有)修饰符
: 例如public static
返回类型
:对应返回值的类型方法名称
:方法名字, 规则与变量意义, 建议符合驼峰命名法参数类型
:对应参数的类型方法体
:方法需要做的事情, 若干代码return
: (可以没有)- 将返回值返还调用处
- 终止当前方法
修饰符 返回类型 方法名称(参数类型 参数名称, ....) { |
调用流程
重载
- 名字相同, 但参数列表不同的方法
- 用于对类似功能的方法的名称进行复用, 也就是记住一个名称就可以使用类似的功, 例如
println()
就进行了多种类型的重载, 使得我们只需要记住println()
就可以了。
以数字相加为例
public static int sum(int a, int b) { |
注意事项
不能方法嵌套定义
方法定义顺序无所谓
void
方法可以写return
, 也可以不写重载
参数个数不同
参数类型不同
参数的多类型顺序不同
下面例子是允许的
public static int sum(double a, int b) {
return (int)(a + b);
}
public static int sum(int a, double b) {
return (int)(a + b);
}
数组
任何数据类型都可以存放在数组中
动态初始化
int[] array = new int[300]; |
- 初始化默认值:
- 整数类型,
0
- 浮点类型,
0.0
- 字符类型,
\u0000
- 布尔类型,
false
- 引用类型,
null
- 整数类型,
静态初始化
int[] array = new int[] {1, 2, 3}; |
省略格式
int[] arrayA = {10, 20, 30}; |
异常
数组越界异常(ArrayIndexOutOfBoundsException)
public class HelloWorld { |
运行结果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2 |
空指针异常(NullPointerException)
数组必须new初始化才能使用, 如果只是赋值了一个null, 将发生空指针异常:
public class HelloWorld { |
运行结果
Exception in thread "main" java.lang.NullPointerException |
数组长度
获得:
array.length
数组一旦创建, 程序运行期间, 长度不可改变
内存
栈(Stack)
- 存放方法中的局部变量, 超出作用域立即从栈内存中消失
堆(Heap)
- 凡是new出来的东西, 都在堆当中
- 堆内存里面的东西都有一个地址值:16进制
- 堆内的数据都有默认值
方法区(Method Area)
存放.class
相关信息, 包含方法的信息
本地方法栈(Native Method Stack)
与操作系统相关
寄存器(Register)
与CPU相关
面向对象的思想
- 面向过程, 每一步都亲力亲为
- 面向对象, 找一个已有功能帮助实现
举例:
public class HelloWorld { |
类和对象
类
- 类:一组相关属性和行为的集合, 可以看成是一类事物的模板, 使用事物的属性特征和行为特征来描述该类事物。
现实中, 描述一类事物:
- 属性: 就是该事物的状态信息,- 行为: 就是该事物能够做什么
举例: 小猫。
- 属性: 名字、体重、年龄、颜色
- 行为: 走、跑、叫
对象
- 对象: 一类事物的具体体现, 对象是类的一个实例, 必然具备该类事物的属性和行为
举例: 一只小猫
关系
- 类是一类事物的描述, 是抽象的
- 对象是一类事务的实例, 是具体的
- 类是对象的模板, 对象是类的实体
创建和使用
感觉和C++有相通之处
导包, 如果在同一个包内可以不写
import 包名称.类名称 |
成员变量没有进行赋值, 呢么将会有一个默认值, 规则和数组一样
内存结构
一个
两个
局部变量和成员变量
- 局部变量: 随着方法进栈而诞生, 随着方法出栈而消失
- 成员变量:随着对象创建而诞生, 随着对象被垃圾回收而消失
面向对象的三大特性
封装
- 方法就是一种封装
- 关键字
private 私有化
也是一种封装 - 把一些细节信息隐藏, 对外界不可见
继承
- 继承是多态的前提
- 继承类似
师徒关系
:师傅会多少都无偿传授给徒弟 - 继承主要解决的问题是:
共性抽取
, 举个栗子(滑稽保命), 在一个公司里有很多的员工, 员工属性:姓名, 性别。职称等就是他们的共性, 但根据职称的不同, 每个人的计算工资的方法不一样, 因此可以对员工
这个共性进行抽取, 然后对员工
类进行继承, 分别实现各自的计算工资的方法。 - 通俗讲就是可以免去
Ctrl + C/V
的麻烦 - 被继承的类可以叫做
父类
、基类
、超类
- 继承的类可以叫做
子类
、派生类
- 继承的关键字是
extends
举例
// Parent.class |
特点
Java是单继承, 即只能有一个父类
// class one
public class ClassOne {
//
}
// class two
public class ClassTwo {
}
// class three 这样定义是错误的!
public class ClassThree extends ClassOne, ClassTwo {
//
}Java可以多级继承
// Parent.class
public class ParentClass {
// ...
}
// Child.class
public class ChildClass extends ParentClass {
// ...
}
// Grandson class
public class GrandsonClass extends ChildClass{
// ...
}父类可以拥有多个子类
成员变量
- 如果在继承关系中成员变量, 则创建子类对象是, 访问有两种方式
- 直接通过子类对象访问成员变量
- 间接通过成员方法访问成员变量
成员方法
- 就近原则, 谁调用执行谁的成员方法, 没有则向上寻找
重载(Overload)
- 父子类名称相同, 参数列表也相同
重写/覆盖(Override)
父子类名称相同, 参数列表不同
关键字
@Override
:可选, 起检测作用, 只要书写正确无也可覆盖返回值:子类方法返回值必须小于等于父类方法的返回值范围, 例如
Object
是String
的父类, 则父类为String
则子类不可以是Object
, 父类为Object
则子类可以是String
权限: 子类方法权限必须大于等于父类方法的权限修饰符
public > protected > (default) > private
defalut
: 表示什么都不写, 留空
举例
// Parent.class
public class ParentClass {
public Object method() {
// ...
}
}
// Child.class
public class ChildClass extends ParentClass {
public Object method() {
// ...
}
}
多态
- 重写, 继承, 重载都是多态的一种表现形式
this 关键字
当方法的局部变量和类成员变量重名, 根据就近原则
, 优先使用局部变量
如果需要访问本类当中的成员变量, 需要使用格式;
this, 成员变量 |
例子:
”通过谁调用的方法, 谁就是this“
: 用打印地址值来验证
static 关键字
- 感觉跟C++一样, 只写一些自己不懂的
静态代码块
特点:
- 当第一次用到本类, 静态代码块执行唯一的一次
- 且比构造方法先执行!
用途:常用于对静态成员的赋值
public class 类名称 { |
super 关键字
构造方法中
super()
: 访问父类中的无参构造函数super(paras...)
: 访问父类的有参构造函数
非构造方法
super.xxx
: 访问父类中的成员变量super.yyy(paras..)
: 访问父类中的成员函数yyy
this vs super
标准类(Java Bean)
一个标准类中通常有
- 所有成员变量用
private
修饰 - 每一个成员变量都有一对
Getter/Setter
方法 - 一个无参构造
- 一个全参构造
匿名对象
- 只有右边的对象, 没有左边的名字和赋值运算符
- 只能使用一次, 下次使用需重新创建
- 也可以作为方法的参数和返回值
// 正常 |
对象数组
Person array = new Person[3]; |
抽象
如果父类中的方法不确定如何进行某个方法体实现, 那么这应该是一个抽象方法
- 狗吃骨头猫吃鱼, 但动物吃什么没法具体描述, 那么就是一个抽象方法
- 正方形三角形可计算面积, 但是图形怎么计算面积没法具体描述, 那么就是一个抽象方法
定义
定义抽象方法:在返回值前加上abstract
关键字, 然后去掉大括号, 直接分号结束
定义抽象类: 在class
之前加上abstract
关键字
抽象方法必须在抽象类中
使用
- 不能直接
new
抽象类对象, 必须用一个子类来继承抽象父类 - 子类必须覆盖重写抽象父类当中的所有的抽象方法
举例
// Animal.java |
注意
- 抽象类不能创建对象
- 抽象类可以有构造方法, 供子类创建对象时, 初始化父类成员
- 先执行父类构造方法
- 再执行子类构造方法
- 抽象类不一定包含抽象方法, 有抽象方法必然是抽象类
- 抽象类的子类, 必须覆盖重写父类中所有抽象方法, 除非子类也是抽象类
接口
- 一种公共的规范, 只要符合标准就可以大家通用
- 引用数据类型, 最重要的内容就是其中的抽象方法
定义
public interface 接口名称 { |
可包含内容
- Java7
- 常量
- 抽象方法
- Java8, 额外包含
- 默认方法
- 静态方法
- Java9, 额外包含
- 私有方法
抽象方法
注意事项
- 接口中的抽象方法修饰符必须是:
public abstract
- 这两个关键字可以选择性的省略
- 方法的三要素可以随意定义
定义举例
public interface MyInterface { |
使用
接口不能直接使用, 必须要有一个实体类来实现接口
实现类必须覆盖重写接口中的抽象方法, 否则必须为抽象类
创建实现类的对象, 进行使用
public class 类名 implements 接口名称 {
// ....
}
使用举例
public class MyInterfaceImpl implements MyInterface { |
默认方法
从java8开始允许在接口中定义默认方法
- 解决接口升级问题
定义格式
public default 返回值类型 方法名称(参数列表) { |
注意事项
- 接口的默认方法会被实现类继承
- 接口的默认方法可以被覆盖重写
静态方法
从java8开始允许在接口中定义静态方法
定义格式
public static 返回类型 方法名称(参数列表) { |
成员变量
- 必须使用public static final三个关键字修饰(可省略, 默认)
- 其实就是接口的常量, 一旦赋值不可更改
- 必须进行赋值
- 成员变量名建议使用大写字母, 符合命名规范
public static final 成员变量名 = 值; |
注意事项
接口没有静态代码块或构造方法
一个类的直接父类是唯一的, 但一个类可以实现多个接口
public class 实现类名 implements 接口1, 接口2 {
// 覆写所有抽象方法
}如果实现类所实现的多个接口当中, 存在重复接口, 只用覆写一次
如果实现类没有覆盖重写所有接口当中的所有抽象方法, 那么实现类就必须是一个抽象类
如果实现类所实现的多个接口当中, 存在重复的默认方法, 那么实现类一定要对冲突的默认方法进行覆写
一个类如果直接父类当中的方法, 和接口当中的默认方法产生了冲突, 优先用父类当中的方法
API
API
(Application Programming Interface)
Java API 文档
Scanner
一个可以解析基本类型和字符串的简单文本扫描器
例如, 以下代码使得用户可以从System.in
中读取一个数
import java.util.Scanner; // 1.导包 |
练习
计算输入的两数字和
Scanner sc = new Scanner(System.in); |
Random
生成随机数
// 导包 |
ArrayList
java.util.ArrayList;
ArrayList<E>
<E>
称为泛型, 也就是装在集合当中的所有元素都是统一类型泛型只能是引用类型, 不能是基本类型
ArrayList集合的长度可以随意改变
对于ArrayList集合来说, 直接打印得到的不是地址值, 而是内容
如果内容为空, 得到的是空的中括号:
[]
// 创建了一个ArrayList聚合, 集合的名称list, 里面装的全都是String字符串类型的数据 |
常用方法
- 不常用可以查询API文档
public boolean add(E e)
: 向集合当中添加元素, 参数的类型和泛型一致- 对于
ArrayList
集合来说, add添加动作一定是成功的, 所以返回值可用可不用, 但是对于其他集合来说, add动作不一定成功
- 对于
public E get(int index)
:从集合当中获取元素, 参数是索引编号, 返回值就是对应位置的元素public E remove(int index)
: 从集合当中删除元素, 参数是索引编号, 返回值就是删除掉的元素public int size()
: 获取集合的尺寸长度, 返回值为集合中包含的元素个数
ArrayList<String> list = new ArrayList<>(); |
存储基本类型
- 如果要存储基本类型, 必须使用基本类型对应的
包装类
(引用数据类型, 包装类都位于java.lang下)
基本类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
从JDK 1.5+开始, 支持自动装箱, 自动拆箱
- 自动装箱: 基本类型 –> 包装类
- 自动拆箱:包装类–> 基本类型
使用(以
Integer
为例)ArrayList<Integer> listInt = new ArrayList<>();
listInt.add(100);
int num = listInt.get(0);
String
java.lang.String
- 程序中所有的双引号字符串全是String类的对象
- 字符串内的内容不可改变
- 字符串可以共享
- 效果上相当于char[]字符数组, 但底层原理是byte[]字节数组【在
JDK 1.8
也就是Java 8
中看到的其实是char[]
字符数组,Java 9
中对其进行了优化, 使用了byte[]
字节数组来节省空间(如使用字母时char需要两个字节, 而byte只需要一个字节)】
Ctrl + Alt
点击String
查看定义:
public final class String |
创建字符串
public String()
: 创建一个空白字符串, 不含有任何内容public String(char[] array)
: 根据字符数组的内容, 来创建对应的字符串public String(byte[] array)
: 根据字节数组的内容, 来创建对应的字符串String str = "xxxx"
:直接创建, 也是对象
String str = new String(); |
字符串的常量池
程序当中直接写上双引号的字符串, 就在字符串常量池中
String str1 = "abc"; |
运行结果:
true |
- 对于基本类型来说,
==
是【数值】比较 - 对于引用类型来说,
==
是【地址值】的比较
- 对于
""
双引号直接括起来的字符串, 在常量池当中 - 读于
new
出来的字符串, 不在常量池中
常用方法
字符比较
public boolean equals(Object obj)
: 参数可以是任何对象, 只有参数是一个字符串并内容相同的才会给true
任何对象都可以用
Object
进行接受具有对称性
a.equals(b)
和b.equlas(a)
效果相同如果比较双方一个常量一个变量, 推荐把
常量
字符写在前面
推荐:
"abc".equals(str)
不推荐:
str.equals("abc")
理由
String str = null;
System.out.println("abc".equals(str)); // false
System.out.println(str.equals("abc")); // 报错:空指针异常 NullPointerException
public boolean equalsIgnoreCase(String str)
: 参数是字符串, 忽略大小写判断
使用
String str1 = "Hello"; |
运行结果:
true |
字符获取
public int length()
: 获取字符串当中含有的字符个数, 拿到字符串长度public String concat(String str)
: 将当前字符串和参数字符串拼接成为返回值(新的字符串)public char charAt(int index)
: 获取指定索引位置的单个字符(从0开始)public int indexOf(String str)
: 查找参数字符串在本字符串当中首次出现的索引位置
字符串截取
public String subtring(int index)
: 截取从参数位置一直到字符串末尾, 返回新字符串public String substring(int begin, int end)
: 截取从begin开始, 一直到end结束, 中间的字符串。 备注:[begin, end)
, 包含左边, 不含右边
字符串转换
public char[] toCharArray()
: 将当前字符串拆分成为字符数组作为返回值public byte[] getBytes()
:获取当前字符串底层的字节数组public String replace(CharSequence oldString, CharSequence newString)
: 将所有出现的老字符串替换为新的字符串, 返回替换之后的新字符串
字符串切割
public String[] split(String regex)
: 根据regex的规则, 将字符串切分成若干部分(由于,
用于切分因此生成的字符串数组中的字符串不包含,
)- 实际上,
split
方法的参数其实是正则表达式, 因此当我们string.split('.')
时并不会用.
进行切割, 因为.
在正则中有特殊的含义, 因此我们必须写string.split('\\.')
, 用\\
来转义
Arrays
java.util.Arrays
: 一个与数组相关的工具类, 里面提供了大量的静态方法, 用来实现数组的常见操作public static String toString(数组)
:将参数数组变成字符串public static void sort(数组)
: 按默认升序(从小到大)对数组元素进行排序- 如果时数值, sort默认按照默认升序(从小到大)对数组元素进行排序
- 如果时字符串, 按字母升序排序
- 如果时自定义类型, 则必须要有
Comparrable
或者Comparator
接口的支持
Math
java.util.Math
: 数学工具类, 提供了大量静态方法, 完成于数学运算相关的操作public static double abs(double num)
: 获取绝对值public static double ceil(double num)
: 向上取整public static double floor(double num)
: 向下取整public static long round(double num)
: 四舍五入Math.PI
:近似圆周率
Java项目结构
IDEA
iml
: 配置文件src
: 代码External Libraries
: JDK的文件psvm
一键生成public static void main(String[] args)
sout
一键生成System.out.println();
Alt + Insert
一键生成Getter/Setter
方法