当前位置: 首页 > news >正文

Java 复习笔记 - 面向对象篇

文章目录

  • 一,面向对象概述
  • 二,类和对象
    • (一)类和对象的概述
    • (二)定义类的补充注意事项
  • 三,封装
  • 四,就近原则和this关键字
    • (一)就近原则
    • (二)this关键字
  • 五,构造方法
    • (一)构造方法的概述
    • (二)构造方法的作用
    • (二)构造方法的种类及各自的作用
    • (三)构造方法的注意事项
  • 六,标准的JavaBean类
  • 七,三种情况的对象内存图
    • (一)一个对象的内存图
    • (二)多个对象的内存图
    • (三)两个变量指向同一个对象的内存图
  • 八,基本数据类型和引用数据类型
    • (一)基本数据类型
    • (二)引用数据类型
  • 九,this的内存原理
  • 十,成员变量和局部变量
    • (一)成员变量
    • (二)局部变量
    • (三)成员变量和局部变量的区别
  • 十一,综合练习
    • (一)文字版格斗游戏
    • (二)对象数组练习
      • 1,对象数组1
      • 2,对象数组2
      • 3,对象数组3
      • 4,定义数组4
      • 5,对象数组5


在这里插入图片描述

一,面向对象概述

Java是一种面向对象的编程语言,面向对象是一种编程范式,它将程序设计看作是对象的集合,每个对象都有自己的状态和行为,并通过相互之间的消息传递来进行交互。

在面向对象的编程中,可以通过定义类来创建对象。类是一种模板或者蓝图,描述了对象的属性和行为。对象是类的实例化,它具有类所定义的属性和行为。

面向对象的编程有以下几个核心概念:

  1. 类(Class):类是对象的抽象,描述了一类具有相同属性和行为的对象。它定义了对象的结构和行为。

  2. 对象(Object):对象是类的实例化,是具体的实体,具有类定义的属性和行为。

  3. 属性(Attribute):属性是对象的状态,描述了对象的特征。

  4. 方法(Method):方法是对象的行为,描述了对象可以做什么。

  5. 封装(Encapsulation):封装是将对象的属性和方法封装在一起,隐藏内部实现细节,只对外提供必要的接口。

  6. 继承(Inheritance):继承是一种机制,允许创建一个新的类,从已有的类派生出来。子类继承父类的属性和方法,并可以添加自己特有的属性和方法。

  7. 多态(Polymorphism):多态是指同一个类的对象在不同的情况下表现出不同的行为。通过继承和方法重写实现了多态。

面向对象的编程具有封装性、继承性和多态性等特点,可以提高代码的可重用性、可维护性和可扩展性。它使得程序的设计更加模块化,更易于理解和修改。面向对象的编程在Java中得到了广泛应用,并且是Java语言的基本特性之一。

二,类和对象

(一)类和对象的概述

在Java中,类是面向对象编程的基本单位,它是对象的抽象描述,定义了对象的属性和行为。而对象是类的实例化,具体的实体,拥有类所定义的属性和行为。

类的定义通常包括以下几个部分:

  1. 类声明:使用关键字class来声明一个类,后面跟类的名称。

  2. 属性(成员变量):类的属性是描述对象特征的变量,可以是基本数据类型或者其他类的对象。属性定义在类的内部,可以通过访问修饰符来控制访问权限。

  3. 方法:类的方法是描述对象行为的函数,定义了对象可以做什么。方法也定义在类的内部,可以通过访问修饰符来控制访问权限。

  4. 构造方法:构造方法是一种特殊的方法,用于创建对象时进行初始化操作。构造方法的名称与类的名称相同,没有返回类型,并且可以重载。

  5. 访问修饰符:访问修饰符用于控制类、属性和方法的访问权限,包括public、protected、private和默认(不声明访问修饰符)。

  6. 类的关系:类与类之间可能存在继承关系、实现关系和关联关系,这些关系可以通过关键字extendsimplements和引用类型变量来表示。

对象是类的实例化,通过使用new关键字来创建类的对象。创建对象后,可以使用对象的引用变量来访问对象的属性和调用对象的方法。

例如,下面是一个简单的Java类和对象的示例:

// 定义一个类
class Person {// 属性String name;int age;// 构造方法public Person(String name, int age) {this.name = name;this.age = age;}// 方法public void sayHello() {System.out.println("Hello, my name is " + name + ", I'm " + age + " years old.");}
}// 创建对象并使用
public class Main {public static void main(String[] args) {// 创建Person对象Person person = new Person("John", 25);// 访问对象的属性System.out.println(person.name); // 输出:JohnSystem.out.println(person.age);  // 输出:25// 调用对象的方法person.sayHello(); // 输出:Hello, my name is John, I'm 25 years old.}
}

在上面的示例中,我们定义了一个Person类,它有两个属性(name和age)和一个方法(sayHello)。然后在主函数中,我们创建了一个Person对象,并通过对象的引用变量来访问对象的属性和调用对象的方法。

(二)定义类的补充注意事项

在Java中定义类时,除了遵循标准的JavaBean规范外,还有一些补充的注意事项:

  1. 类名的命名规范:类名应该采用驼峰命名法,首字母大写,例如"Person"。
  2. 文件名的命名规范:Java源文件的文件名应该与类名相同,并以.java为扩展名,例如"Person.java"。
  3. 包的命名规范:如果类位于一个包中,包名应该全部小写,并使用点(.)作为分隔符,例如"com.example"。包名应该反映类的层次结构和所属项目的唯一性。
  4. 访问修饰符的使用:类可以使用四种不同的访问修饰符:public、protected、default(即不写任何修饰符)和private。根据需要,选择适当的访问修饰符,以控制类的可见性和访问权限。
  5. 继承和接口实现:Java中的类可以继承其他类,并实现一个或多个接口。继承和接口实现通过关键字extends和implements来实现。
  6. 成员变量和局部变量的命名规范:成员变量应该使用驼峰命名法,首字母小写,例如"age"。局部变量应该使用驼峰命名法或者简短的命名,例如"i"。
  7. 类的设计原则:在定义类时,可以考虑一些设计原则,如单一职责原则、开放封闭原则、依赖倒置原则等,以提高代码的可维护性、可扩展性和可重用性。

在编写Java代码时,遵循这些注意事项可以使代码更加规范、易读和易于维护。同时,也可以提高代码的可移植性,并与其他开发人员的代码保持一致。

三,封装

在Java中,封装是一种面向对象编程的重要概念,它将类的属性和方法封装在一起,对外部使用者隐藏了类的内部实现细节,只暴露必要的接口供外部访问。

封装的目的是为了保护类的内部数据不被直接访问和修改,只能通过类提供的公开方法进行操作。这样可以防止外部代码对内部数据的错误修改和意外访问,提高代码的安全性和可维护性。

在Java中,通过访问修饰符来实现封装:

  1. private:私有访问修饰符,只能在当前类中访问,外部类无法直接访问。

  2. public:公共访问修饰符,可以在任何地方访问。

  3. protected:受保护的访问修饰符,可以在当前类、同一包内的类和子类中访问。

  4. 默认(不声明访问修饰符):默认访问修饰符,只能在当前包内访问。

通常情况下,类的属性都应该声明为私有(private)访问修饰符,然后通过公共(public)的setter和getter方法来访问和修改属性的值。这样可以在setter和getter方法中加入额外的逻辑操作,实现对属性的控制和保护。

下面是一个示例代码:

class Person {private String name;private int age;public String getName() {return name;}public void setName(String name) {// 可以在setter方法中添加逻辑判断if (name != null && !name.isEmpty()) {this.name = name;}}public int getAge() {return age;}public void setAge(int age) {// 可以在setter方法中添加逻辑判断if (age >= 0 && age <= 100) {this.age = age;}}
}public class Main {public static void main(String[] args) {Person person = new Person();person.setName("John");person.setAge(25);System.out.println(person.getName()); // 输出:JohnSystem.out.println(person.getAge());  // 输出:25}
}

在上面的示例中,Person类的属性name和age都被声明为私有(private)访问修饰符,外部无法直接访问。通过公共(public)的setter和getter方法来访问和修改属性的值,并在setter方法中加入了逻辑判断,保证属性值的有效性。

这样做的好处是,Person类的内部实现细节对外部是隐藏的,外部只能通过公共接口来操作属性,提高了代码的安全性和可维护性。同时,如果需要对属性的访问和修改进行额外的处理,只需要在setter和getter方法中添加相应的逻辑即可。

四,就近原则和this关键字

(一)就近原则

在Java中,就近原则(Lexical Scoping)是指在程序中变量的作用域是由它在代码中声明的位置决定的。当程序中存在同名的变量时,就近原则规定在给定作用域内,优先使用最近声明的变量。

例如,考虑以下示例代码:

public class Main {public static void main(String[] args) {int x = 5;{int x = 10;System.out.println(x);  // 输出:10}System.out.println(x);  // 输出:5}
}

在上面的代码中,有两个同名的变量x。第一个x是在main方法中声明的,第二个x是在一个代码块内部声明的。根据就近原则,当我们在代码块内部访问变量x时,应该使用最近声明的变量,即x = 10。而当我们在代码块外部访问变量x时,应该使用最近的作用域中声明的变量,即x = 5。

就近原则在Java中非常重要,它确保变量的作用域是可控的,并避免了命名冲突和变量混淆的问题。在编写代码时,我们应该养成良好的命名习惯,避免使用相同的变量名,以免造成误解和错误。同时,合理使用代码块和方法等,可以控制变量的作用域,遵循就近原则,使代码更加清晰易懂。

(二)this关键字

在Java中,this是一个关键字,它代表当前对象的引用。this关键字可以在类的成员方法中使用,用于引用当前对象的成员变量和成员方法。

使用this关键字可以解决以下两种常见的问题:

  1. 解决命名冲突:当成员变量与方法参数或局部变量同名时,使用this关键字可以明确指定要引用的是成员变量还是方法参数或局部变量。例如:
public class Person {private String name;public void setName(String name) {this.name = name;}
}// 使用示例
Person person = new Person();
person.setName("John");

在上面的例子中,setName方法的参数名是name,而成员变量也是name。为了解决命名冲突,我们使用this关键字来引用成员变量,即this.name = name。

  1. 在构造方法中调用其他构造方法:在一个类中,可以定义多个构造方法(重载),当我们在一个构造方法中调用其他构造方法时,可以使用this关键字。例如:
public class Person {private String name;private int age;public Person(String name) {this.name = name;}public Person(String name, int age) {this(name);  // 调用另一个构造方法this.age = age;}
}// 使用示例
Person person = new Person("John", 25);

在上面的例子中,第二个构造方法调用了第一个构造方法,使用this(name)的方式传递name参数,这样可以避免代码的重复。

总之,this关键字在Java中用于引用当前对象的成员变量和成员方法,并且可以在构造方法中调用其他构造方法。它的使用可以帮助解决命名冲突和代码重复的问题。

五,构造方法

(一)构造方法的概述

构造方法(Constructor)是一种特殊的方法,用于创建对象并初始化对象的属性。在Java中,每个类都可以有一个或多个构造方法。

构造方法的概述如下:

  1. 构造方法的名称必须与类名完全相同,且没有返回类型(包括void)。
  2. 构造方法可以有零个或多个参数,用于接收外部传入的值。
  3. 构造方法可以重载,即一个类可以有多个构造方法,只要它们的参数列表不同。
  4. 如果类没有显式定义构造方法,系统会自动提供一个默认的无参构造方法。但如果在类中定义了带参数的构造方法,系统不会自动提供默认构造方法,需要手动定义。
  5. 构造方法可以有访问修饰符,如public、protected、private或默认(即没有修饰符)。根据需要,可以选择适当的访问修饰符来控制构造方法的访问权限。
  6. 构造方法通常用于在创建对象时进行属性的初始化。在构造方法中,可以使用传入的参数对对象的属性进行赋值。
  7. 构造方法在使用new关键字创建对象时被调用,创建对象并分配内存空间。构造方法会在对象创建完成后立即执行。
  8. 构造方法不能通过对象来调用,只能通过new关键字来调用。
  9. 构造方法可以使用this关键字来调用同一个类中的其他构造方法,称为构造方法链。通过构造方法链,可以在创建对象时使用不同的构造方法来进行属性初始化。

构造方法的主要作用是初始化对象的属性,并提供不同的方式来创建对象。合理地使用构造方法可以确保对象的属性被正确初始化,并满足不同场景下的需求。

(二)构造方法的作用

Java构造方法是一种特殊的方法,它的作用是用于创建对象并初始化对象的属性。它的名称必须与类名相同,并且没有返回类型(包括void)。构造方法在使用new关键字时自动调用,用于在内存中分配对象的空间,并对对象的属性进行初始化。

构造方法的作用包括:

  1. 创建对象:构造方法用于在内存中创建对象的实例。当使用new关键字创建对象时,系统会自动调用对应类的构造方法,通过构造方法分配对象所需的内存空间。

  2. 初始化对象属性:构造方法可以对对象的属性进行初始化,为对象的属性赋予初始值。通过在构造方法中设置参数,可以在创建对象时为属性传递初始值。

  3. 提供默认构造方法:如果类没有显式定义构造方法,系统会自动提供一个默认的无参构造方法。默认构造方法可以在创建对象时进行调用。如果类中有自定义的构造方法,但没有提供无参构造方法,那么在创建对象时如果没有传递参数,编译器会报错。

  4. 初始化对象的状态:构造方法可以在创建对象时对对象的状态进行初始化,例如设置对象的初始状态、连接数据库等操作。

  5. 控制对象的创建过程:通过构造方法的重载和访问修饰符的使用,可以控制对象的创建过程,限制对象的访问权限等。

总结来说,构造方法在创建对象时起到了至关重要的作用,它不仅用于分配对象的内存空间,还可以对对象的属性进行初始化,提供默认构造方法,初始化对象的状态,以及控制对象的创建过程。构造方法在类的定义中起到了重要的作用,是面向对象编程中的一个基本概念。

(二)构造方法的种类及各自的作用

在Java中,构造方法可以分为以下几种类型:

  1. 默认构造方法(无参构造方法):如果类没有显式定义构造方法,系统会自动提供一个默认的无参构造方法。默认构造方法没有任何参数,并且什么都不做。它的作用是创建对象并分配内存空间,但不对对象的属性进行初始化。

  2. 带参数的构造方法:带参数的构造方法可以接受一个或多个参数,用于在创建对象时传递初始值。通过在构造方法中设置参数,可以对对象的属性进行初始化。带参数的构造方法可以根据不同的参数组合进行重载,以满足不同的需求。

  3. 重载构造方法:在一个类中,可以定义多个构造方法,只要它们的参数列表不同。重载构造方法的作用是提供多种创建对象的方式,根据不同的参数组合来初始化对象的属性。

  4. 私有构造方法:私有构造方法是指访问修饰符为private的构造方法,它仅在本类中可见,外部无法直接访问。私有构造方法的作用是限制对象的创建,通常用于实现单例模式或工具类,确保只能通过特定的方式创建对象。

  5. 构造方法链:在一个构造方法中,可以使用this关键字调用同一个类中的其他构造方法,称为构造方法链。构造方法链的作用是在创建对象时,可以通过不同的构造方法来进行属性初始化,避免代码重复。

总结来说,构造方法的种类包括默认构造方法、带参数的构造方法、重载构造方法、私有构造方法和构造方法链。它们的作用分别是创建对象并分配内存空间、对对象的属性进行初始化、提供多种创建对象的方式、限制对象的创建、以及在构造方法中调用其他构造方法来避免代码重复。不同的构造方法可以根据需求灵活地使用。

(三)构造方法的注意事项

在使用构造方法时,需要注意以下几点:

  1. 构造方法与类名相同:构造方法的名称必须与类名完全相同,并且没有返回类型(包括void)。如果构造方法的名称与类名不一致,它会被当作普通方法,而不是构造方法。

  2. 构造方法的重载:一个类可以有多个构造方法,只要它们的参数列表不同。构造方法的重载可以提供多种创建对象的方式,根据不同的参数组合进行初始化。

  3. 默认构造方法的提供:如果类没有显式定义构造方法,系统会自动提供一个默认的无参构造方法。但是,如果在类中定义了带参数的构造方法,系统不会自动提供默认构造方法,需要手动定义。

  4. 构造方法的访问修饰符:构造方法可以使用public、protected、private或默认(即没有修饰符)这些访问修饰符。根据需要,可以选择适当的访问修饰符来控制构造方法的访问权限。

  5. 构造方法的调用:通过使用new关键字来调用构造方法,创建对象并分配内存空间。构造方法可以在创建对象时进行属性的初始化,但不能在创建对象后再次调用。

  6. 构造方法的链式调用:在一个构造方法中,可以使用this关键字调用同一个类中的其他构造方法,称为构造方法链。通过构造方法链,可以在创建对象时使用不同的构造方法来进行属性初始化。

  7. 私有构造方法的使用:私有构造方法的访问权限仅限于类内部,外部无法直接访问。私有构造方法通常用于实现单例模式或工具类,限制对象的创建。

  8. 构造方法不能被继承:构造方法不会被继承,子类不能直接调用父类的构造方法。子类中可以使用super关键字来调用父类的构造方法,用于初始化继承自父类的属性。

以上是在使用构造方法时需要注意的几点。合理地使用构造方法可以正确初始化对象的属性,并控制对象的创建和访问权限。

六,标准的JavaBean类

在Java中,标准的JavaBean类是一种遵循特定规范的类,用于封装数据并提供访问和操作这些数据的方法。JavaBean类通常用于在不同层之间传递数据,例如在Web开发中存储和传递表单数据。

标准的JavaBean类应该满足以下要求:

  1. 类必须具有一个公共的无参构造方法:这允许使用默认的构造方法实例化JavaBean对象。
  2. 属性必须是私有的:JavaBean类通常将属性声明为私有,并通过公共的getter和setter方法提供对属性的访问。
  3. 提供公共的getter和setter方法:JavaBean类应该为每个属性提供公共的getter和setter方法,以允许其他类访问和修改属性的值。
  4. 实现Serializable接口(可选):如果JavaBean类需要被序列化或者需要在网络上传输,可以实现Serializable接口。

以下是一个示例的标准JavaBean类:

public class Person implements Serializable {private String name;private int age;public Person() {// 默认的无参构造方法}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

在上面的示例中,Person类是一个标准的JavaBean类。它满足了以下要求:拥有一个公共的无参构造方法、私有的属性、公共的getter和setter方法,并可选择实现Serializable接口。

标准的JavaBean类可以被用于各种用途,例如在Spring框架中作为数据传输对象(DTO),在Hibernate中作为持久化实体类等。通过遵循JavaBean规范,可以更好地封装和管理数据,并提供对数据的访问和操作。

七,三种情况的对象内存图

(一)一个对象的内存图

下面是一个Java对象的内存图示例:

+---------------------------+
|                           |
|       Object Header       |
|                           |
+---------------------------+
|     Instance Variables    |
|                           |
+---------------------------+
|                           |
|       Padding             |
|                           |
+---------------------------+

Java对象的内存图主要包括以下几个部分:

  1. Object Header:对象头,包含一些与对象相关的元数据,如对象的哈希码、锁状态、GC标记等信息。
  2. Instance Variables:实例变量,存储对象的属性值。每个实例变量占用一定的内存空间。
  3. Padding:内存对齐填充,用于保持对象的对齐性和性能优化。

在内存中,Java对象被分配在堆(Heap)中。当使用new关键字创建对象时,会在堆中分配一块连续的内存空间来存储对象的实例变量。对象头和内存对齐填充不计入对象的实例变量空间。

实例变量可以是基本数据类型(如int、double等)或者引用类型(如String、数组等)。对于引用类型的实例变量,实际存储的是对对象的引用,而不是对象本身。

通过给对象的实例变量赋值,可以修改对象的属性值。不同的对象拥有独立的内存空间,因此它们的属性可以独立地进行修改和访问。

在Java中,对对象的内存管理由垃圾回收器(Garbage Collector)负责。当对象不再被引用时,垃圾回收器会自动回收对象所占用的内存空间,以供后续的对象分配使用。

(二)多个对象的内存图

下面是一个Java程序中多个对象的内存图示例:

+------------------------------+
|        Object Header         |
+------------------------------+
|      Instance Variables      |
+------------------------------+
|        Padding               |
+------------------------------++------------------------------+
|        Object Header         |
+------------------------------+
|      Instance Variables      |
+------------------------------+
|        Padding               |
+------------------------------+...

每个Java对象都有自己的内存图,对象之间互相独立存储,并且拥有相同的结构。每个对象的内存图都包含了对象头、实例变量和内存对齐填充。

在内存中,每个对象都被分配在堆(Heap)中的不同的内存空间上。当创建多个对象时,Java会在堆中分配多个连续的内存块来存储每个对象的实例变量。每个对象的实例变量可以独立地进行修改和访问。

不同对象的内存图之间可以有共享的实例变量,即多个对象的同一实例变量指向同一个内存位置。这通常发生在引用类型的实例变量中,当多个对象引用同一个对象时,它们的实例变量指向同一个对象的引用。

Java中的垃圾回收器(Garbage Collector)会自动回收不再被引用的对象所占用的内存空间。当对象不再被引用时,垃圾回收器会将其标记为垃圾,并在适当的时候回收它们占用的内存,以供后续的对象分配使用。

总结来说,多个对象的内存图在堆中是独立分配的,每个对象拥有自己的对象头、实例变量和内存对齐填充。对象之间可以共享引用类型的实例变量,而垃圾回收器会负责回收不再被引用的对象。

(三)两个变量指向同一个对象的内存图

下面是一个Java程序中两个变量指向同一个对象的内存图示例:

+------------------------+
|      Variable 1        |
+------------------------+
|     Memory Address     |
+------------------------+|v+------------------------+
|      Variable 2        |
+------------------------+
|     Memory Address     |
+------------------------+|v+------------------------------+
|        Object Header         |
+------------------------------+
|      Instance Variables      |
+------------------------------+
|        Padding               |
+------------------------------+

在上面的示例中,Variable 1Variable 2是两个Java变量,它们都存储了同一个对象的内存地址。这意味着两个变量实际上指向了同一个对象。

在堆中,有一个对象被分配了内存空间,它有一个对象头和实例变量。Variable 1Variable 2存储了该对象在内存中的地址,通过这个地址,它们可以共享访问该对象的实例变量。

修改一个变量所指向的对象的状态,将会影响到通过另一个变量访问的对象状态。这是因为两个变量指向的是同一个对象,它们共享同一个对象的内存空间。

在Java中,对象的引用是一个指向对象的内存地址的值,而不是对象本身。这允许多个变量引用同一个对象,从而实现对象之间的共享和相互影响。垃圾回收器会负责回收不再被引用的对象所占用的内存空间,但只有当所有引用该对象的变量都不再引用它时,对象才会被认为是不再被引用的垃圾。

八,基本数据类型和引用数据类型

(一)基本数据类型

Java基本数据类型是指Java语言中的基本数据类型,它们是预定义的,不是由类定义的。Java的基本数据类型包括以下几种:

  1. byte:表示8位有符号整数,范围为-128到127。
  2. short:表示16位有符号整数,范围为-32,768到32,767。
  3. int:表示32位有符号整数,范围为-231到231-1。
  4. long:表示64位有符号整数,范围为-263到263-1。
  5. float:表示32位单精度浮点数,范围为正负3.40282347e+38F(有效位数为6-7位)。
  6. double:表示64位双精度浮点数,范围为正负1.79769313486231570e+308(有效位数为15位)。
  7. boolean:表示布尔值,只有两个取值:true和false。
  8. char:表示16位Unicode字符。

基本数据类型在内存中占用固定大小的空间,它们被直接存储在栈中,而不是在堆中(与引用类型不同)。每种基本数据类型都有对应的包装类,用于提供与该数据类型相关的操作和方法。

基本数据类型的主要优点是效率高,占用的内存空间较小。然而,它们无法直接调用方法,因为它们不是对象,所以需要使用包装类来操作基本数据类型的一些特殊需求,例如进行比较、转换等操作。

(二)引用数据类型

Java引用数据类型是指Java语言中的非基本数据类型(也称为对象类型),它们是由类或接口创建的。Java的引用数据类型包括以下几种:

  1. 类(Class):引用数据类型最常见的形式就是类。类是一种自定义的数据类型,它可以包含属性(成员变量)和方法(成员方法),并可以创建该类的对象。
  2. 接口(Interface):接口是一种定义一组方法签名的引用数据类型,它可以被类实现,从而使类具有接口中定义的行为。
  3. 数组(Array):数组是一种用来存储相同类型数据的容器,可以存储基本数据类型或引用数据类型的元素。
  4. 枚举(Enum):枚举是一种特殊的引用数据类型,它限制变量只能取特定的值,这些值在枚举类型中预先定义。
  5. 字符串(String):字符串是一种引用数据类型,它表示一串字符序列。在Java中,字符串是不可变的,即一旦创建,就不能被修改。

引用数据类型的对象存储在堆内存中,而引用(变量)本身存储在栈内存中。与基本数据类型不同,引用数据类型的变量可以调用方法,并且可以通过引用来操作对象的属性和行为。当对象没有被任何引用变量引用时,它将成为垃圾,并由Java的垃圾回收机制自动回收内存。

九,this的内存原理

在Java中,关键字"this"代表当前对象的引用。它可以在对象的方法中使用,用来访问当前对象的成员变量和成员方法。

内存原理方面,每当我们创建一个对象时,Java会在堆内存中为该对象分配一块内存空间,并将对象的成员变量存储在这个内存空间中。同时,Java会为这个对象创建一个指向该内存空间的引用。

当我们在对象的方法中使用"this"关键字时,编译器会将"this"关键字解析为对当前对象的引用。具体地说,编译器会通过将"this"关键字作为方法参数传递给方法,从而使方法能够访问当前对象的成员变量和成员方法。

在内存中,每个线程都会有一个栈,称为"线程栈"。当一个方法被调用时,Java会在当前线程的栈中创建一个"栈帧",栈帧包含了方法的局部变量、方法参数以及方法返回值等信息。此时,"this"关键字被存储在栈帧中的一个特殊位置,用于指向当前对象的内存空间。

总结起来,Java中的"this"关键字是一个指向当前对象的引用,它在对象的方法中使用。它的内存原理是通过在当前线程的栈帧中存储一个指向当前对象的引用,从而使方法能够访问当前对象的成员变量和成员方法。

十,成员变量和局部变量

(一)成员变量

Java中的成员变量也称为实例变量,是定义在类中的变量。它们是属于对象的,每个对象都有自己的一份成员变量副本,用来存储对象的状态和属性。

成员变量有以下特点:

  1. 作用域:成员变量的作用域是整个类,可以在类的任何方法、构造方法、代码块中访问。
  2. 生命周期:成员变量的生命周期与对象的生命周期一致。当对象被创建时,成员变量就分配相应的内存空间;当对象被销毁时,成员变量的内存空间也被释放。
  3. 默认值:如果没有显式赋值,成员变量会有默认值。例如,整型的成员变量默认值为0,布尔型的成员变量默认值为false。
  4. 访问性:成员变量可以使用访问修饰符进行限制,例如public、private、protected等。根据访问修饰符的不同,成员变量可以被不同的类和方法访问。

成员变量通常用来存储对象的属性和状态信息,可以在类的各个方法中使用和修改。它们在类中声明,但在方法中不进行初始化赋值,而是在对象创建时随着对象的初始化而赋予初始值。

(二)局部变量

Java中的局部变量是在方法、构造方法或代码块中声明的变量。它们只在声明的方法、构造方法或代码块中可见,并且只在方法、构造方法或代码块的执行期间存在。

局部变量有以下特点:

  1. 作用域:局部变量的作用域限定在声明它的方法、构造方法或代码块中。超出该作用域,局部变量将不再可见。
  2. 生命周期:局部变量的生命周期与方法、构造方法或代码块的执行周期一致。在方法、构造方法或代码块执行结束后,局部变量的内存空间将被释放。
  3. 必须显式初始化:局部变量在使用前必须进行显式初始化。否则,编译器会报错。
  4. 不具有默认值:与成员变量不同,局部变量没有默认值。在使用前必须赋值。

局部变量通常用于临时存储和处理方法、构造方法或代码块中的数据。它们在方法、构造方法或代码块内部声明,只在所声明的方法、构造方法或代码块中有效。一旦执行离开该方法、构造方法或代码块,局部变量的内存空间会被释放。

(三)成员变量和局部变量的区别

Java中的成员变量和局部变量是两种不同类型的变量,它们在作用域、生命周期和访问性等方面有所不同。

  1. 作用域:

    • 成员变量(也称为实例变量)是定义在类中、方法之外的变量。它的作用域是整个类,可以被类中的所有方法访问。
    • 局部变量是定义在方法、构造方法、代码块中的变量。它的作用域只在声明的方法中,只能在方法内部访问。
  2. 生命周期:

    • 成员变量的生命周期与对象的生命周期一致。当对象被创建时,成员变量就分配相应的内存空间;当对象被销毁时,成员变量的内存空间也被释放。
    • 局部变量的生命周期在方法执行时开始,在方法执行结束后结束。当方法执行完毕时,局部变量的内存空间也会被释放。
  3. 初始化值:

    • 成员变量可以有默认值,如果没有显式赋值,它们会根据数据类型而有所不同。例如,整型的成员变量默认值为0,布尔型的成员变量默认值为false。
    • 局部变量没有默认值,必须在使用之前显式赋值,否则会编译错误。
  4. 访问性:

    • 成员变量可以使用访问修饰符进行限制,例如public、private、protected等。根据访问修饰符的不同,成员变量可以被不同的类和方法访问。
    • 局部变量没有访问修饰符,它们只能在声明的方法内部访问。

总结起来,成员变量是定义在类中和方法之外的变量,作用域是整个类,生命周期与对象一致;而局部变量是定义在方法、构造方法和代码块中的变量,作用域只在声明的方法内部,生命周期在方法执行期间。

十一,综合练习

(一)文字版格斗游戏

需求:格斗游戏,每个游戏角色的姓名,血量,都不相同,在选定人物的时候(new对象的时候),这些信息就应该被确定下来。

下面是一个使用面向对象的Java代码示例,实现带有姓名和血量的文字版格斗游戏:

import java.util.Random;
import java.util.Scanner;public class FightGame {private static final int MAX_HEALTH = 100;private static final int MAX_ATTACK_DAMAGE = 20;public static void main(String[] args) {Scanner scanner = new Scanner(System.in);Random random = new Random();System.out.println("欢迎来到文字版格斗游戏!");System.out.print("请输入你的角色名字:");String playerName = scanner.nextLine();System.out.print("请输入你的角色生命值(1-" + MAX_HEALTH + "):");int playerHealth = scanner.nextInt();Player player = new Player(playerName, playerHealth);Enemy enemy = new Enemy("敌人", MAX_HEALTH);System.out.println("你的角色名字是:" + player.getName());System.out.println("你的初始生命值为:" + player.getHealth());System.out.println("敌人的生命值为:" + enemy.getHealth());System.out.println("游戏开始!");while (player.getHealth() > 0 && enemy.getHealth() > 0) {System.out.print("请输入你的攻击力(1-" + MAX_ATTACK_DAMAGE + "):");int playerAttack = scanner.nextInt();int enemyAttack = random.nextInt(MAX_ATTACK_DAMAGE) + 1;enemy.takeDamage(playerAttack);player.takeDamage(enemyAttack);System.out.println("你对敌人造成了" + playerAttack + "点伤害!");System.out.println("敌人对你造成了" + enemyAttack + "点伤害!");System.out.println("你的剩余生命值为:" + player.getHealth());System.out.println("敌人的剩余生命值为:" + enemy.getHealth());}if (player.getHealth() <= 0) {System.out.println("你输了游戏!");} else {System.out.println("你赢了游戏!");}System.out.println("游戏结束!");}
}class Character {private String name;private int health;public Character(String name, int health) {this.name = name;this.health = health;}public void takeDamage(int damage) {health -= damage;if (health < 0) {health = 0;}}public String getName() {return name;}public int getHealth() {return health;}
}class Player extends Character {public Player(String name, int health) {super(name, health);}
}class Enemy extends Character {public Enemy(String name, int health) {super(name, health);}
}

在这个示例中,我们创建了一个Character类作为角色的基类,其中包含了姓名和血量两个属性,以及受伤的方法。Player类和Enemy类继承自Character类,分别表示玩家和敌人角色。在实例化Player和Enemy对象时,需要传入姓名和血量参数来初始化对象。

在主方法中,我们首先根据玩家输入的姓名和血量创建了Player对象和Enemy对象。然后,通过调用对象的方法来获取和修改角色的属性。游戏过程中,玩家和敌人轮流攻击,并根据攻击造成的伤害来更新角色的血量。最后,根据玩家和敌人的血量判断游戏的胜负,并输出相应的结果。

(二)对象数组练习

1,对象数组1

需求:定义数组存储3个商品对象。
商品的属性:商品的id,名字,价格,库存。
创建三个商品对象,并把商品对象存入到数组当中。

下面是一个使用面向对象的Java代码示例,实现创建商品对象并存储到对象数组中:

import java.util.Scanner;public class ProductArray {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);Product[] products = new Product[3];for (int i = 0; i < products.length; i++) {System.out.println("请输入第" + (i + 1) + "个商品的信息:");System.out.print("商品ID:");int id = scanner.nextInt();System.out.print("商品名称:");String name = scanner.next();System.out.print("商品价格:");double price = scanner.nextDouble();System.out.print("商品库存:");int stock = scanner.nextInt();Product product = new Product(id, name, price, stock);products[i] = product;}System.out.println("三个商品的信息如下:");for (int i = 0; i < products.length; i++) {System.out.println("商品ID:" + products[i].getId());System.out.println("商品名称:" + products[i].getName());System.out.println("商品价格:" + products[i].getPrice());System.out.println("商品库存:" + products[i].getStock());System.out.println("---------------------------");}}
}class Product {private int id;private String name;private double price;private int stock;public Product(int id, String name, double price, int stock) {this.id = id;this.name = name;this.price = price;this.stock = stock;}public int getId() {return id;}public String getName() {return name;}public double getPrice() {return price;}public int getStock() {return stock;}
}

在这个示例中,我们创建了一个Product类来表示商品,包含了商品的ID、名称、价格和库存四个属性。在ProductArray类的主方法中,我们首先定义了一个长度为3的Product数组用于存储商品对象。

然后,通过循环从用户输入中获取每个商品的信息,并使用构造方法创建Product对象。将每个创建的Product对象存储到数组中。

最后,通过遍历数组,将每个商品对象的属性打印出来展示给用户。

2,对象数组2

需求:定义数组存储3部汽车对象。
汽车的属性:品牌,价格,颜色。
创建三个汽车对象,数据通过键盘录入而来,并把数据存入到数组当中。

下面是一个使用面向对象的Java代码示例,实现创建汽车对象并存储到对象数组中:

import java.util.Scanner;public class CarArray {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);Car[] cars = new Car[3];for (int i = 0; i < cars.length; i++) {System.out.println("请输入第" + (i + 1) + "部汽车的信息:");System.out.print("汽车品牌:");String brand = scanner.next();System.out.print("汽车价格:");double price = scanner.nextDouble();System.out.print("汽车颜色:");String color = scanner.next();Car car = new Car(brand, price, color);cars[i] = car;}System.out.println("三部汽车的信息如下:");for (int i = 0; i < cars.length; i++) {System.out.println("汽车品牌:" + cars[i].getBrand());System.out.println("汽车价格:" + cars[i].getPrice());System.out.println("汽车颜色:" + cars[i].getColor());System.out.println("---------------------------");}}
}class Car {private String brand;private double price;private String color;public Car(String brand, double price, String color) {this.brand = brand;this.price = price;this.color = color;}public String getBrand() {return brand;}public double getPrice() {return price;}public String getColor() {return color;}
}

在这个示例中,我们创建了一个Car类来表示汽车,包含了汽车的品牌、价格和颜色三个属性。在CarArray类的主方法中,我们首先定义了一个长度为3的Car数组用于存储汽车对象。

然后,通过循环从用户输入中获取每辆汽车的信息,并使用构造方法创建Car对象。将每个创建的Car对象存储到数组中。

最后,通过遍历数组,将每辆汽车对象的属性打印出来展示给用户。

3,对象数组3

需求:定义数组存储3部手机对象。
手机的属性:品牌,价格,颜色。
要求:计算出三部手机的平均价格。

下面是一个使用面向对象的Java代码示例,实现创建手机对象并计算平均价格:

import java.util.Scanner;public class PhoneArray {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);Phone[] phones = new Phone[3];for (int i = 0; i < phones.length; i++) {System.out.println("请输入第" + (i + 1) + "部手机的信息:");System.out.print("手机品牌:");String brand = scanner.next();System.out.print("手机价格:");double price = scanner.nextDouble();System.out.print("手机颜色:");String color = scanner.next();Phone phone = new Phone(brand, price, color);phones[i] = phone;}double total = 0;for (int i = 0; i < phones.length; i++) {total += phones[i].getPrice();}double average = total / phones.length;System.out.println("三部手机的平均价格为:" + average);}
}class Phone {private String brand;private double price;private String color;public Phone(String brand, double price, String color) {this.brand = brand;this.price = price;this.color = color;}public String getBrand() {return brand;}public double getPrice() {return price;}public String getColor() {return color;}
}

在这个示例中,我们创建了一个Phone类来表示手机,包含了手机的品牌、价格和颜色三个属性。在PhoneArray类的主方法中,我们首先定义了一个长度为3的Phone数组用于存储手机对象。

然后,通过循环从用户输入中获取每部手机的信息,并使用构造方法创建Phone对象。将每个创建的Phone对象存储到数组中。

接着,我们使用一个变量total来累加所有手机的价格。然后,通过除以数组的长度来计算平均价格。

最后,我们将计算出的平均价格打印出来展示给用户。

4,定义数组4

需求:定义数组存储4个女朋友对象。
女朋友的属性:姓名,年龄,性别,爱好。
要求1:计算出四个女朋友的平均年龄。
要求2:统计年龄比平均值低的女朋友有几个?并把她们的所有信息打印出来。

下面是一个使用面向对象的Java代码示例,实现创建女朋友对象并计算平均年龄,以及统计年龄低于平均值的女朋友数量并打印她们的信息:

import java.util.Scanner;public class GirlfriendArray {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);Girlfriend[] girlfriends = new Girlfriend[4];for (int i = 0; i < girlfriends.length; i++) {System.out.println("请输入第" + (i + 1) + "个女朋友的信息:");System.out.print("姓名:");String name = scanner.next();System.out.print("年龄:");int age = scanner.nextInt();System.out.print("性别:");String gender = scanner.next();System.out.print("爱好:");String hobby = scanner.next();Girlfriend girlfriend = new Girlfriend(name, age, gender, hobby);girlfriends[i] = girlfriend;}int totalAge = 0;for (int i = 0; i < girlfriends.length; i++) {totalAge += girlfriends[i].getAge();}int averageAge = totalAge / girlfriends.length;System.out.println("四个女朋友的平均年龄为:" + averageAge);int count = 0;System.out.println("年龄低于平均值的女朋友有:");for (int i = 0; i < girlfriends.length; i++) {if (girlfriends[i].getAge() < averageAge) {count++;System.out.println(girlfriends[i].toString());}}System.out.println("共有" + count + "个女朋友的年龄低于平均值。");}
}class Girlfriend {private String name;private int age;private String gender;private String hobby;public Girlfriend(String name, int age, String gender, String hobby) {this.name = name;this.age = age;this.gender = gender;this.hobby = hobby;}public String getName() {return name;}public int getAge() {return age;}public String getGender() {return gender;}public String getHobby() {return hobby;}@Overridepublic String toString() {return "姓名:" + name + ",年龄:" + age + ",性别:" + gender + ",爱好:" + hobby;}
}

在这个示例中,我们创建了一个Girlfriend类来表示女朋友,包含了女朋友的姓名、年龄、性别和爱好四个属性。在GirlfriendArray类的主方法中,我们首先定义了一个长度为4的Girlfriend数组用于存储女朋友对象。

然后,通过循环从用户输入中获取每个女朋友的信息,并使用构造方法创建Girlfriend对象。将每个创建的Girlfriend对象存储到数组中。

接着,我们使用一个变量totalAge来累加所有女朋友的年龄。然后,通过除以数组的长度来计算平均年龄。

最后,我们遍历数组,判断每个女朋友的年龄是否低于平均值,如果是,则将其打印出来并统计数量。

同时,我们在Girlfriend类中重写了toString方法,用于返回女朋友对象的信息。

5,对象数组5

需求:定义一个长度为3的数组,数组存储1~3名学生对象作为初始化数据,学生对象的学号,姓名各不相同。
学生的属性:学号,姓名,年龄。
要求1:再次添加一个学生对象,并在添加的时候进行学号的唯一判断。
要求2:添加完毕之后,遍历所有学生信息。
要求3:通过id删除学生信息,如果存在,则删除,如果不存在则表示删除失败。
要求4:删除完毕之后,遍历所有学生信息。
要求5:查询数组id为 “2023002” 的学生,如果存在,则将他的年龄+1岁。

下面是一个使用面向对象的Java代码示例,实现创建学生对象数组,并实现添加、删除、遍历和查询学生信息的功能:

import java.util.Scanner;public class StudentArray {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);Student[] students = new Student[3];students[0] = new Student("2023001", "张三", 18);students[1] = new Student("2023002", "李四", 19);students[2] = new Student("2023003", "王五", 20);System.out.println("当前学生信息如下:");printStudents(students);System.out.println("请输入要添加的学生信息:");System.out.print("学号:");String id = scanner.next();System.out.print("姓名:");String name = scanner.next();System.out.print("年龄:");int age = scanner.nextInt();boolean isExist = false;for (int i = 0; i < students.length; i++) {if (students[i].getId().equals(id)) {isExist = true;break;}}if (isExist) {System.out.println("学号已存在,添加失败!");} else {Student newStudent = new Student(id, name, age);Student[] newStudents = new Student[students.length + 1];for (int i = 0; i < students.length; i++) {newStudents[i] = students[i];}newStudents[newStudents.length - 1] = newStudent;students = newStudents;System.out.println("添加成功!");System.out.println("当前学生信息如下:");printStudents(students);}System.out.print("请输入要删除的学生学号:");String deleteId = scanner.next();boolean isDeleted = false;for (int i = 0; i < students.length; i++) {if (students[i].getId().equals(deleteId)) {students[i] = null;isDeleted = true;break;}}if (isDeleted) {Student[] newStudents = new Student[students.length - 1];int newIndex = 0;for (int i = 0; i < students.length; i++) {if (students[i] != null) {newStudents[newIndex] = students[i];newIndex++;}}students = newStudents;System.out.println("删除成功!");System.out.println("当前学生信息如下:");printStudents(students);} else {System.out.println("学号不存在,删除失败!");}System.out.print("请输入要查询的学生学号:");String queryId = scanner.next();boolean isFound = false;for (int i = 0; i < students.length; i++) {if (students[i].getId().equals(queryId)) {students[i].setAge(students[i].getAge() + 1);isFound = true;break;}}if (isFound) {System.out.println("年龄已加1岁!");System.out.println("当前学生信息如下:");printStudents(students);} else {System.out.println("学号不存在!");}}public static void printStudents(Student[] students) {for (int i = 0; i < students.length; i++) {System.out.println(students[i].toString());}}
}class Student {private String id;private String name;private int age;public Student(String id, String name, int age) {this.id = id;this.name = name;this.age = age;}public String getId() {return id;}public String getName() {return name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "学号:" + id + ",姓名:" + name + ",年龄:" + age;}
}

在这个示例中,我们创建了一个Student类来表示学生,包含了学生的学号、姓名和年龄三个属性。在StudentArray类的主方法中,我们首先定义了一个长度为3的Student数组,并初始化了数组的前3个元素。

然后,我们通过输入获取要添加的学生信息,并进行学号的唯一判断。如果学号已存在,则添加失败;否则,创建一个新的Student对象,并将其添加到新的数组中。

接着,我们获取要删除的学生学号,并进行判断。如果学号存在,则将对应的数组元素置为null,并创建一个新的数组来存储非null的元素,从而实现删除。

然后,我们获取要查询的学生学号,并进行判断。如果学号存在,则将对应的学生对象的年龄加1岁。

最后,我们通过调用printStudents方法来遍历并打印所有学生信息。

同时,我们在Student类中重写了toString方法,用于返回学生对象的信息。

相关文章:

Java 复习笔记 - 面向对象篇

文章目录 一&#xff0c;面向对象概述二&#xff0c;类和对象&#xff08;一&#xff09;类和对象的概述&#xff08;二&#xff09;定义类的补充注意事项 三&#xff0c;封装四&#xff0c;就近原则和this关键字&#xff08;一&#xff09;就近原则&#xff08;二&#xff09;…...

行业追踪,2023-08-31

自动复盘 2023-08-31 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…...

科技资讯|苹果发布新专利:可在车内定位苹果的智能设备

根据美国商标和专利局近期公示的清单&#xff0c;苹果公司获得了一项名为《车内定位移动设备的系统和方式》专利&#xff0c;概述了在车内狭窄空间内如何定位 iPhone 等移动设备。 Find My 服务现阶段没有使用 UWB 来追踪 iPhone 或者 iPad&#xff0c;而是依赖 GPS 等相关辅…...

浅析Linux SCSI子系统:IO路径

文章目录 概述scsi_cmd&#xff1a;SCSI命令result字段proto_op字段proto_type字段 SCSI命令下发scsi_request_fnscsi_dev_queue_readyscsi_host_queue_ready SCSI命令响应命令请求完成的软中断处理 相关参考 概述 SCSI子系统向上与块层对接&#xff0c;由块层提交的对块设备的…...

linux系统(centos、Ubuntu、银河服务器)备份

制作u盘启动盘 下载usblive系统镜像 Get Kali | Kali Linux 下载u盘启动工具 balenaEtcher - Flash OS images to SD cards & USB drives 点击下载&#xff0c;等待下载完成 双击安装&#xff0c;等待安装完成 双击 启动 选择镜像 选择U盘 开始烧录 等地制作完成 进入…...

堆栈深度超过限制

报错&#xff1a;Cause: com.kingbase8.util.KSQLException: 错误: 堆栈深度超过限制 Hint: 在确定了平台的堆栈深度限制是足够大后&#xff0c;增加配置参数 "max_stack_depth"的值(当前值为2048kB).; 错误: 堆栈深度超过限制 Hint: 在确定了平台的堆栈深度限制是足…...

Linux ptrace系统调用

文章目录 一、ptrace 简介二、ptrace 参数request2.1 PTRACE_TRACEME2.2 PTRACE_PEEKTEXT, PTRACE_PEEKDATA2.3 PTRACE_PEEKUSER2.4 PTRACE_POKETEXT, PTRACE_POKEDATA2.5 PTRACE_POKEUSER2.6 PTRACE_GETREGS, PTRACE_GETFPREGS2.7 PTRACE_GETREGSET2.8 PTRACE_SETREGS, PTRACE…...

CSDN每日一练 |『贝博士发奖金』『Longest Continuous Increasing Subsequence』『最小差值』2023-09-01

CSDN每日一练 |『贝博士发奖金』『Longest Continuous Increasing Subsequence』『最小差值』2023-09-01 一、题目名称:贝博士发奖金二、题目名称:Longest Continuous Increasing Subsequence三、题目名称:最小差值一、题目名称:贝博士发奖金 时间限制:1000ms内存限制:25…...

二维数组创建方式比较

暑假跟着地质队去跑山了&#xff0c;到现在还没结束&#xff0c;今天休息的时候突然刷到了一篇关于C二维数组创建方面的文章&#xff0c;我觉得还是非常不错滴&#xff0c;就将其中提到的新方法和我已经使用过的三种方法进行了比较&#xff0c;发现该方法提高了二维数组的分配、…...

安达发|富士康科技集团利用自动排程APS软件打造智慧工厂

富士康科技集团作为全球领先的3C产品研发制造企业&#xff0c;近年来积极布局智能制造领域&#xff0c;通过引入先进的自动化排程系统(APS),成功打造了智慧工厂&#xff0c;提高了生产质量与效率&#xff0c;降低了生产成本。 富士康集团自2019年下半年提出在观澜厂区建立数字可…...

云计算在大数据分析中的应用与优势

文章目录 云计算在大数据分析中的应用云计算在大数据分析中的优势云计算在大数据分析中的示例未来发展和拓展结论 &#x1f389;欢迎来到AIGC人工智能专栏~云计算在大数据分析中的应用与优势 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&…...

linux————ELK(日志收集系统集群)

目录 一、为什么要使用ELK 二、ELK作用 二、组件 一、elasticsearch 特点 二、logstash 工作过程 INPUT&#xff08;输入&#xff09; FILETER(过滤) OUTPUTS&#xff08;输出&#xff09; 三、kibana 三、架构类型 ELK ELKK ELFK ELFKK EFK 四、构建ELk集群…...

Leetcode213 打劫家舍2

思路&#xff1a;既然头尾不能同时取&#xff0c;那就分别算只取头或者只取尾&#xff0c;不考虑特殊情况的话是一个简单的动态规划 class Solution:def rob(self, nums: list[int]) -> int:if len(nums) < 3:return max(nums)max_sum [nums[0], max(nums[1], nums[0])…...

Redis全局命令

"那篝火在银河尽头~" Redis-cli命令启动 现如今&#xff0c;我们已经启动了Redis服务&#xff0c;下⾯将介绍如何使⽤redis-cli连接、操作Redis服务。客户端与服务端交互的方式有两种: ● 第⼀种是交互式⽅式: 后续所有的操作都是通过交互式的⽅式实现&#xff0c;…...

Xml转json

利用fastjson转换,pom文件依赖: <dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version> </dependency> <dependency><groupId>com.alibaba</groupId><artifa…...

Spring框架知识点汇总

01.Spring框架的基本理解 关键字&#xff1a;核心思想IOC/AOP&#xff0c;作用&#xff08;解耦&#xff0c;简化&#xff09;&#xff0c;简单描述框架组成&#xff1b; Spring框架是一款轻量级的开发框架&#xff0c;核心思想是IOC&#xff08;反转控制&#xff09;和AOP&a…...

JavaScript Web APIs - 06 正则表达式

Web APIs - 06 文章目录 Web APIs - 06正则表达式正则基本使用元字符边界符量词范围字符类 替换和修饰符正则插件change 事件判断是否有类 目标&#xff1a;能够利用正则表达式完成小兔鲜注册页面的表单验证&#xff0c;具备常见的表单验证能力 正则表达式综合案例阶段案例 正…...

Python入门教程 | Python3 字符串

字符串是 Python 中最常用的数据类型。我们可以使用引号( ’ 或 " )来创建字符串。 创建字符串很简单&#xff0c;只要为变量分配一个值即可。例如&#xff1a; var1 Hello World! var2 "Tarzan"Python 访问字符串中的值 Python 不支持单字符类型&#xff…...

Playwright for Python:安装及初步使用

文章目录 一、Playwright介绍1.1 简单介绍1.2 支持的平台1.3 支持语言1.4 官方文档&#xff08;python&#xff09; 二、开始2.1 安装要求2.2 安装2.3 脚本录制2.4 代码示例 一、Playwright介绍 1.1 简单介绍 Playwright是微软推出来的一款自动化测试工具&#xff0c;是专门为…...

Ubuntu 20.04.5 怎么安装微信

这是我的ubutun版本号 在这个系统装桌面版微信很多功能不健全。搜索了很多方法&#xff0c;这个算是不错的一个法子。 1.添加仓库 首次使用时&#xff0c;你需要运行如下一条命令将移植仓库添加到系统中。 wget -O- https://deepin-wine.i-m.dev/setup.sh | sh 2.应用安装 …...

HummerRisk V1.4.0发布

大家好&#xff0c;HummerRisk 1.4.0和大家见面了&#xff0c;在这个版本中我们变更了多云检测的底层逻辑&#xff0c;增加了每次检测的project概念&#xff0c;更好的去支持检测历史和检索需要&#xff0c;增加阿里云最佳实践中资源监控检测规则&#xff0c;增加资源态势中的细…...

C语言每日一练----Day(12)

本专栏为c语言练习专栏&#xff0c;适合刚刚学完c语言的初学者。本专栏每天会不定时更新&#xff0c;通过每天练习&#xff0c;进一步对c语言的重难点知识进行更深入的学习。 今日练习题关键字&#xff1a;最大连续1的个数 完全数计算 &#x1f493;博主csdn个人主页&#xff1…...

【Tkinter系列11/15】小部件 (Text)

24. 小部件Text 文本小部件是一种更通用的方法 处理比小部件多行文本。文本小部件几乎是一个完整的文本 窗口中的编辑器&#xff1a;Label 您可以将文本与不同的字体、颜色和 背景。 您可以用文本穿插嵌入的图像。一 图像被视为单个字符。请参见第 24.3 节 “文本小部件图像”…...

通过「内网穿透」技术,实现出差期间远程访问企业局域网中的象过河ERP系统

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 概述 ERP系统对于企业来说重要性不言而喻&#xff0c;不管是财务、生产、销售还是采购&#xff0c;都需要用到ERP系统来协助。…...

ChatGPT和大型语言模型(LLM)是什么关系?

参考&#xff1a;https://zhuanlan.zhihu.com/p/615203178 # ChatGPT和大型语言模型(LLM)是什么关系&#xff1f; 参考&#xff1a;https://zhuanlan.zhihu.com/p/622518771 # 什么是LLM大语言模型&#xff1f;Large Language Model&#xff0c;从量变到质变 https://zhuanla…...

list(介绍与实现)

目录 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 list的构造 1.2.2 list iterator的使用 1.2.3 list capacity 1.2.4 list element access 1.2.5 list modififiers 1.2.6 list的迭代器失效 2. list的模拟实现 2.1 模拟实现list 2.2 list的反向迭代器 1.…...

Centos7 使用docker安装oracle数据库(超详细)

在linux中采用解压安装包的方式安装oracle非常麻烦&#xff0c;并且稍微不注意就会出现问题&#xff0c;因此采用docker来安装&#xff0c;下面为详细的步骤&#xff1a; 若不知道是否安装docker可查看这篇文章&#xff1a;docker安装 1、拉取oracle镜像 docker pull registr…...

昨天面试的时候被提问到的问题集合(答案)

1、vue的双向绑定原理是什么&#xff1f;里面的关键点在哪里&#xff1f; Vue的双向绑定原理是基于Object.defineProperty或者Proxy来实现的&#xff0c;其关键点在于数据劫持&#xff0c;即对数据的读取和修改进行拦截&#xff0c;在数据发生变化时自动更新视图 2、实现水平垂…...

PYTHON用户流失数据挖掘:建立逻辑回归、XGBOOST、随机森林、决策树、支持向量机、朴素贝叶斯和KMEANS聚类用户画像...

原文链接&#xff1a;http://tecdat.cn/?p24346 在今天产品高度同质化的品牌营销阶段&#xff0c;企业与企业之间的竞争集中地体现在对客户的争夺上&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 “用户就是上帝”促使众多的企业不惜代价去争夺尽可能多的客…...

详解IP协议

在介绍IP协议之前&#xff0c;先抛出一个概念&#xff1a;IP地址的作用——定位主机&#xff0c;具有将数据从主机A跨网络传输到主机B的能力&#xff0c;有了TCP提供的策略&#xff0c;例如滑动窗口、拥塞控制等&#xff0c;IP去执行它&#xff0c;所以我们通常叫TCP/IP协议&am…...