Java开发基本语法笔记其一


知识库,有时间更新…

JVM内存划分

方法区(Method Area):
方法区用于存储类的结构信息、静态变量、常量、编译器编译后的代码等数据。在JDK 8及之前的版本中,方法区是一块逻辑上的内存区域,通常被实现为永久代(Permanent Generation)。从JDK 8开始,方法区被元数据区(Metaspace)所取代。

堆(Heap):
堆是JVM中最大的一块内存区域,用于存储对象实例和数组。堆可以动态地分配和释放内存,是垃圾收集器主要管理的区域。堆被所有线程共享,是Java程序中创建对象实例的主要区域。

虚拟机栈(VM Stack):
每个线程在创建时都会被分配一个私有的虚拟机栈,用于存储线程的方法调用、局部变量、操作数栈等信息。虚拟机栈包括栈帧(Stack Frame),每个方法的执行对应着一个栈帧的入栈和出栈过程。

本地方法栈(Native Method Stack):
本地方法栈与虚拟机栈类似,不同之处在于本地方法栈用于执行本地(Native)方法,而虚拟机栈用于执行Java方法。本地方法栈也是线程私有的,与虚拟机栈一样,本地方法栈也会抛出StackOverflowErrorOutOfMemoryError异常。

程序计数器(Program Counter Register):
程序计数器是当前线程执行的字节码行号指示器。每个线程都有自己的程序计数器,用于记录当前线程正在执行的字节码指令地址。在多线程环境下,程序计数器是线程私有的。

抽象

抽象方法

抽象方法是在抽象类中声明的方法,没有方法体,只有方法签名。
抽象方法不包含方法体的原因是让子类去实现具体的逻辑,强制子类对其进行实现。
子类继承抽象类后,必须实现父类中的所有抽象方法,否则子类也必须声明为抽象类。
示例:
public abstract class Animal {
    public abstract void makeSound();
}

public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof");
    }
}

抽象类

抽象类是用abstract关键字声明的类,它不能被实例化,只能作为其他类的父类,用于被继承。
抽象类可以包含普通的方法实现,也可以包含抽象方法(没有方法体,只有方法声明),子类必须实现这些抽象方法。
如果一个类包含抽象方法,那么该类必须声明为抽象类。
抽象类的目的是为了提供一个模板或者规范,让子类来实现具体的行为。
示例:
public abstract class Shape {
    public abstract double calculateArea();
}

public class Circle extends Shape {
    private double radius;

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

注意事项

无法实例化抽象类:
抽象类不能被实例化,只能用作父类被其他类继承。如果试图实例化抽象类,会导致编译错误。

子类必须实现抽象方法:
子类继承抽象类后,必须实现父类中的所有抽象方法,否则子类也必须声明为抽象类。未实现抽象方法的子类仍然是一个抽象类。

抽象方法不能有方法体:
抽象方法只有方法声明,没有方法体。它们存在的目的是为了让子类去实现具体的逻辑。

抽象类可以包含普通方法:
抽象类中除了抽象方法外,还可以包含普通的方法实现。子类继承抽象类时,可以选择性地覆盖这些方法。

抽象类可以不包含抽象方法:
抽象类并不一定要包含抽象方法,它可以只作为一个普通类,提供一些通用的方法实现。

抽象类不能和final关键字一起使用:
抽象类和final关键字是冲突的,因为final修饰的类不能被继承,而抽象类需要被继承才能被实例化。

抽象类可以有构造函数:
抽象类可以有构造函数,用于初始化抽象类的成员变量。子类在实例化时会调用父类的构造函数。

抽象类的抽象方法可以被静态方法或私有方法调用:
抽象类中的抽象方法可以被静态方法或私有方法调用,但子类必须实现这些抽象方法。

设计模式

设计模式是一种解决方案(解决开发中的某种问题方案)23种
设计模式可以分为以下几个类别:

创建型模式(Creational Patterns):
创建型模式关注对象的创建机制,包括构造函数和对象的创建方式。常见的创建型模式有单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式等。

结构型模式(Structural Patterns):
结构型模式关注对象和类之间的组合,以形成更大的结构。常见的结构型模式有适配器模式、装饰器模式、代理模式、组合模式、桥接模式和享元模式等。

行为型模式(Behavioral Patterns):
行为型模式关注对象之间的通信和协作方式,以及算法的分配和责任的划分。常见的行为型模式有观察者模式、策略模式、模板方法模式、迭代器模式、命令模式、状态模式和访问者模式等。

并发型模式(Concurrency Patterns):
并发型模式关注多线程环境下的任务调度和协作方式,以解决并发编程中的问题。常见的并发型模式有生产者消费者模式、读写锁模式、线程池模式和信号量模式等。

其他模式:
还有一些其他类型的设计模式,如架构模式、企业模式和领域模式等,它们是对特定领域或特定问题的解决方案。

模板设计模式

确定的方法提前写,不确定的方法定义为抽象类

模板设计模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法的框架,将算法的具体步骤延迟到子类中实现。该模式在一个方法中定义了一个算法的骨架,而将一些步骤的实现延迟到子类中。

结构
在模板设计模式中,通常包含以下角色:

抽象类(Abstract Class):
抽象类定义了一个模板方法(Template Method),其中包含了算法的骨架,但某些步骤会由子类来实现。抽象类也可以包含一些具体的方法,这些方法可以被模板方法调用。

具体子类(Concrete Subclass):
具体子类继承自抽象类,并实现了抽象类中定义的抽象方法,完成了算法的特定步骤。

示例
下面是一个简单的示例来说明模板设计模式:
// 抽象类
abstract class AbstractClass {
    public void templateMethod() {
        stepOne();
        stepTwo();
    }

    abstract void stepOne();

    abstract void stepTwo();
}

// 具体子类
class ConcreteClass extends AbstractClass {
    @Override
    void stepOne() {
        System.out.println("Step One");
    }

    @Override
    void stepTwo() {
        System.out.println("Step Two");
    }
}

// 主程序
public class Main {
    public static void main(String[] args) {
        ConcreteClass concrete = new ConcreteClass();
        concrete.templateMethod();
    }
}

优点
提供了代码复用和减少重复性代码的优势。
定义了一个算法的骨架,使得子类可以在不改变算法结构的情况下重新定义算法的某些步骤。
注意事项
模板方法模式需要考虑好哪些方法应该是抽象的,哪些方法应该是具体的,以确保灵活性和可维护性。
子类实现的具体方法可能影响算法的整体性能,需要谨慎设计。

匿名对象

简单来说就是

new Myclass();//而不是 Myclass a = new Myclass();
Java中,匿名对象是指没有被显式赋予一个变量名的对象。它通常在创建对象的同时调用其方法或者作为参数传递给方法时使用,而不将其赋值给一个变量。

下面是一个简单的示例来说明匿名对象的概念:

java
class MyClass {
    public void display() {
        System.out.println("Hello, this is a method of the object");
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建匿名对象并调用方法
        new MyClass().display();

        // 匿名对象作为方法参数
        printMessage(new MyClass());
    }

    public static void printMessage(MyClass obj) {
        obj.display();
    }
}
在上面的示例中,MyClass 是一个简单的类,其中包含了一个 display() 方法。在 Main 类的 main 方法中,
我们创建了一个匿名对象并直接调用其 display() 方法。另外,我们也演示了如何将匿名对象作为参数传递给另一个方法 printMessage()。

使用匿名对象可以简化代码,特别是在一次性使用某个对象时。然而,需要注意的是,由于匿名对象没有变量名引用,因此无法再次使用或者对其进行操作。

匿名内部类

class a{
    class b{
    }
}
//访问:a.b
方法:
new 类名/接口(){
    //重写方法
}
例子
interface Greeting {
    void greet();
}

public class Main {
    public static void main(String[] args) {
        // 使用匿名内部类实现接口
        Greeting greeting = new Greeting() {
            @Override
            public void greet() {
                System.out.println("Hello, world!");
            }
        };
        
        greeting.greet(); // 输出:Hello, world!
    }
}


static

是什么

Java中,static 是一个关键字,可以用来修饰变量、方法、代码块和内部类。下面我将解释 static 关键字在不同情境下的用法:

1. 静态变量(Static Variables):
静态变量属于类,而不是属于类的实例。所有该类的实例共享同一个静态变量的值。

class MyClass {
    static int count = 0;
}

2. 静态方法(Static Methods):
静态方法属于类,可以直接通过类名调用,不需要创建类的实例。

class MyClass {
    static void static Method() {
        System.out.println("This is a static method");
    }
}
3. 静态代码块(Static Blocks):
静态代码块在类加载时执行,用于初始化静态变量或执行一些静态操作。

class MyClass {
    static {
        System.out.println("Static block is executed");
    }
}
4. 静态内部类(Static Inner Classes):
静态内部类与外部类的实例无关,可以直接通过外部类名访问。

class OuterClass {
    static class InnerClass {
        // 内部类的代码
    }
}

注意事项

静态变量和方法可以直接通过类名访问,无需实例化对象。
静态方法不能直接访问非静态成员,但可以调用其他静态方法。
静态代码块在类加载时执行,只会执行一次。
静态变量会在类加载时初始化,并且只会初始化一次。
静态方法只能访问静态成员,非静态可以访问静态
静态方法中不能使用this
常用于工具类

final、static、abstract的区别

Java中,staticfinalabstract是三个不同的关键字,它们在面向对象编程中有着不同的作用和用途。

static 关键字:
static 用于定义静态变量、静态方法、静态代码块和静态内部类。
静态成员属于类级别而不是实例级别,可以通过类名直接访问,不需要创建类的实例。
静态成员在类加载时就被初始化,并且只有一份副本。

final 关键字:
final 用于声明不可改变的常量、不可继承的类或不可重写的方法。
对于变量,一旦赋值后就不能再次修改。
对于方法,表示方法不能被子类重写。
对于类,表示该类不能被继承。

abstract 关键字:
abstract 用于定义抽象类和抽象方法。
抽象类不能被实例化,其中可以包含抽象方法和非抽象方法。
抽象方法只有声明而没有实现,必须在子类中被重写实现。
如果一个类包含抽象方法,则该类必须被声明为抽象类。

区别:
作用不同:static 用于定义静态成员,final 用于定义不可变的实体,abstract 用于定义抽象类和方法。
可访问性不同:静态成员可以通过类名直接访问,final 成员不可改变,abstract 方法需要在子类中实现。
实例化不同:静态类无法实例化,final 变量是常量,抽象类无法实例化。
举例来说,一个静态方法可以是 static 但不是 finalabstract,因为它是类级别的方法;
一个常量可以是 final 但不是 staticabstract,因为它是不可变的;
一个抽象方法可以是 abstract 但不是 staticfinal,因为它需要在子类中实现。
finalabstract是冲突的

final

是什么

java关键字
用来修饰:类,变量,方法

使用场景

1.某个变量不允许修改
2.某个方法不允许子类重写
3.某个类不允许继承

怎么用

修饰方法
class ParentClass {
    public final void finalMethod() {
        // 方法的实现
    }
}

修饰变量
final int num = 10;
声明为final的基本类型变量num表示一个常量,其值不能再被修改。

修饰类
java
final MyClass myObj = new MyClass();

注意事项

final引用类型变量的限制: 
使用final修饰的引用类型变量表示其引用指向的对象不能再改变。但是,对象本身的属性可以被修改,除非也使用了其他限定词(例如,const)。

final与多线程:
final关键字提供了一定程度的线程安全性,因为final变量的值在初始化后不能被修改。然而,如果final变量引用的是可变对象,对象本身的状态可能会被修改。

final关键字可以帮助编译器进行优化,但使用过多的final变量可能会导致代码可读性下降。因此,应该谨慎使用final,只在必要的情况下使用。

权限修饰符

private: 本类使用
protected:  
成员可以被子类继承,并且在子类中可以被访问。也就是说,子类可以访问其父类中被protected修饰的成员。
同包非子类可访问,不同包子类可访问
public: 公开的
默认: 当前包下的任意类
所以三者范围 : private < 默认 < protected < public
注意事项 : 方法重写保证子类中方法的访问权限 >= 父类

特殊类

工具类

JDK = JRE + 核心类库.JDK提供很多工具类.

不能被继承
不能让其他类创建对象,不需要实例化
提供静态方法
public class StringUtils {
    private StringUtils() {
        // 私有构造方法,避免实例化
    }
    
    public static boolean isNullOrEmpty(String str) {//静态方法
        return str == null || str.isEmpty();
    }
    
    public static String reverseString(String str) {
        return new StringBuilder(str).reverse().toString();
    }
}

特殊工具类

Date类

日期类,java.util包里,精确到毫秒,getTime(),setTime();

DateFormat类
日期格式化类,对日期格式化
//DateFormat类是一个抽象类,我们用子类SimpleDateFormat
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
    public static void main(String[] args) {
        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String formattedDate = sdf.format(now);
        System.out.println("Formatted date: " + formattedDate);
    }
}

Calendar类
没有过期,代替java.util.Date过期方法
在 Java 中,Calendar 类是用于处理日期和时间的抽象类,它提供了许多操作日期和时间的方法,
如获取日期时间的各个部分(年、月、日、时、分、秒等)、日期计算、日期比较等功能。
Calendar 类是一个抽象类,通常使用其子类 GregorianCalendar 来表示具体的日期和时间。

以下是一个简单的示例,演示了如何使用 Calendar 类来获取当前日期和时间的各个部分:
import java.util.Calendar;

public class Main {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();//获取子类GregorianCalendar

        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1; // 月份从0开始,需要加1
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);

        System.out.println("Current Date and Time:");
        System.out.println("Year: " + year);
        System.out.println("Month: " + month);
        System.out.println("Day: " + day);
        System.out.println("Hour: " + hour);
        System.out.println("Minute: " + minute);
        System.out.println("Second: " + second);
    }
}
在上面的示例中,我们首先通过 Calendar.getInstance() 方法获取一个 Calendar 对象 cal,
然后使用该对象的 get 方法获取当前日期和时间的各个部分,如年、月、日、时、分、秒等。

需要注意的是,Calendar 类也是非线程安全的,如果需要在多线程环境下进行日期时间操作,
应当考虑使用线程安全的方式处理,比如使用 ThreadLocal 来保证每个线程都有自己的 Calendar 实例。

System类
System工具类中常用的方法包括:

getProperty(String key): 获取指定系统属性的值。
String osName = System.getProperty("os.name");

currentTimeMillis(): 返回当前时间的毫秒数。
long currentTime = System.currentTimeMillis();

exit(int status): 终止当前运行的Java虚拟机。
System.exit(0);

gc(): 请求垃圾回收。
System.gc();

arraycopy(Object src, int srcPos, Object dest, int destPos, int length): 复制数组。
int[] srcArray = {1, 2, 3};
int[] destArray = new int[3];
System.arraycopy(srcArray, 0, destArray, 0, 3);

BigInteger类
BigInteger类是Java中用于表示任意精度整数的类。
它允许你表示和操作比基本数据类型(如intlong)所能表示的范围更大的整数。

创建BigInteger对象:可以通过构造方法或静态工厂方法创建BigInteger对象。

BigInteger num1 = new BigInteger("123456789012345678901234567890"); // 通过字符串创建
BigInteger num2 = BigInteger.valueOf(987654321098765432109876543210L); // 通过long类型创建

基本运算
BigInteger sum = num1.add(num2); // 加法
BigInteger product = num1.multiply(num2); // 乘法
int result = num1.compareTo(num2); //比较 返回-1(小于)、0(等于)、1(大于)

转换为基本数据类型
可以将BigInteger转换为基本数据类型,或者获取其对应的字节数组。
long longValue = num1.longValue(); // 转换为long类型
byte[] byteArray = num1.toByteArray(); // 转换为字节数组

BigDecimal类
BigDecimal类是Java中用于表示任意精度的十进制数的类。
它提供了高精度的浮点数运算,用于解决在使用浮点数时可能出现的精度丢失问题。

创建BigDecimal对象:可以通过构造方法或静态方法创建BigDecimal对象。
BigDecimal num1 = new BigDecimal("123.456"); // 通过字符串创建
BigDecimal num2 = BigDecimal.valueOf(987.654); // 通过double类型创建

基本运算
BigDecimal sum = num1.add(num2); // 加法
BigDecimal product = num1.multiply(num2); // 乘法
int result = num1.compareTo(num2); //比较 返回-1(小于)、0(等于)、1(大于)

设置精度:可以设置精度并进行舍入操作。
BigDecimal result = num1.setScale(2, RoundingMode.HALF_UP); // 设置精度为2位,采用四舍五入

BigDecimal类通常用于金融计算、税务计算或其他需要高精度计算的场景。

Arrays类
Arrays类是Java中用于操作数组的工具类,提供了各种方法来方便地对数组进行排序、搜索、比较等操作。

排序数组
int[] arr = {3, 1, 4, 1, 5, 9, 2, 6};
Arrays.sort(arr); // 对数组进行升序排序

数组填充
int[] arr = new int[5];
Arrays.fill(arr, 10); // 将数组所有元素填充为10

数组复制
int[] srcArr = {1, 2, 3, 4, 5};
int[] destArr = Arrays.copyOf(srcArr, srcArr.length); // 复制srcArr数组到destArr数组

数组比较
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
boolean isEqual = Arrays.equals(arr1, arr2); // 判断arr1和arr2是否相等

数组搜索
int[] arr = {10, 20, 30, 40, 50};
int index = Arrays.binarySearch(arr, 30); // 在数组中查找元素30的索引

包装类

基本类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charcharacter
booleanBoolen
。解决问题:
1.实现String类型(非包装类)的七种基本类型的(没有char)之间的转换
2.学习mysql会使用包装类,包装类可以存null

。怎么使用:
Integer num = 100;//定义
String s = String.valueof(num); //int => String
int num = Integer.pareseInt(s); //String => int

。注意事项:
1.String 类型转成 其他类型:1234AAAInt 会有异常

。除了floatdouble都有常量池:
Integer num1 = 10;//整数只要是在[-128,127]中,就会直接在常量池中获取对象

String类

常用的函数:

length():返回字符串的长度。
charAt(int index):返回指定索引处的字符。
indexOf(String str):返回指定子字符串第一次出现的索引。
substring(int beginIndex):返回从指定索引开始到字符串末尾的子字符串。
substring(int beginIndex, int endIndex):返回指定索引范围内的子字符串。
equals(Object anObject):比较字符串内容是否相同。
toLowerCase():将字符串转换为小写。
toUpperCase():将字符串转换为大写。
trim():去除字符串首尾的空格。
startsWith(String s);是否以s开头
split(String regex):根据给定正则表达式分隔字符串。

代码块

代码位置

class A{
    //成员变量:静态、非静态
    
    //成员方法:静态、非静态、抽象
    
    //构造方法
    
    //代码块
    {
    }
}

代码块划分

。静态代码块//使用最多

static{
    //类加载时,执行一次,对静态数据初始化
}

。构造代码块

位置:在类中方法,在构造函数之前运行
使用场景:在构造函数中共性的东西放在构造代码块中

。局部代码块

写在方法体中
用于限定变量作用域

接口

。定义开发功能
。不能实例化,没有构造方法
。可以多实现,一类可以实现多接口,解决java的单继承问题

public interface 接口{
    double 抽象方法();  // 接口中的抽象方法,不包含方法体
    double getPerimeter();  // 另一个抽象方法
    //静态常量: 数据固定且值是唯一
    public static final int NUMBER = 10;
    //成员方法:抽象
    
}

// 实现接口的类
public class 接口实现类 implements 接口 {

}

jdk8变化

.jdk8往后允许接口中的定义可以是默认default
不能直接(接口名.方法名)用
.其他的成员可以(接口名.方法名)

类和接口

类和类:继承
类和接口:实现
接口和接口:继承,可以多继承

枚举

//枚举是什么
数据类型,表示常用固定的取值,本质是一个类
//怎么用
public enum 枚举名{
     BOY,GIRL;
}
//例子
enum Sex {
    BOY = "boy",GIRL = "girl";
};

int main() {
    // 使用switch语句根据今天是星期几做出不同的操作
    switch (Sex sex) {
        case BOY:
            cout << "男孩" << endl;
            break;
        case GIRL:
             cout << "女孩" << endl;
    }
    return 0;
}

多态

多种形态,同一个对象在不同时刻表现出不同形态
方式:
父类型 对象 = new 子类();//大类型包含小类型
好处:
1.提高代码复用性
2.提高代码扩展性
。编译时多态(静态多态):编译时多态是通过函数重载和运算符重载实现的
void print(int num) {
    std::cout << "Integer: " << num << std::endl;
}

void print(double num) {
    std::cout << "Double: " << num << std::endl;
}

int main() {
    int x = 10;
    double y = 3.14;
    print(x);  // 调用print(int)
    print(y);  // 调用print(double)
    return 0;
}
。运行时多态(动态多态):运行时多态是通过继承和虚函数实现的。一般就是大类包含小类
// 运行时多态示例:虚函数
class Shape {
public:
    virtual void draw() {
        std::cout << "Drawing a shape." << std::endl;
    }
};

class Circle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a circle." << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a rectangle." << std::endl;
    }
};

int main() {
    Shape* shape1 = new Circle();
    Shape* shape2 = new Rectangle();

    shape1->draw();  // 调用Circle的draw函数
    shape2->draw();  // 调用Rectangle的draw函数

    delete shape1;
    delete shape2;

    return 0;
}

注意事项

。父类和子类有相同的成员变量:编译和运行都是以父类的为主
。父类和子类有相同的成员方法:
编译以父类为主,也就是父类必须有;运行以子类为主,调用子类的成员方法
。弊端:父类引用不能调用子类的特有的方法

多态转型

。自动类型提升
父类型 父引用 = new 子类;
。强制类型转换
。解决问题:父引用不能使用子类特有成员
。子类 对象 = (子类)父引用
注意细节 :
会有类型转换异常:ClassCastException
=> 解决方法
对象名 instanceof 引用数据类型
class Animal {}

class Dog extends Animal {}

class Cat extends Animal {}

public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();

        System.out.println(animal1 instanceof Animal); // true,因为animal1是Animal类的实例
        System.out.println(animal1 instanceof Dog);    // true,因为animal1是Dog类的实例
        System.out.println(animal1 instanceof Cat);    // false,因为animal1不是Cat类的实例

        System.out.println(animal2 instanceof Animal); // true,因为animal2是Animal类的实例
        System.out.println(animal2 instanceof Dog);    // false,因为animal2不是Dog类的实例
        System.out.println(animal2 instanceof Cat);    // true,因为animal2是Cat类的实例
    }
}

Object

顶层父类:Object
方法:
equals(Object obj): 用于比较两个对象是否相等。默认情况下,它比较的是对象的引用地址,可以根据需要重写该方法以实现自定义的相等性比较逻辑。

hashCode(): 返回对象的哈希码值,通常用于哈希表等数据结构中。

toString(): 返回对象的字符串表示。默认实现返回类的名称加上 “@” 符号和对象的哈希码值,通常需要根据需求重写以返回更有意义的字符串表示。

getClass(): 返回对象的运行时类。

clone(): 从原始对象创建一个副本。在使用时需要注意实现 Cloneable 接口并处理可能抛出的 CloneNotSupportedException 异常。

notify(), notifyAll(), wait(): 这些方法用于线程之间的通信和同步。

finalize(): 用于垃圾回收前的资源释放操作,但不推荐使用,因为无法保证何时会被调用。

正则表达式

什么是正则表达式:
由特定的字符组成的字符串校验规则
用来干嘛?
用来校验,检查字符串是否符合规定
。怎么用:
详细语法

普通字符:包括字母、数字和大多数标点符号,在正则表达式中表示自身。

例如:字符 "a" 匹配字符串 "apple" 中的 "a"。

元字符:具有特殊含义的字符,如下所示:

.: 匹配任意单个字符,除了换行符。
^: 匹配输入字符串的开始位置。
$: 匹配输入字符串的结束位置。
*: 匹配前面的元素零次或多次。
+: 匹配前面的元素一次或多次。
?: 匹配前面的元素零次或一次。
\: 转义字符,可以将具有特殊含义的字符转义为普通字符。

字符类:用[]表示,匹配其中任意一个字符。

例如:[aeiou] 匹配任何一个元音字母。

重复:用{}表示,指定重复次数。

例如:a{3} 匹配三个连续的字符 "a"。

选择:用|表示,表示两者中的一个。

例如:cat|dog 匹配 "cat""dog"。

分组:用()表示,可以对正则表达式的一部分进行分组。

例如:(ab)+ 匹配 "ab""abab""ababab" 等。

集合

Collection集合

特点:
大小可变(随意扩容)、可以存储多种类型数据、底层使用数据结构(快)
记住接口必须实例化
image.png
常用方法

添加元素

boolean add(E e): 将指定的元素添加到集合中(如果适用)。
boolean addAll(Collection<? extends E> c): 将指定集合的所有元素添加到集合中(如果适用)。

移除元素
boolean remove(Object o): 从集合中移除指定元素(如果存在)。
boolean removeAll(Collection<?> c): 从集合中移除包含在指定集合中的所有元素。

获取大小和清空
int size(): 返回集合中的元素数量。
void clear(): 清空集合中的所有元素。

判断包含关系
boolean contains(Object o): 如果集合包含指定的元素,则返回trueboolean containsAll(Collection<?> c): 如果集合包含指定集合的所有元素,则返回true。

迭代访问
Iterator<E> iterator(): 返回在此集合上进行迭代的迭代器。

List集合
表示一个有序的集合,其中可以包含重复元素。
List接口允许按照插入顺序来访问集合中的元素,并且可以通过索引来访问指定位置的元素。
常用的List实现类有ArrayListLinkedListVector//获取元素:
List集合.get(索引);
//添加元素:
List集合.add(索引,元素值)
//修改元素
List集合.set(索引,元素值)

import java.util.List;
import java.util.ArrayList;

public class ListExample {
    public static void main(String[] args) {
        // 创建一个ArrayList实例
        List<String> stringList = new ArrayList<>();

        // 添加元素到List中
        stringList.add("Apple");

        // 通过索引访问元素
        String secondElement = stringList.get(1);

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

LinkList集合

底层:链表,查询慢,增删快,双向链表,有序,重复元素,有索引

         // 创建一个LinkedList实例
        LinkedList<String> linkedList = new LinkedList<>();
        // 向链表中添加元素
        linkedList.add("Apple");

        // 在链表开头添加元素
        linkedList.addFirst("Mango");

        // 在链表末尾添加元素
        linkedList.addLast("Grapes");

        // 遍历链表并打印元素
        for (String fruit : linkedList) {
            System.out.println(fruit);
        }

        // 获取第一个元素
        String firstElement = linkedList.getFirst();

        // 获取最后一个元素
        String lastElement = linkedList.getLast();

Set集合

没有索引,不保证顺序,不允许重复元素,会自动去重,元素唯一,底层是哈希表
子类: HashSet,TreeSet

HashSet

底层就是HashMap实现的

        // 创建一个HashSet实例
        Set<String> stringSet = new HashSet<>();

        // 向Set中添加元素
        stringSet.add("Apple");

        // 检查Set是否包含特定元素
        System.out.println("Contains 'Banana': " + stringSet.contains("Banana"));

        // 移除指定元素
        stringSet.remove("Apple");

LinkedHashSet

没有索引,没有重复元素,元素顺序一致,底层是LinkedHashMap实现

TreesSet

底层是红黑树,没有重复元素,没有索引,存储的元素按照规则排序

//通过Comparator接口
TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {//新排序规则
            @Override
            public int compare(String s1, String s2) {
                return Integer.compare(s1.length(), s2.length());
            }
        });
class Person implements Comparable<Person> {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public int compareTo(Person otherPerson) {
        // 按照年龄升序排序
        return Integer.compare(this.age, otherPerson.age);
    }
    
    @Override
    public String toString() {
        return name + " (" + age + ")";
    }
}

public class Main {
    public static void main(String[] args) {
        TreeSet<Person> treeSet = new TreeSet<>();
        
        treeSet.add(new Person("Alice", 30));
        treeSet.add(new Person("Bob", 25));
        treeSet.add(new Person("Charlie", 35));
        
        System.out.println(treeSet); // 输出结果为 [Bob (25), Alice (30), Charlie (35)]
    }
}

哈希表

。JDK8以前:底层是大小16的数组+链表的存储方式
。JDK8以后:底层是数组 + 链表/红黑树

Map集合

。双列集合,一次存储两个元素,key 和 value
。key不能重复,value允许重复
。一个key对应一个value
。存取元素不保证顺序
。没有索引

public class Main {
    public static void main(String[] args) {
        // 创建一个HashMap,键为String类型,值为Integer类型
        Map<String, Integer> myMap = new HashMap<>();

        // 向HashMap中插入键值对
        myMap.put("Alice", 30);

        // 遍历HashMap并输出键值对
        //方法一:Map.entry对象是所有键值对对象
        for (Map.Entry<String, Integer> entry : myMap.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        //方法二: 获取所有的key
        Set<String> keys = map.keySet();
        for(String k:keys){
            String value = map.get(key);
            cout << "keys" << key << "values" << values << endl;
        }
        // 检查HashMap中是否存在某个键
        String name = "Bob";
        if (myMap.containsKey(name)) {
            System.out.println(name + " found in the map with value: " + myMap.get(name));
        } else {
            System.out.println(name + " not found in the map");
        }

        // 删除HashMap中的一个键值对
        myMap.remove("Charlie");
    }
}

HashMap

哈希表

LinkedHashMap

元素唯一且有序

TreeMap

红黑树,有排序,键去重

迭代器

用于集合遍历

获取迭代器
首先需要通过集合的iterator()方法获取到迭代器实例,通常是通过Collection接口提供的iterator()方法来获取。
Collection<String> collection = new ArrayList<>();
Iterator<String> iterator = collection.iterator();

遍历集合
使用迭代器的hasNext()next()方法来遍历集合中的元素。
hasNext()方法用于检查是否还有下一个元素,next()方法用于获取下一个元素。
while (iterator.hasNext()) {
    String element = iterator.next();
    // 对当前元素进行操作
}

删除元素
使用迭代器的remove()方法而不是集合自身的remove()方法。
理由:
因为集合和迭代器一一对应,集合remove,迭代器是不知道的,会有ConcurrentModificationException异常。
同样,集合add也会造成错误
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    if (someCondition) {
        iterator.remove(); // 删除当前元素
    }
}

注意事项
1迭代器是单向的,只能向前遍历,不能后退。
2在使用迭代器遍历过程中,不要直接修改集合,应该使用迭代器提供的方法进行修改。
3也会有索引边界问题,不能访问空集合的next()

增强for循环链接

for(元素类型 变量 : 容器){
    //底层也是使用迭代器
}

泛型

是什么:
是一种类型参数,可以设置存储数据的类型
使用在代码编译器时的技术方式,在运行时就擦除了。
解决问题:
限定类型,指定对应类型,简化代码
在工具类时常用
。泛型的使用:

泛型类:不确定类中属性不知道使用什么时

public class Box<T> {
    private T value;
    
    public T getValue() {
        return value;
    }
    
    public void setValue(T value) {
        this.value = value;
    }
}

泛型方法:
public <T> T getFirstElement(List<T> list) {
    if (list.isEmpty()) {
        return null;
    }
    return list.get(0);
}

泛型接口:
// 泛型接口
public interface MyCollection<E> {
    // 添加功能
    public abstract void add(E e);
    // 删除功能
    public abstract void remove(E e);
}
// 指定泛型的第一种方式 : 让实现类去指定接口的泛型
class MyCollectionImpl1 implements MyCollection<String>{
    @Override
    public void add(String s) {

    }
    @Override
    public void remove(String s) {

    }
}
// 指定泛型的第二种方式 : 实现类不确定泛型,延续泛型,回到泛型类的使用
class MyCollectionImpl2<E> implements MyCollection<E>{
    @Override
    public void add(E a) {

    }
    @Override
    public void remove(E a) {

    }
}

通配符:
通配符主要用于指定泛型的上限和下限。
有三种通配符:?表示未知类型,? extends T表示类型的上限为T(<= T)? super T表示类型的下限为T( >= T)。

泛型约束:
可以通过继承和接口实现来限制泛型类型参数的类型范围
public class Box<T extends Number> {
    // 只能是Number或其子类
}
类型擦除:
Java中的泛型是通过类型擦除来实现的,编译器在编译时会擦除泛型信息,这意味着在运行时无法获取泛型类型信息。

异常

什么是异常:
程序在运行时发生一些不正常的情况,造成程序中断
解决什么问题:
确保程序不会中断,跳过异常部分代码
异常怎么处理:
1、声明:throws , 自己不处理交给其他类
2、捕获:try…catch,自己处理

public void method()throws 异常类{
    //有编译异常
}
public void hello(){
    //有运行异常:try..catch
}

注意事项:

捕获合适的异常: 捕获并处理特定类型的异常,而不是简单地捕获通用的Exception。这样可以更精确地处理各种情况,并避免隐藏潜在的问题。

避免空指针异常: 在访问对象之前,务必进行空指针检查,以确保对象不为空。可以使用条件语句或者Java 8中引入的Optional类来避免空指针异常。

不要忽略异常: 不要在catch块中什么都不做,或者简单地打印异常信息。至少应该记录异常信息、采取适当的措施或者抛出新的异常。

使用try-with-resources语句: 对于需要关闭的资源(如文件或数据库连接),使用try-with-resources语句可以确保资源在使用完毕后被正确关闭,避免资源泄漏。

抛出适当的异常: 当方法无法处理某个情况时,应该抛出适当的异常来通知调用者。可以选择现有的异常类,也可以自定义异常类。

避免捕获所有异常: 避免过度捕获所有异常而不加区分,这可能导致隐藏真正的问题。只捕获你能够处理的异常,并将其他异常向上层抛出。

日志记录异常: 使用日志记录框架(如log4j、SLF4J等)来记录异常信息,以便后续排查问题。

遵循异常处理最佳实践: 尽量避免在finally块中添加业务逻辑,确保finally块只用于资源清理操作。

finally和catch使用注意事项:

如果try块中的代码发生异常,Java会匹配相应的catch块来处理异常。
如果异常被捕获并处理,那么接下来会执行对应的catch块中的代码。
然后,无论是否发生异常,finally块中的代码都会被执行。finally块用于确保资源的释放或清理工作,在异常处理之后执行。
所以,无论是否发生异常,finally块中的代码都会在catch块处理完异常之后被执行。即使在catch块中有return语句,finally块中的代码仍然会被执行。

可变参数

在调用方法时,传递的参数可以是任意个(底层是使用数组)

public static int sum(int... numbers) {
    
}

注意事项

。可变参数只能书写在末尾
public int sum(int n,int...numbers){
}
。不能重复命名
错误示范:
public int sum(int...numbers){
}
public int sum(int[]a){
}

。Collections工具类
不能创建对象,提供静态方法,针对List,Set集合

Collections.addAll(list,"html","javascript");//向list集合中添加元素

笔记参考链接

1.

  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tag_B

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值