2023年java学习笔记
Java基础语法
数据类型
基本数据类型:
若需要一整型字面量默认是long型,可在后面加上L / l;
若需要一小数字面量默认是float型,可在后面加上F / f;
类型转换
自动类型转换
自动类型转换的其他形式:
byte --> short or char --> int --> long --> float -->double
表达式的自动类型转换
1.表达式的最终表达结果类型由表达式中的最高类型决定;
2.在表达式中,byte、short、char 是直接转换int类型参与运算的。
强制类型转换
注意类型范围大的数据或变量,直接赋值给类型范围小的变量会报错。
package com.it.hello;
public class HelloWorld {
public static void main(String[] args) {
System.out.println((char)('a'+10));
}
}
注意事项:
强制类型转换可能造成数据(丢失)溢出;
浮点型强转成整型,丢失小数部分,保留整数部分返回。
运算符
基本的算数运算符
package com.it.hello;
public class HelloWorld {
public static void main(String[] args) {
System.out.println(10 % 3); // 1
System.out.println(10 / 3); // 3
}
}
“+”符号作连接符:“+”符号与字符串运算时作连接符,其结果仍然是一个字符串。
自增自减运算符
注意++,--只能操作变量,不能操作字面量。
package com.it.hello;
public class HelloWorld {
public static void main(String[] args) {
int a = 5;
System.out.println(++a); //先执行a+1,再输出新的a
System.out.println(a++); //输出a,再执行a+1
}
}
赋值运算符
package com.it.hello;
public class HelloWorld {
public static void main(String[] args) {
int a = 5;// 从右往左看,把数据5赋给变量a储存
}
}
注意:拓展的赋值预算符隐含了强制类型转换
关系运算符
用于判断数据是否满足条件,最终返回一个判断的结果,返回值的类型是布尔值:true或false。
逻辑运算符
在java中,"&"、"|",无论左边是true还是false,右边都执行
&& 和 || 效率更高
三元运算符、运算符的优先级
" * "、"/"的优先级高于"+"、"-"
&&优先级高于 ||
package com.it.hello;
public class HelloWorld {
public static void main(String[] args) {
int a = 3,b = 5;
System.out.println(10>3 || 10 > 3 && 10 < 3);// true
}
}
"( )"优先级最高
Scanner接收键盘输入数据
package com.it.hello;
import java.util.Scanner;
public class HelloWorld {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 调用sc的功能,来接收用户从键盘输入的数据
int age = sc.nextInt();// 执行到这,会开始等待用户输入一个整数,直到用户输入换行(回车),才会拿到数据
System.out.println(age);
}
}
流程控制
分支结构
if
根据条件(真或假)来执行某段代码。
若不满足条件1,判断条件2,向下依次判断条件,如果都不满足,执行else部分代码。
if语句中常见问题:
1.if(条件)后不能跟" ; ",否则{ }中的代码不受if控制。
2.如果if中语句中只有一行代码,{ }可以省略不写。(不推荐省略)
switch
switch(表达式){
case值1:
执行代码...;
break;
case值2:
执行代码...;
break;
...
...
case值n:
执行代码...;
break;
default:
执行代码...;
}
if与switch比较:
1.if在功能上强于switch
2.当前条件是区间时,应该使用if分支结构
3.当条件是一个一个值比较时,switch分支结构更好:格式良好,性能较高,代码优雅
利用switch的穿透性,在某些情况下可以简化代码:当存在多个分支的代码相同时,可以把相同的代码放到一个case块中,其他的case块都通过穿透性穿透到该case块执行代码即可,这样可以简化代码
循环结构
for循环
//输出3次Hello World
for(int i = 0 ; i < 3 ; i++){
System.out.println("Hello World")
}
执行流程:
while循环
//打印3次Hello World
int i = 0;
while(i < 3){
System.out.println("Hello World");
i++;
}
执行流程:
知道循环几次使用for,不知道循环几次建议用while。
do-while循环
do-while执行特点:
先执行后判断
死循环
for( ; ; ){
System.out.println("Hello World1");
}
//经典写法
while(true){
System.out.println("Hello World2");
}
do(
System.out.println("Hello World3");
}while(true)
可以一直执行下去的循环,如果没有干预不会停止执行.
循环嵌套
循环中又包含循环
//输入15次Hello World
for(int i = 0 ; i < 5 ; i ++){
for(int j = 0 ; j < 3 ; j++){
System.out.println("Hello World");
}
}
跳转关键字:break,continue
Random的使用
import java.util.Random;
public class HelloWorld {
public static void main(String[] args) {
//创建一个random对象,用于生成随机数
Random r = new Random();
//调用Random提供的功能nextInt得到随机数
int data = r.nextInt(10);// 0-9
System.out.println(data);
}
}
数组
静态初始化数组
数组的访问
数组的遍历
遍历就是一个一个数据的访问
//遍历ages
int ages[] = {15,18,20};
int Length = ages.length;
for(int i = 0 ; i < Length ; i++){
System.out.println(ages[i]);
}
动态初始化数组


方法
方法的其他形式
Java的参数传递机制
基本类型的参数传递
引用类型的参数传递
面向对象编程基础
开发一个一个的对象,把数据传输给对象,再调用对象的方法完成对数据的处理。
package com.it.object;
public class Test {
public static void main(String[] args) {
Student s1 = new Student();
s1.name = "小虎";
s1.Chinese = 100;
s1.Math = 130;
s1.PrintTotalScore();
}
}
package com.it.object;
public class Student {
String name;
double Chinese;
double Math;
public void PrintTotalScore(){
System.out.println(name + "各科的总分是:" + (Chinese + Math));
}
}
认识面向对象
1.面向对象编程符合人类思维,编程更简单,更直观
2.对象本质上是一种特殊的数据结构
3.class也就是类,也称为对象的设计图(或对象的模板)。
类和对象的一些注意事项
this
this就是一个变量,可以用在方法中,来拿到当前对象。
package com.it.object;
public class Student {
public void PrintThis(){
System.out.println(this);
}
}
package com.it.object;
public class Test {
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1);
s1.PrintThis();
}
}
输出结果:
this主要用来解决变量冲突问题
构造器
创建对象时,对象会去调用构造器
public class Student {
//无参数构造器
public Student(){
}
//有参数构造器
public Student(String name){
}
}
构造器的常见应用场景
创建对象时,同时完成对对象成员变量(属性)的初始化赋值
package com.it.object;
public class Student {
String name;
double score;
public Student(String name,double score){
this.name = name;
this.score = score;
}
}
package com.it.object;
public class Test {
public static void main(String[] args) {
Student s1 = new Student("小虎",100);
System.out.println(s1.name);// 小虎
System.out.println(s1.score);// 100
}
}
构造器的注意事项
封装
什么是封装?
封装就是用类设计对象处理某一个事物的数据是,应该把要处理的数据,以及处理这些数据的方法,设计到一个对象中去
封装的设计规范:合理隐藏,合理暴露
public class test {
String name;// 都可访问
private double score; //私有访问
}
实体javaBean(实体类)
什么是实体类?
实体类就是一种特殊类
1.这个类中的成员变量都要私有,并且要对外提供相应的getxxx,setxxx方法
public class test{
private double number;// 私有数据
public void SetNumber(double temp){
this.number = temp;
}
public double GetNumber(){
return this.number;
}
}
2.类中必须有一个公共的无参的构造器
实体类应用场景
常用API
API全称Application Programming Interface(应用程序接口)
就是调用别人写好的程序来解决问题
String
调用java.lang.String
String使用时的注意事项
1.String对象的内容不可改变,被称为不可改变字符串对象
每次试图改变字符串对象实际上是产生了新的字符串对象,变量每次都是指向了新的字符串对象,之前字符串的内容始终没有改变,因此称String的对象是不可变的
2.只要是以”...."方式写出的字符串对象,会存储到字符串常量池,且相同内容的字符串只存储一份。但通过new方式创建字符串对象,每new一次都会产生一个新的对象放在堆内存中。
ArrayList
ArrayList代表一种集合。
集合是一种容器,用来存储数据,类似于数组。不同于数组,数组定义完成并启动后,长度固定,而集合大小可变。
面向对象高级
Static
Static修饰成员变量
static叫静态,可以修饰成员变量、成员方法。
成员变量按照有static修饰分为两种:
类变量(静态成员变量):有static修饰,属于类,在计算机中只有一份,会被类的全部对象共享
实例变量(对象的变量):无static修饰,属于每个对象
package com.it.object;
public class Student {
static String name;
}
package com.it.object;
public class Test {
public static void main(String[] args) {
Student.name = "Tim";
Student s1 = new Student();
s1.name = "Tom";
Student s2 = new Student();
s2.name = "TimTom";
System.out.println(s1.name); // TimTom
}
}
Static修饰成员方法
类方法:有static修饰的成员方法,属于类
实例方法:无static修饰的成员方法,属于对象
Static的注意事项
代码块
单例设计模式
单例设计模式:确保一个类只有一个对象
写法:
1.把类的构造器私有
2.定义一个类变量记住类的一个对象
3.定义一个类对象,返回对象
package com.it.object;
public class Student {
//定义一个类变量记住类的一个对象
private static Student Stu = new Student();
//必须私有类的构造器
private Student(){
}
//定义一个类方法返回类的对象
public static Student GetObject(){
return Stu;
}
}
继承
继承相关的注意事项
权限修饰符
权限修饰符就是用来限制类中的成员(成员变量、成员方法、构造器、代码块)能够被访问的范围。
单继承、Object
Java是单继承的,Java中的类不支持多继承,但是支持多层继承。
Object类是java所有类的祖宗类,我们写的任意一个类,实际上是object的子类或子孙类
方法重写
子类根据需求重写一个方法名称、参数列表一样的方法,去覆盖父类的方法,这就是方法重写
注意:重写后,方法的访问,java会遵循自动原则
方法重写的注意事项:
- 使用Override注解,可以指定java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好。
- 子类重写父类方法时,访问权限必须大于后者等于父类该方法的权限(public > protected > 缺省)
- 重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小
- 私有方法、静态方法不能被重写
子类访问其他成员的特点
子类访问其他成员(成员变量、成员方法),是遵循就近原则的
- 先子类局部范围找
- 然后子类成员范围找
- 然后父类范围找,如果父类没找到则报错
如果子父类中,出现重名的成员,会优先使用子类如果需要使用父类可以通过super关键字指定访问父类的成员:super.父类成员变量/成员方法
子类构造器的特点
子类的全部构造器,都会先调用父类的构造器,再执行自己。
子类构造器是如何实现调用父类构造器的:
- 默认情况下,子类全部构造器的第一行代码都是super()(写不写都有),它会调用父类的无参数构造器
- 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(...),指定去调用父类的有参数构造器
补充:this(...)调用兄弟构造器:
任意类的构造器中,是可以通过this(...)去调用该类的其他构造器的
面向对象的三大特征之三:多态
认识多态
多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态
使用多态的好处
- 在多态形式下,右边对象是解耦合的,更便于拓展和维护
- 定义方法时,使用父类类型的形参,可以接受一切子类对象,拓展性更强,更便利
多态下的类型转换问题
- 自动类型转换:父类 变量名 = new 子类();
- 强制类型钻换:子类 变量名 = (子类) 父类变量
注意事项:
- 存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错
- 运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换一场(ClassCastException)的错误出来。
强转前使用instanceof关键字,判断当前对象的真实类型,再进行强转
p1 instanceof Test //返回True或False
final
认识final
final关键字是最终的意思,可以修饰(类,方法,变量)
- 修饰类:该类称为最终类,不能被继承了
- 修饰方法:该方法称为最终方法,特点是不能被重写了
- 修饰变量:该变量只能被赋值一次
final修饰变量的注意:
- final修饰基本类型的变量,变量存储的数据不能改变
- final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向的内容是可以被改变的
常量详解:
使用了static final修饰的成员变量就称为常量
作用:通常用于记录系统的配置信息
public static final String TEST_NAME = "This is a test"
常量名命名规范:使用大写英文单词,多个单词使用下划线连接
使用常量记录系统配置信息的优势、执行原理:
- 代码可读性更好,可维护性也更好
- 程序编译后,变量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和使用字面量的性能是一样的
抽象类
认识抽象类
abstract关键字(抽象),可以修饰类、成员方法
abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法
抽象类的注意事项、特点:
- 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
- 类该有的成员(成员变量、方法、构造器)抽象类都可以有
- 抽象类最主要特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现
- 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义为抽象类
抽象类的好处
- 父类知道每个子类都要做某个行为,但每个子类做的情况不一样,父类就定义抽象方法,交给子类去重写实现,这样就是为了更好的支持多态
抽象类常见应用场景:模板方法设计模式
模板方法设计模式解决方法中存在重复代码的问题
接口
JAVA提供一个关键字interface,用这个关键字我们可以定义一个特殊的结构:接口
public interface 接口名{
//成员变量 (常量)
//成员方法 (抽象方法)
}
接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类
一个类可以实现多个接口,实现类实现多个接口,必须全部重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类
接口的好处
- 弥补了类单继承的不足,一个类同时可以实现多个接口
- 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现
package com.it.hello;
public class test {
public static void main(String[] args) {
Singer s =new A();
}
}
class A extends Student implements Drivers, Singer{
@Override
public void drive() {
}
@Override
public void sing() {
}
}
class Student{
}
interface Drivers{
void drive();
}
interface Singer{
void sing();
}
一个接口可以继承多个接口
注意事项:
- 一个接口继承多个接口,如果多个接口中存在签名冲突,则此时不支持多继承
- 一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现
- 一个类继承了父类,有同时实现了接口,父类和接口中有同名的默认方法,实现类会优先用父类的
- 一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可
interface I{
void test1();
}
interface J{
String test1();
}
//一个接口继承多个接口,如果多个接口中存在签名冲突,则此时不支持多继承
interface K extends I,J{
//
}
一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现
class E implements I,J{
//
}
内部类
内部类是类的五大成员之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类
使用场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类
内部类四种形式:成员内部类、静态内部类、局部内部类、匿名内部类
成员内部类:
Outer.Inner in = new Outer.new Inner();
成员内部类可以访问外部类的实例成员、静态成员
静态内部类
又static修饰的内部类,属于外部类自己持有
可以直接访问外部类的静态成员,不可以访问外部类实例成员
匿名内部类
是一种特殊的局部内部类;所谓匿名,指的是程序员不需要为这个类命名
new 类或接口(参数值...){
类体(一般是方法重写);
};
public class test {
public static void main(String[] args) {
Animal a = new Animal(){
@Override
public void cry() {
System.out.println("喵喵喵");
}
};
a.cry();
}
}
abstract class Animal{
public abstract void cry();
}
特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象
作用:用于更方便的创建一个子类对象
匿名对象类通常作为一个参数传输方法
枚举
枚举是一种特殊类。
枚举类的格式:
修饰符 enum 枚举类名{
名称1,名称2,...;
其他成员...
}
public enum A{
X , Y , Z;
...
}
注意:
- 枚举类的第一行,只能写一些合法的标识符,多个名称用逗号隔开
- 这些名称,本质上是常量,每个常量都会记住枚举类的一个对象
- 枚举类的构造器都是私有的,因此枚举类对外不能创造对象
- 枚举都是最终类,不可以被继承
- 枚举类中,从第二行开始,可以定义类的其他成员
枚举的常见应用场景:
用来表示一组信息,然后作为参数进行传输
泛型
定义类、接口、方法时,同时声明了一个或者多个类型变量(如:<E>),称为泛型类、泛型接口、泛型方法,他们统称为泛型
ArrayList<String> list1 = new ArrayList<>();
作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动检查的能力!这样可以避免强制类型转换,及其可能出现的异常
泛型的本质:把具体的数据类型作为参数类传递给类型变量
泛型类
修饰符 class 类名<类型变量,类型变量,...>{
}
public class Arraylist<E>{
...
}
泛型接口
public interface A<E>{
...
}
泛型方法
泛型的擦除问题和注意事项
- 泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除
- 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)
常用API
Object
Object类是Java所有类的祖宗类,因此Java的所有对象一直接使用Object类提供的一些方法
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
包装类

StringBuilder
StringBuilder代表可变字符串对象,相当是一个容器,他里面装的字符串是可以改变的,就是用来操作字符串的。
好处:StringBuilder比String更适合做字符串的修改操作,效率更高,代码更简洁
StringBuffer与StringBuilder
StringBuffer与StingBuilder用法相同,但StringBuffer是线程不安全的,StringBuffer是线程安全的
StringJoiner
Math
System
System代表程序所在的系统,也就是一个工具类
Runtime
代表程序所在的运行环境,Runtime是一个单例类
BigDecimal
BigDecimal
Date
SimpleDateFormat
JDK8新增时间
Arrays
用来操作数组的一个工具类
Lambda表达式
Lambda是JDK8以后新增的语法形式,用于简化匿名内部类写法
方法引用
静态方法的引用
正则表达式
public class Main {
public static void main(String[] args) {
System.out.println(checkQQ("123124124"));
}
public static boolean checkQQ(String qq){
//1.判断qq是否为空或非法
if(qq == null || qq.startsWith("0") || qq.length() <6 || qq.length() > 20){
return false;
}
//2.判断qq号码是否都为数字
for (int i = 0; i < qq.length(); i++) {
//根据索引提取当前位置处的字符
char ch = qq.charAt(i);
//判断ch记住的字符,如果不是数字,qq号码不合法
if(ch < '0' || ch > '9'){
return false;
}
}
//qq号码合法
return true;
}
}
使用String的matches方法
public class Main {
public static void main(String[] args) {
System.out.println(checkQQ("123124124"));
}
public static boolean checkQQ(String qq) {
return qq != null && qq.matches( "[1-9]\\d{5,20}");
}
}
书写规则
string提供了一个匹配正则表达式的方法
public boolean matches(String regex) //判断字符串是否匹配正则表达式,匹配返回true,不匹配返回false
代码演示:
public class Main {
public static void main(String[] args) {
System.out.println("a".matches("[abc]")); //[abc]只能匹配abc
System.out.println("e".matches("[^abc]")); // [^abc]不能是abc
System.out.println("b".matches("[a-zA-Z]")); // [a-zA-Z] 只能是a-z A-Z的字符
System.out.println("a".matches("[a-z&&[^bc]]"));// a到z,除了b和c
//以上只能匹配单字符
//2.预定义字符(只能匹配单个字符)
/*
\d 任意字符
\s表示一个空白字符
\S代表一个非空白字符
\w : [a-zA-Z_0-9]
\W : 不能是a-zA-Z_0-9
*/
//-------------------------------------
//3.数量词
/*
? 代表0次或1次
* 代表0次或多次
+ 代表1次或多次
{n} 代表正好是n次
{3,} 代表>=3次
{3,9} 代表大于等于3次,小于等于9次
*/
System.out.println("abc123ll".matches("\\w{3,9}"));
//4.其他几个常用符号: (?i)忽略大小写 或: | 分组:()
System.out.println("aBc".matches("a((?i)b)c"));
}
}
异常
认识异常
异常就是程序出现的问题
自定义异常
import com.sun.tools.attach.AgentInitializationException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
public class Main {
public static void main(String[] args){
try {
savaAge(160);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void savaAge(int age){
if(age > 0 && age <150){
System.out.println("succeed");
}
else{
throw new AgeIllegalRuntimeException("Age is illegal");
}
}
}
public class AgeIllegalRuntimeException extends RuntimeException {
public AgeIllegalRuntimeException(){
}
public AgeIllegalRuntimeException(String message) {
super(message);
}
}
异常的处理方式
集合进阶
Collection的常用方法
Collection的遍历方式
迭代器
Lambda表达式遍历集合
List集合
特点、特有方法
List集合特点:有序、可重复、有索引
- ArrayList:有序、可重复、有索引
- LinkedList:有序、可重复、有索引
遍历方式
LinkList
数据进入栈模型的过程称为:压/进栈(push)
数据离开栈模型的过程称为:弹/出栈(pop)