Java基础知识(2023年总结)持续更新...

写在前面的话,

1)坚持:初学一门语言时,一定要持续学习,不能中断。

2)实践:学习编程语言,一定也要多敲代码,先跟着例子敲一遍,然后试着自主完成课后习题。

3)万事开头难:不理解代码也没关系,可以学习debug后。一行一行打断点,查看程序的实行过程,千万不要觉得麻烦,养成习惯会节省很多重复学习的时间。

目前该学微服务,所以决定每天复习总结一点Java基础知识再学习一些新知识,写博客就是总结+学习。

Java特点(看不懂没事,别背)

跨平台性:Java 代码可以在不同的操作系统平台上运行。这是因为 Java 代码在编译时被转换为字节码格式,而该格式可以在任何 Java 虚拟机(JVM)上运行。这种跨平台性使得 Java 成为最流行的开发高度移植性应用程序的语言之一。
面向对象:Java 是一种面向对象编程(OOP)的语言,它支持封装、继承和多态等 OOP 的核心概念。这使得代码易于维护、理解和扩展。Java 的 OOP 特性也可以提高代码的可重用性和可靠性。
安全性:由于 Java 的应用程序运行在虚拟机中,可以设置安全策略,因此 Java 应用程序有较高的安全性。其还包括内置的安全功能,如内存管理机制可以避免缓冲区溢出等安全漏洞,Java 还支持许多安全性功能和技术,例如数字签名和加密等。
可移植性:由于 Java 应用程序可以在任何 JVM 上运行,因此它们不仅是跨平台的,而且也是可移植的。这意味着即使在不同的计算机或操作系统上运行,Java 应用程序也可以以相同的方式运行。
多线程性:Java 提供原生支持多线程编程。Java 的线程机制可帮助开发人员构建并发、异步和并行应用程序。这使得 Java 成为处理同时性和 I/O 密集型任务的理想语言。
简单性:Java 的语法相对简单,易于学习和理解。其注重一致性,因此程序员可以用相同的代码风格编写程序。Java 的标准库也非常大,其中包含许多有用的工具和数据结构来帮助程序员编写高质量的代码。
性能:由于 Java 应用程序由 JVM 执行,JVM 可以根据应用程序的特定需求进行调整,以优化代码的性能。Java 还使用即时编译器(Just-In-Time Compilation,JIT)来将字节码转换为本机机器码,以进一步提高应用程序的性能。

1.环境搭建

1.1 jdk的下载与安装

jdk8下载地址:Java Downloads | Oracle 中国

运行.exe文件

 点击下一步,配置安装路径

1.2 配置环境变量

右击此电脑选择属性=>点击高级系统设置=>点击环境变量=>点击系统变量下面新建=>配置安装路径(第一个图)=>再配置bin

 输入后回车。

然后再点新建,输入后回车。

 点击确定,环境变量就配置完成了。

 让我们来检测一下是否配置成功,按win+r,输入cmd,确认。

然后再命令框里面输入java -version,一定要有空格和-。

如果显示类似于如下的信息,代表配置成功,如果配置失败,请检查是否严格按照步骤来的。

1.3 打印helloworld

代码,保存为HelloWorld.java

 Javac HelloWorld.java编译之后出现class文件

 java HelloWorld运行

 2.Java基础语法

2.1 数据类型

基本数据类型(Primitive Data Type)

Java有8种基本数据类型,分别是:

byte:1字节,范围为-128到127
short:2字节,范围为-32768到32767
int:4字节,范围为-2147483648到2147483647
long:8字节,范围为-9223372036854775808到9223372036854775807
float:4字节,范围为1.4E-45到3.4028235E38
double:8字节,范围为4.9E-324到1.7976931348623157E308
char:2字节,表示Unicode字符集中的一个字符,范围为\u0000到\uFFFF
boolean:1位,表示true或false

引用数据类型(Reference Data Type)

Java中的引用类型指的是对象(Object)的引用,这种类型不包含实际的数据。Java中引用类型有:

类(Class)
接口(Interface)
数组(Array)
字符串(String)
包装类(Wrapper Class)

2.2类型转换

  1. 自动类型转换:数据类型小的自动赋值给数据类型大的
  2. 强制类型转换:数据类型大的赋值给数据类型小的
  3. 格式:小数据类型 变量名 = (小数据类型)大数据类型;
  4. 加号会自动转换为int类型
  5. 整数默认是int类型,byte、short和char类型数据参与运算均会自动转换为int类型。
  6. boolean类型不能与其他基本数据类型相互转换

2.3 double精度丢失问题

小数转换为二进制会有丢失

例如:
○ 有穷尽数据:
    0.125变成二进制为:
        0.125*2=0.25  ......取整0
        0.25*2=0.5   ......取整0
        0.5*2= 1.0   ......取整1
        0.0*2=0
        所以0.125的二进制为0.001
○ 无穷尽数据:
    0.9变成二进制为:
        0.9*2=1.8.....取整1
        0.8*2=1.6…....取整1
        0.6*2=1.2.....取整1
        0.2*2=0.4.....取整0
        0.4*2=0.8 ...取整0
        0.8*2=1.6 ....取整1
        所以0.9的二进制为0.111001110011100。。。
它是一个循环,不可能出现小数部分为0的情况。
所以当你按照一定精度进行截取时,它在内存中表示时就会小于0.9,就会产生精度丢失。

2.4 运算符

  1. 算数运算符:+,-,*,/(除、取整),%(取余)
  2. 赋值运算符:= , += , -= , *= , /= , %=
    1. 面试题:
          short s=1;  s = s+1; 
          
          short s=1;  s+=1;
      ​
          上面两个代码有没有问题,如果有,那里有问题。
          
          为什么第二个木有问题呢?
              扩展的赋值运算符其实隐含了一个强制类型转换。
              
              s += 1;
              不是等价于 s = s + 1;
              而是等价于 s = (s的数据类型)(s + 1);
    2. 赋值运算符隐含强制类型转换

    3. 自增自减运算符: ++ , --,

    4. 关系运算符:==(判断两端值是否相等),!= , > , >= , < , <=

    5. 字符串的+操作

      1. 在”+”操作中,如果出现了字符串,就是连接运算符,否则就是算术运算。当连续进行“+”操作时,从左到右逐个执行。

      2. 出现字符串则执行连接

    6. 逻辑运算符

                & 逻辑与 | 逻辑或 ^ 异或 ! 非

                逻辑短路运算符

                 && 短路与:左边为假,右边不执行

                || 短路或:左边为真,右边不执行

2.5 流程控制

J流程控制是一种使用Java编程语言的技术,用于控制代码的执行流程和决策。这种技术使用条件语句和循环语句来逐步指导程序确定下一步要执行的代码路径。
Java中的三种主要类型的流程控制语句是条件语句、循环语句和跳转语句

条件语句
条件语句是用于根据条件的不同,执行不同的代码块或语句。Java中提供了两种主要的条件语句:if语句和switch语句。

if语句:if语句根据布尔表达式的值来执行代码块。当布尔表达式为true时,if语句块中的代码将会被执行,否则if语句块中的代码将不会被执行。
语法如下:

 if (boolean_expression) {
     //Code to be executed if the boolean expression is true.
 }


switch语句:switch语句根据表达式的值来执行相应的代码块。表达式和每个case语句中的值进行比较,匹配时执行相应的代码块。如果没有找到匹配的值,则执行default语句块。
语法如下:
 

switch (expression) {
     case value1:
         //Code to be executed if expression matches value1
         break;
     case value2:
         //Code to be executed if expression matches value2
         break;
     …
     case valueN:
         //Code to be executed if expression matches valueN
         break;
     default:
         //Code to be executed if no other case matches
         break;
 }

循环语句
循环语句是用于重复执行相同代码块的技术。Java中提供了三种主要的循环语句:for循环、while循环和do-while循环。

for循环:for循环用于重复执行代码块,根据指定的初始值、终止条件和步长进行迭代。for循环特别适用于可以精确控制迭代次数的情况。
语法如下:

 for (initialization; condition; update) {
     //Code to be executed repeatedly until condition is true.
 }


while循环:while循环用于重复执行代码块,只要给定的布尔表达式为true,代码块就会被执行。while循环特别适用于不知道循环次数的情况。
语法如下:

 while (booleanexpression) {
     //Code to be executed repeatedly while booleanexpression is true.
 }


do-while循环:do-while循环类似于while循环,不同之处在于循环体代码块至少会被执行一次,因为判断布尔表达式的值是在循环体执行完之后进行的。
语法如下:

 do {
     //Code to be executed once before the boolean expression is checked.
 } while (boolean_expression);

跳转语句
跳转语句用于在代码块执行过程中跳转到指定位置,从而改变代码块的执行流程。Java中有三种主要的跳转语句:break语句、continue语句和return语句。

break语句:break语句用于跳出最近的循环语句或switch语句。
语法如下:
 break;
continue语句:continue语句用于跳过循环中的当前迭代,直接开始执行下一次循环迭代。
语法如下:
 continue;
return语句:return语句用于从方法中退出,并返回到调用该方法的代码中。
语法如下:
 return [expression];

3.数组

数组是一种数据结构,用于存储一组相同数据类型的值。 在Java中,数组是一个对象,具有一组固定大小的元素,可以通过索引来访问每个元素,索引从0开始。
Java中的数组有以下特点:

数组长度固定: 在创建数组时需要指定数组的长度,一旦创建后就不能改变数组的大小。
数组可以存储任何数据类型: Java中的数组可以存储基本数据类型,比如int、float、char等,也可以存储对象类型。
数组是对象: Java中的每个数组都是一个对象,因此可以有数组的引用。
数组元素的访问: 数组元素可以使用索引访问,数组元素的索引从0开始。
多维数组: 除了一维数组,Java还支持多维数组,可以是二维、三维等等。

在Java中,可以使用以下方式创建数组:

静态初始化: 创建数组时指定数组元素的值。

int[] numbers = {1, 2, 3, 4, 5};

动态初始化: 创建数组时只指定数组的长度,而不是元素的值。

int[] numbers = new int[5];

多维数组的创建:

int[][] matrix = new int[3][4];

Java中的数组拥有丰富的API,包括数组拷贝、数组排序、数组查找等等。 借助这些API,可以更加方便地操作数组。

4.面向对象

4.1方法

在Java编程中,方法是一段定义好的、可执行的代码块,用于完成特定的功能。方法声明的基本语法如下:

[修饰符] 返回类型 方法名(参数列表) {
    // 方法体
    // ...
    // [return 返回值;]
}

其中,修饰符可以是public、private、protected和default(不写修饰符),返回类型指定方法返回值的数据类型,如果该方法不返回任何值则使用关键字void,方法名表示方法的名称,参数列表指定方法需要的参数类型和参数名称,如果方法不需要参数,则留空。
在Java中,方法可以分为两种类型:静态方法非静态方法静态方法是一个类的方法,不需要实例化就可以调用;非静态方法必须通过实例化对象才能调用。
定义方法时可以有一个或多个参数,也可以没有参数。参数可以是任何数据类型,通常包括基本数据类型和对象类型。方法可以有一个返回值或没有返回值。如果方法返回值,则需要在方法中使用return语句用于返回所需类型的值。
示例代码:

public class MyClass {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int sum = add(a, b); // 调用静态方法
        System.out.println("sum = " + sum);
    }

    public static int add(int x, int y) { // 静态方法
        int result = x + y;
        return result; // 返回结果
    }
}

在上述示例中,我们定义了一个静态方法add,用于计算两个整数的和。在main方法中,我们调用了add方法,并将计算结果输出到控制台。
在Java中,还有一种特殊的方法叫做构造方法(Constructor),用于创建对象时初始化对象的数据。构造方法与普通方法的区别在于,构造方法没有返回值并且方法名必须与类名相同。当创建一个对象时,Java会自动调用构造方法来初始化对象的数据。
示例代码:

public class MyClass {
    private String name;
    private int age;

    public MyClass(String n, int a) { // 构造方法
        name = n;
        age = a;
    }

    public void display() {
        System.out.println("My name is " + name + ", and I'm " + age + " years old.");
    }

    public static void main(String[] args) {
        MyClass obj = new MyClass("Tom", 20); // 创建对象,调用构造方法
        obj.display(); // 调用方法
    }
}

在上述示例中,我们定义了一个类MyClass,包括构造方法和普通方法display。在构造方法中,我们初始化了对象的数据。在main方法中,我们创建了一个MyClass类型的对象,并调用display方法,输出对象的数据。

方法也根据有无返回值来划分,方法display无返回值,方法add有返回值。

4.2重载

方法重载(Overloading)是指在一个类中,可以定义多个同名方法,但参数列表不同(参数类型、参数个数或参数顺序不同),编译器会根据不同的参数列表自动调用相应的方法。Java中支持方法重载,是为了方便编程,在不同的场景下,使用同一个方法名可以传递不同的参数,灵活性更高。
方法重载的规则如下:

  1. 方法名相同;
  2. 参数列表不同,包括参数类型、参数个数或参数顺序不同;
  3. 与方法的返回类型无关;
  4. 方法的访问修饰符和final修饰符与重载无关。

例如,可以定义以下两个方法进行整数相加操作:

public class MathUtil {
    public static int add(int a, int b) {
        return a + b;
    }

    public static int add(int a, int b, int c) {
        return a + b + c;
    }
}

在上述代码中,我们定义了两个同名方法add,但是参数列表不同,第一个方法接受两个整数作为参数,第二个方法接受三个整数作为参数。通过方法重载,我们可以根据不同的情况选择使用适当的方法。
需要注意的是,在Java中,不允许同一个类中存在两个方法,它们的参数列表除了返回类型不同外,其他所有参数的类型都相同。
对于方法重载,还需要避免出现歧义的情况。例如,如果存在以下两个方法:

public static void func(int a, float b) {}
public static void func(float a, int b) {}

则当我们使用func(1, 2)的时候,编译器无法确定调用哪个方法,此时编译会失败。此种情形可通过强制类型转换来解决:

func(1.0f, 2); // 调用第二个方法
func(1, 2.0f); // 调用第一个方法

总之,方法重载可以提高代码的灵活度和可读性,但是需要注意参数列表的差异,避免出现歧义的情况。

方法重写

方法重写的规则如下:

  1. 父类中被重写的方法必须是一个非私有的实例方法,也就是说不能是 static、final 或 private 关键字修饰的方法。
  2. 重写方法必须有完全相同的方法名、参数列表(方法签名)、返回值类型及访问修饰符,否则会在编译时出错。
  3. 子类重写的方法的访问级别不能小于父类被重写方法的访问级别,即重写方法的访问修饰符权限不得收窄。
  4. 如果父类中被重写的方法抛出了异常,则子类中重写的方法必须抛出相同类型或其子类型的异常,或者不抛出任何异常。

方法重写的目的通常是为了增加、更新或修改父类方法的功能,使其更符合子类的需求。子类可以通过 super 关键字来调用被重写的父类方法。
关于方法重载(Method Overloading)与方法重写的区别,方法重载是在同一个类中定义了多个方法,而这些方法的方法名相同,但是参数列表不同(包括参数类型、参数顺序及参数个数),返回值类型可以相同也可以不同。其主要目的是方便调用方法,而不用为每个方法创建一个全新的名称,与方法重写是没有任何关系的概念。

4.3封装

封装是指将数据和行为封装在一个单元中,并对外部世界隐藏内部细节。这个单元被称为类。封装可以帮助保护数据的完整性和安全性,同时隐藏数据结构,使得代码更为简洁。
在Java中,封装可以通过访问控制修饰符来实现。Java有四种访问控制修饰符:public、protected、default、private。

  1. public:公共的,即任何地方都可以访问。
  2. protected:受保护的,只有同一个包内及其子类可以访问。
  3. default:默认的,即不加修饰符,只能在同一个包内访问。
  4. private:私有的,只有同一个类内部可以访问。

例如:

public class Person {
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

在上面的示例中,Person类有两个私有的成员变量name和age,这意味着它们只能在Person类内部访问,外部世界无法直接访问。此外,Person类还有两个公共的setter和getter方法,这些方法允许外部世界通过这些方法来访问这些私有的成员变量。这就是封装的一种体现。
在实际开发中,封装是很重要的。通过封装,可以保护数据的完整性和安全性,同时隐藏内部实现细节,使得代码更为简洁。这有助于提高代码的可维护性和可读性。因此,封装是Java编程中的一个重要概念。

4.4继承

Java中的继承是面向对象编程中的重要概念之一。它允许一个类(子类或派生类)继承另一个类(父类或基类)的属性和方法,并可以在子类中添加额外的属性和方法或修改父类的行为,从而提高代码的可重用性和扩展性。
Java中使用关键字extends来表示类的继承关系,子类继承父类中的所有非私有成员(属性和方法),包括构造函数。当一个子类继承父类时,它自动获得了父类的方法和属性,可以在子类中直接调用和使用。
下面是一个简单的Java继承例子:

// 定义父类Animal
public class Animal {
    private String name;
    public Animal(String name) {
        this.name = name;
    }
    public void eat() {
        System.out.println(name + " is eating");
    }
}

// 定义子类Dog
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
    public void bark() {
        System.out.println("Woof!");
    }
}

// 测试代码
public static void main(String[] args) {
    Dog dog = new Dog("Tom");
    dog.eat(); // 调用从父类Animal继承来的eat()方法
    dog.bark(); // 调用子类Dog中定义的bark()方法
}

在上面的例子中,Animal是父类,Dog是子类。Dog在定义时使用extends Animal语句指明它是Animal类的子类。在Dog类中,我们可以直接调用从Animal类继承来的eat()方法,同时也定义了自己的bark()方法。
Java中的单继承机制意味着每个类只能有一个直接父类,但是可以通过多级继承建立更复杂的继承关系。同时,Java中也提供了接口(Interface)机制,允许类实现多个接口,以实现功能上的多继承。

4.5多态

Java是一门面向对象编程语言,在Java中,多态指的是允许我们使用一个父类类型的引用来指向一个实际上是子类类型的对象的能力。多态允许我们编写更加灵活和可扩展的程序。
多态包括两种方式:动态多态和静态多态。
动态多态是指在程序运行时,根据对象的实际类型来执行方法。在Java中,动态多态的实现是通过方法重写来实现的。方法重写是指在子类中重新定义与父类中相同的方法,并且子类的方法具有相同的名称、参数列表和返回类型。在运行时,JVM将根据对象的实际类型来调用相应的方法。
静态多态是指在编译时根据参数类型来调用相应的方法。在Java中,静态多态的实现是通过方法重载来实现的。方法重载是指在同一个类中定义与相同的名称但参数列表不同的方法。在编译时,编译器会根据传递给方法的参数类型来决定调用哪个方法。(静态多态只是编辑时,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数)

  1. 多态的前提1:是继承
  2. 多态的前提2:要有方法的重写
  3. 父类引用指向子类对象,如:Animal a = new Cat();
  4. 多态中,编译看左边,运行看右边

以下是一个示例程序,它演示了Java中的多态:

public class Animal {
    public void makeSound() {
        System.out.println("The animal makes a sound");
    }
}

public class Dog extends Animal {
    public void makeSound() {
        System.out.println("The dog barks");
    }
}

public class Cat extends Animal {
    public void makeSound() {
        System.out.println("The cat meows");
    }
}

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

在上面的程序中,我们定义了一个Animal类作为父类,还定义了Dog和Cat作为子类。在主方法中,我们创建了一个Dog类型的对象以及一个Cat类型的对象,并分别分配给Animal类型的引用animal1和animal2。我们在这两个引用上调用makeSound方法。发生了什么?
这里发生了动态多态。尽管animal1和animal2的类型都是Animal,但它们所引用的对象的实际类型为Dog和Cat。因此,当我们在它们上面调用makeSound方法时,JVM会根据对象的实际类型来调用相应的方法。这意味着,当我们在animal1上调用makeSound时,JVM会调用Dog类中的makeSound方法,输出“The dog barks”。当我们在animal2上调用makeSound时,JVM会调用Cat类中的makeSound方法,输出“The cat meows”。
通过多态,我们可以编写更加灵活和可扩展的程序,因为我们可以使用父类类型的引用来访问子类对象,从而减少了代码的重复性。同时,多态使得我们的程序更易于维护和扩展,因为我们可以通过添加新的子类来扩展现有的程序。

5.抽象类

抽象类是一种特殊的类,不能被实例化。它通常用作其他类的基类,其中包含一些未实现的方法。抽象类中可以包含具有实现的方法以及抽象方法。抽象方法是一种没有实现体的方法,必须由子类实现。子类必须实现所有抽象方法,否则子类也必须声明自身为抽象类。
定义一个抽象类需要使用关键字“abstract”,并将其放在类的前面。以下是一个抽象类的简单例子,它包含了一个抽象方法和一个具体的方法:

abstract class Car {
   public void start() {
      System.out.println("Car started.");
   }

   public abstract void accelerate();
}

在这个例子中,Car是一个抽象类,它有一个具体的方法start(),它会打印出"Car started."这个信息。而accelerate()则是一个抽象方法,没有具体实现。
一个非抽象的子类必须实现所有抽象方法,否则它也必须是一个抽象类。以下是一个实现抽象类的子类的例子:

class Sedan extends Car {
   public void accelerate() {
      System.out.println("Sedan is accelerating.");
   }
}

在这个例子中,Sedan是Car的子类,它实现了抽象方法accelerate(),但没有实现start()方法,因为它已经在父类中有了具体的实现。
总之,抽象类是一种特殊的类,不能被实例化。它通常被用作其他类的基类,其中包含一些未实现的方法。抽象方法是一种没有实现体的方法,必须由子类实现。子类必须实现所有抽象方法,否则子类也必须声明自身为抽象类。

抽象类的使用原则如下:
(1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public;
(2)抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理;
(3)抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类;
(4)子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法(如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类)。

6.接口

接口是一种抽象类型,它定义了一组方法但没有实现方法的具体代码。接口只包含方法签名、常量和默认方法,没有成员变量和构造函数。
接口可以被多个类实现,实现类必须实现接口中定义的所有方法。一个类可以实现多个接口,这种方式有助于实现多重继承。
接口的语法格式:

public interface MyInterface {
    // 常量
    public static final int NUMBER = 10;

    // 抽象方法
    public void doSomething();

    // 默认方法
    public default void doSomethingElse() {
        // 默认实现
    }
}

接口中的方法默认是public抽象方法,不能有方法体,因为接口是抽象类型。接口中可以包含常量,常量是public static final的,不能被修改。接口中还可以定义默认方法,它们有默认实现。接口还可以继承其他接口。
示例:

public interface Movable {
    public void move();
}

public interface Swimmable {
    public void swim();
}

public class Fish implements Movable, Swimmable {
    public void move() {
        swim();
    }

    public void swim() {
        // 实现代码
    }
}

在这个示例中,移动和游泳是两个不同的接口。Fish类实现了这两个接口,必须实现接口中定义的方法。Fish类中的move()方法调用了swim()方法,因为它们实际上是同一个方法。
Java 8引入了默认方法和静态方法的概念,使接口更加灵活和可扩展。默认方法是接口提供的方法的默认实现,而静态方法是基于接口的工具方法或实用方法。
示例:

public interface Movable {
    public void move();
}

public interface Swimmable {
    public void swim();
}

public class Fish implements Movable, Swimmable {
    public void move() {
        swim();
    }

    public void swim() {
        // 实现代码
    }
}

在这个示例中,Printable接口定义了print()方法、默认方法printHello()和静态方法printStatic()。MyClass实现了Printable接口,并实现了print()方法。main()方法中演示了如何使用默认方法和静态方法。
总结一下,Java接口提供了一种协议来定义类之间的一组相似的方法特征。它还允许多个类实现同一组接口,实现多态性和代码复用。同时,接口还提供了默认方法和静态方法的特性来增强接口的性能。

需要注意的是:

在Java中,接口中的抽象方法默认就是抽象方法,因此在定义接口中的抽象方法时,可以省略abstract关键字。
例如,定义一个接口Animal,其中包含一个抽象方法eat(),可以写成如下形式:

public interface Animal {
    void eat();
}

在上述例子中,eat()方法的修饰符没有包含abstract关键字,但它仍然是一个抽象方法,需要在实现该接口的类中进行具体实现。
需要注意的是,如果在接口中定义一个非抽象方法,则必须显式地包含方法的实现代码。例如:

public interface Animal {
    void eat();  // 抽象方法
    default void sleep() {
        System.out.println("Animal is sleeping");
    }  // 非抽象方法,有实现代码
}

在上述例子中,sleep()方法是一个非抽象方法,其中包含了具体的实现代码。在具体实现该接口的类中,可以选择重写eat()方法,但不需要重写sleep()方法。

7.枚举

枚举是一种特殊的类,枚举类型是一组固定的常量,每个常量都有一个名称和一个对应的值。Java的枚举类型是在Java 5中引入的,它有助于编写更好的、可读性更好的代码。
枚举类型定义了一组常量,每个常量都是唯一的,不可改变的。通过定义枚举类型,可以将常量分类并把它们放在同一个组中。Java中的枚举类型是通过使用enum关键字定义的。
枚举类型在Java中有很多用途。例如,它们可以用来表示不同的状态、类型或选项。枚举类型还可以用于避免使用魔术常量,从而提高代码的可读性和可维护性。
以下是Java中定义枚举类型的语法:

enum EnumName {
   CONSTANT1, CONSTANT2, ..., CONSTANTN;
}

在这里,“EnumName”是枚举类型的名称,“CONSTANT1”到“CONSTANTN”是枚举类型的常量。例如,在下面的代码中我们定义了一个表示颜色的枚举类型:

enum Color {
   RED, GREEN, BLUE;
}

在这个例子中,我们定义了一个名为“Color”的枚举类型,它定义了三个常量:“RED”、“GREEN”和“BLUE”。
在Java中,可以使用switch语句来处理枚举类型。例如,如果我们想要检查一个变量是否为某个枚举类型中的常量,可以使用以下代码:

Color color = Color.RED;

switch (color) {
   case RED:
      System.out.println("The color is red.");
      break;
   case GREEN:
      System.out.println("The color is green.");
      break;
   case BLUE:
      System.out.println("The color is blue.");
      break;
   default:
      System.out.println("Unknown color.");
}

在这个例子中,我们首先定义了一个变量“color”并将其设置为“Color.RED”。然后,我们使用switch语句来检查这个变量是否为某个枚举类型中的常量,并根据不同的情况输出不同的消息。
总的来说,Java中的枚举类型可以提高代码的可读性和可维护性,因为它们将常量分类并把它们放在同一个组中。

8.常用类

8.1String

String是一个非常常用的类,它用于表示字符串。String类的实例是不可变的,即一旦创建了一个字符串对象,它的值就不能被改变。以下是Java常用类String的基本知识点和用法:

创建字符串对象

在Java中,可以通过以下方式创建一个字符串对象:
String str = "Hello, World!";  // 通过字符串字面值创建
String str = new String("Hello, World!");  // 通过new关键字创建

字符串操作

String类提供了许多操作字符串的方法,例如:
str.length() // 返回字符串的长度
str.charAt(index) // 返回指定索引处的字符
str.concat(str2) // 连接两个字符串
str.indexOf(str2) // 返回子字符串在原字符串中的位置
str.substring(start, end) // 返回原字符串的子字符串
str.replace(oldChar, newChar) // 替换字符串中的字符
str.toUpperCase() // 将字符串转换成大写字母
str.toLowerCase() // 将字符串转换成小写字母

字符串比较

String类还提供了许多比较字符串的方法,例如:
str.equals(str2) // 比较两个字符串是否相等
str.compareTo(str2) // 比较两个字符串的字典顺序

字符串格式化

String类中的format方法可以用于格式化字符串,例如:
String str = String.format("Hi, %s! You are %d years old.", "Tom", 18);

正则表达式

String类中的matches方法可以用于使用正则表达式检查字符串是否符合特定的模式,例如:

String str = "Hello, World!";
boolean result = str.matches(".World.");

以上是Java常用类String的基本知识点和用法。在应用程序中,String类的应用非常广泛,特别是在处理文本数据时。

8.2日期时间

日期和时间都被封装成了类,这些类都位于java.util和java.time包中。一些常用的日期时间类和方法:

1. java.util.Date
java.util.Date类表示日期和时间,它是存在于特定时间点的毫秒数的表示。Date对象可以通过System.currentTimeMillis()方法或者new Date()构造器来获取。
2.java.util.Calendar
Calendar类是一个抽象类,它用于处理日期和时间。通过Calendar.getInstance()方法可以获取当前时间的日历对象。Calendar提供了很多常用的方法,比如get()方法用于获取指定字段的值,如年、月、日等;set()方法用于设置指定字段的值;add()方法用于在指定字段上增加或减少某个数值;getTime()方法用于将Calendar对象转换为Date对象。
3.java.text.SimpleDateFormat
SimpleDateFormat类用于格式化日期和时间。类的构造器需要传入一个指定日期和时间格式的字符串,然后调用format()方法即可将日期格式化为指定格式的字符串,调用parse()方法可以将字符串解析为日期对象。
4.java.time.LocalDate、java.time.LocalTime、java.time.LocalDateTime
java.time包中的这三个类用于处理本地日期和时间。LocalDate类表示日期,LocalTime类表示时间,LocalDateTime类表示日期和时间。这些类提供了很多方法,比如now()方法可以获取当前的日期和时间,plus()方法可以在指定字段上增加或减少某个数值,with()方法可以设置指定字段的值,等等。
5.java.time.ZonedDateTime、java.time.OffsetDateTime、java.time.Duration
这些类用于处理时区、偏移量和时间差。ZonedDateTime类表示带有时区信息的日期和时间,OffsetDateTime类表示带有UTC偏移量的日期和时间,Duration类表示时间间隔。这些类也提供了很多方法,可以进行时间计算、解析格式化等操作。

除了上述类和方法,Java还提供了很多其他的日期和时间处理工具,比如java.sql.Date、java.sql.Time、java.sql.Timestamp等用于处理数据库中的日期和时间,以及java.util.TimeZone、java.time.ZoneId等用于处理时区信息。开发者可以根据具体需求选用适合的类和方法进行日期和时间处理。

9.集合类

数组定义后类型确定,长度固定,适合做个数和类型确定的场景。

集合类型可以不固定,大小是可变的,适合做个数不确定,且要做增删元素的场景。

注意:集合只能存储引用数据类型,如果要存储基本数据类型可选择包装类。

9.1Collection集合接口

Collection单列集合,每个元素只包含一个值,

Map双列集合,每个元素包含两个值,

 9.2list集合

ArrayList:底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素。
LinkedList 底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素。
Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素。


9.2.1ArrayList

有序、可重复、有索引

 加元素时,如果数组已满,则会创建一个更大的数组,将原数组中的元素复制到新数组中,然后添加新元素。这个过程称为扩容,ArrayList扩容的默认策略是将当前容量增加50%。(1.5倍)

当删除元素时,ArrayList中的元素并不会像链表那样链接在一起,而是通过将待删除元素之后的所有元素依次向左移动一个位置,填补被删除元素的位置。这个过程称为“数组的拷贝”。

优点:

1.可以随机访问,读取效率高。

2.可以动态增长,无需预先分配空间。

缺点:

1.删除元素时,需要执行数组的拷贝,效率较低。

2.插入元素时,如果数组需要扩容,效率较低。

3.数组所占空间通常比实际元素占用的空间大,浪费空间。

9.2.2LinekdList

有序、可重复、有索引

底层原理:

LinkedList是Java集合框架中的一个双向链表集合,其底层原理是使用链表来存储元素,每个元素都由一个包含了对其前驱节点和后继节点的引用的节点表示。由于每个节点记录了下一个节点的引用,因此可以通过访问一个节点来遍历整个链表。

LinkedList的特点包括:

  1. 随机访问元素效率较低:因为要从头开始循环,并且还需要沿着链表找到目标元素。

  2. 插入和删除元素效率较高:只需要改变前后节点的引用即可。

  3. 不支持同步:LinkedList并不是线程安全的。

LinkedList相对于其他集合类型的优势是能够快速的对集合进行增删操作, 而不需要对数组进行频繁的扩容。
在LinkedList中,集合的大小是通过一个整数变量来表示的,该变量指示集合中元素的数量,每个节点都包含一个存储元素的变量和指向前一个节点和后一个节点的引用。当向LinkedList中添加或删除元素时,该整数变量的值会相应地增加或减少。

拓展:

LinkedList是一种链表数据结构,不像数组那样使用连续的内存空间存储元素,而是使用节点组成的链表来存储元素。因此,LinkedList没有像数组那样可以通过索引直接访问元素。

LinkedList的每个节点都包含一个元素以及一个指向下一个节点的引用。要访问LinkedList中的元素,通常需要从头结点开始顺序遍历链表,直到找到目标节点。

为了简化链表的访问,Java中提供了List接口和其实现类LinkedList,支持像数组那样使用索引访问元素。但实际上,当使用LinkedList时,通过索引访问元素并不是高效的操作,因为在LinkedList中查找一个元素需要从头结点开始遍历链表,直到找到目标节点。

9.3set集合

9.3.1HashSet

无序,不重复,无索引

底层原理:

底层采用hash表存储数据,对于增删改查性能都较好。

JDK8之前,底层使用数组+链表组成

JDK8之后,底层使用数组+链表+红黑树组成

 扩容:

   红黑树讲解(手撕红黑树):http://t.csdn.cn/jLN50

9.3.2LinekdHashSet

9.3.3TreeSet

 TreeSet是一种有序集合,它使用红黑树作为底层数据结构实现。TreeSet底层采用红黑树的数据结构,具有以下特点:

元素自动排序:TreeSet中的元素会根据元素的自然顺序(通过实现Comparable接口)或比较器(通过传递比较器对象给TreeSet构造函数)进行排序,保证元素是有序的。
不允许重复元素:插入到TreeSet中的元素必须是唯一的,如果插入重复元素,则不会成功添加到集合中。
高效查找、插入、删除操作:由于底层使用红黑树,因此查找、插入和删除操作都可以在O(log n)时间内完成。
非线程安全:TreeSet不是线程安全的,如果多个线程并发访问TreeSet,需要手动同步访问。

TreeSet的使用与其他Java集合类相似,不同之处在于它使用红黑树来实现底层数据结构,所以它具有有序、不允许重复元素、高效查找、插入、删除等特点。在实际应用中,TreeSet通常用于需要排序、去重的场景,也可以通过自定义比较器来实现自定义排序方式。

 10.泛型

本质:

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时决定了。这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

为什么使用泛型:
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

(1)保证了类型的安全性。

在没有泛型之前,从集合中读取到的每一个对象都必须进行类型转换,如果不小心插入了错误的类型对象,在运行时的转换处理就会出错。

比如:没有泛型的情况下使用集合:

public static void noGeneric() {
ArrayList names = new ArrayList();
names.add("mikechen的互联网架构");
names.add(123); //编译正常
}

有泛型的情况下使用集合:

public static void useGeneric() {
ArrayList<String> names = new ArrayList<>();
names.add("mikechen的互联网架构");
names.add(123); //编译不通过
}

有了泛型后,定义好的集合names在编译的时候add(123)就会编译不通过。

相当于告诉编译器每个集合接收的对象类型是什么,编译器在编译期就会做类型检查,告知是否插入了错误类型的对象,使得程序更加安全,增强了程序的健壮性。

(2) 消除强制转换

泛型的一个附带好处是,消除源代码中的许多强制类型转换,这使得代码更加可读,并且减少了出错机会。
还是举例说明,以下没有泛型的代码段需要强制转换:

List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);

当重写为使用泛型时,代码不需要强制转换:

List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast

(3)避免了不必要的装箱、拆箱操作,提高程序的性能

在非泛型编程中,将筒单类型作为Object传递时会引起Boxing(装箱)和Unboxing(拆箱)操作,这两个过程都是具有很大开销的。引入泛型后,就不必进行Boxing和Unboxing操作了,所以运行效率相对较高,特别在对集合操作非常频繁的系统中,这个特点带来的性能提升更加明显。

泛型变量固定了类型,使用的时候就已经知道是值类型还是引用类型,避免了不必要的装箱、拆箱操作。

object a=1;//由于是object类型,会自动进行装箱操作。
 
int b=(int)a;//强制转换,拆箱操作。这样一去一来,当次数多了以后会影响程序的运行效率。

使用泛型之后

public static T GetValue<T>(T a)
 
{
  return a;
}
 
public static void Main()
 
{
  int b=GetValue<int>(1);//使用这个方法的时候已经指定了类型是int,所以不会有装箱和拆箱的操作。
}

(4)提高了代码的重用性。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
很抱歉,我无法回答关于2023年的问题,因为我无法提供未来的信息。但是,如果你对Java基础知识点有兴趣,我可以为你提供一些相关的信息。Java基础知识点包括数据类型、变量、运算符、控制流程、数组、字符串、面向对象编程等。你可以参考Java基础教程系列,其中包含了Java基础知识点、Java8新特性、Java集合、Java多线程等内容,可以帮助你轻松学习Java编程。\[1\]另外,Javac是Java编译器程序的一部分,负责将Java源代码编译成字节码文件,也就是class文件,供Java虚拟机(JVM)执行。\[2\]Java分为三个体系,分别是Java SE(标准版)、Java EE(企业版)和Java ME(微型版),每个体系都有不同的用途和应用领域。\[3\]希望这些信息对你有帮助! #### 引用[.reference_title] - *1* [java基础知识点](https://blog.csdn.net/guorui_java/article/details/120317300)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Java基础知识点整理,推荐收藏!](https://blog.csdn.net/weixin_42599558/article/details/114148399)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值