day02_Java基础

文章目录

  • day02_Java基础
    • 一、今日课程内容
    • 二、数组(熟悉)
      • 1、定义格式
      • 2、基本使用
      • 3、了解数组的内存图介绍
      • 4、数组的两个小问题
      • 5、数组的常见操作
    • 三、方法(熟悉)
      • 1、定义格式
      • 2、方法重载overload
    • 四、面向对象(掌握)
      • 1、类的定义与使用
      • 2、构造方法
      • 3、封装
      • 4、继承
      • 5、多态
      • 6、两个关键字
      • 7、抽象类
      • 8、接口
      • 9、内部类
    • 五、作业

day02_Java基础

一、今日课程内容

  • 1- 数组(熟悉)

  • 2- 方法(熟悉)

  • 3- 面向对象(掌握)

今日目的:面向对象

二、数组(熟悉)

​ 和Python中一样, Java中也是有用来同时存储多个同类型元素的容器的, 那就是: 数组。在一个数组中,数据元素的类型是唯一的,即一个数组中的元素的类型相同。

1、定义格式

  • 方式一: 动态初始化 (我们给定长度, 由系统给出默认初始化值)
格式一: 数据类型[] 数组名 = new 数据类型[长度];格式二: 数据类型 数组名[] = new 数据类型[长度];

解释: 上述两种定义方式只是写法不同, 并无其他区别。推荐使用格式一

  • 方式二: 静态初始化(我们给定初始化值, 由系统指定长度)
格式一:数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, 元素3};		格式二:数据类型[] 数组名 = {元素1, 元素2, 元素3};

解释: 上述两种定义方式只是写法不同, 并无其他区别. 推荐使用格式二

数组中的每个元素都是有编号的, 且编号是从0开始的. 可以方便我们快速操作数组中的元素.

解释: 编号也叫索引(这个是最常见的念法), 下标、角标、index
注意: Java中的数组只有正向索引,没有负向索引。

数组中每个元素都有默认值.

例如:
int类型数组, 元素默认值是: 0
double类型的数组, 元素默认值是: 0.0
boolean类型的数组, 元素默认值是: false
String类型的数组, 元素默认值是: null

2、基本使用

  • 1- 通过数组名[索引]的形式, 可以快速获取数组中的指定元素
格式: 数组名[索引]例如:
int[] arr = {11, 22, 33};
System.out.println(arr[0]);	//打印结果是: 11
  • 2- 通过数组名[索引] = 值;的方式, 可以修改数组中的指定元素值.
格式: 数组名[索引] = 值;//例如:
int[] arr = {11, 22, 33};
System.out.println(arr[1]);	//打印结果是: 22
arr[1] = 222;
System.out.println(arr[1]);	//打印结果是: 222
  • 3- 通过数组名的length方法, 可以获取数组的长度
格式: 数组名.length例如:
int[] arr = {11, 22, 33};
System.out.println(arr.length);	//打印结果是: 3

案例实现:

package com.itheima;import java.util.Arrays;public class Test09 {public static void main(String[] args) {//1. 创建一个数组// 方式一: 动态指定, 构建数组的时候, 只需要指定长度即可int[] arr1 = new int[10];//int arr2[] = new int[10];// 方式二: 静态指定, 构建数组的时候, 直接指定数组中每一个元素的值//double[] arr3 = new double[]{3.5,6.2,1.3,4.5};double[] arr4 = {3.5,6.2,1.3,4.5};//2. 执行相关的操作// 2.1 如何获取数组中指定位置的元素: 在数组中, 通过索引下标的方式获取, 默认下标从0开始int e1 = arr1[2];System.out.println(e1);double e2 = arr4[3];System.out.println(e2);//double e3 = arr4[4]; // 注意: 当获取超出数组范围的数据时候, 会报出如下的错误: ArrayIndexOutOfBoundsException//System.out.println(e3);// 2.2 如何为数组中元素进行重新赋值arr1[2] = 10;System.out.println(arr1[2]);// 2.3 如何获取数组的长度:int length = arr4.length;System.out.println(length);// 2.4 遍历数组System.out.println("-------------------");// for循环for(int i = 0; i< arr4.length; i++){System.out.println(arr4[i]);}// while循环System.out.println("-------------------");int i = 0;while(i< arr4.length){System.out.println(arr4[i]);i++;}// 增强for: 迭代器   快捷键:  iter + 回车   此种方式与Python中For循环有一些相似了System.out.println("-------------------");for (double v : arr4) {System.out.println(v);}System.out.println("-------------------");// 2.5 将arr4中数据进行反转操作double[] arr5 = new double[arr4.length];for(int j = arr4.length-1; j >= 0; j--){arr5[arr4.length -1 - j] = arr4[j];}System.out.println(Arrays.toString(arr5)); // 将数组以字符串的形式打印出来// 演示 小错误:String[] arr6 = new String[10];String e3 = arr6[2]; // 注意 e3 = Nulle3.concat("xxx'"); // 注意: 使用 null 调用API, 会报: NullPointerException (空指针异常)}
}

3、了解数组的内存图介绍

​ 内存是计算机中的重要原件,也是临时存储区域,作用是运行程序。我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。

​ 即: Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。

JVM的内存划分

1.栈: 存储局部变量以及所有代码执行的.  局部变量: 指的是定义在方法中, 或者方法声明上的变量. 特点: 先进后出. 
2.堆: 存储所有new出来的内容(即: 对象).特点: 堆中的内容会在不确定的时间, 被GC(垃圾回收)回收. 
3.方法区: 存储字节码文件的.字节码文件: 指的是后缀名为.class的文件. 
4.本地方法区:和系统相关, 了解即可. 
5.寄存器和CPU相关, 了解即可.

以下为一个数组的内存图:

public class ArrayDemo03 {public static void main(String[] args) {int[] arr = new int[3];//打印数组中的第一个元素, 值为: 0System.out.println(arr[0]);	//[I@1540e19dSystem.out.println(arr);}
}

其中[I@1540e19d是arr数组的地址值

在这里插入图片描述

核心点: 当创建一个数组的时候, 由于数组是一个引用类型, 是一个对象, 首先会在堆空间中开辟一块空间, 将数组中数据放置到空间下, 此空间同时也会有一个唯一的地址指向这个空间,  此时变量也是指向此内存空间地址

在这里插入图片描述

4、数组的两个小问题

数组是我们在实际开发中用到的比较多的容器, 在使用它的时候, 很可能会遇到如下的两个问题:

  • 1- 数组索引越界异常(ArrayIndexOutOfBoundsException)
产生原因: 访问了数组中不存在的索引
解决方案: 访问数组中存在的索引即可
  • 2- 空指针异常(NullPointerException)
产生原因: 访问了空对象。即: 对象为空, 你还去调用它的一些方法, 肯定不行
解决方案: 给对象赋具体的值即可

5、数组的常见操作

数组是我们在实际开发中用到的比较多的一种容器, 它的常见操作如下:

  • 遍历数组

  • 获取数组的最值(最大值, 或者最小值)

  • 反转数组

package com.itheima;import java.util.Arrays;public class Demo02_数组相关操作 {public static void main(String[] args) {//1. 创建一个数组int[] arr1 = {1,5,6,2,8,4,9,10,0};//2. 执行相关的操作//2.1 遍历数组for (int i : arr1) {System.out.println(i);}// 2.2 获取数组最大值 和 最小值int maxV = arr1[0];int minV = arr1[0];for (int i : arr1) {if( maxV < i ) {maxV = i;}if( minV > i ) {minV = i;}}System.out.println("最大值为:" + maxV);System.out.println("最小值为:" + minV);// 2.3 如何反转数组int[] arr2 = new int[arr1.length];for(int i = arr1.length -1; i >= 0 ; i--){System.out.println(arr1[i]);arr2[arr1.length-1-i] = arr1[i];}System.out.println(Arrays.toString(arr2));}}
package cn.itcast.object;import java.util.Arrays;/*** 数组演示:定义和基本操作*/
public class ArrayDemo {public static void main(String[] args) {/*1-定义数组Arrays.toString:数组工具类,用来将数组转成字符串形式*/// 动态定义int[] arr1 = new int[5];int arr2[] = new int[5];double[] arr3 = new double[5];System.out.println(Arrays.toString(arr1));System.out.println(Arrays.toString(arr3));// 静态定义int[] arr4 = {1,3,5};int[] arr5 = new int[]{2,4,6};System.out.println(Arrays.toString(arr4));// 数组的基本操作// 获取对应索引的值System.out.println(arr4[0]);System.out.println(arr4[1]);System.out.println(arr4[2]);//System.out.println(arr4[3]);// 给数组中某个索引进行赋值操作arr4[1] = 6;System.out.println(arr4[1]);System.out.println(Arrays.toString(arr4));// 获取数组的长度System.out.println(arr4.length);System.out.println("------------------------------");// 遍历数组。常规for循环的快捷方式:.for+回车for(int i=0;i<arr4.length;i++){System.out.println(arr4[i]);}int i=0;while(i<arr4.length){System.out.println(arr4[i]);i++;}int minValue = Integer.MAX_VALUE;int maxValue = Integer.MIN_VALUE;// int maxValue = arr4[0];// 获取数组的最值(最大值, 或者最小值)for(int j=0;j<arr4.length;j++){int tmp = arr4[j];if(tmp>maxValue){maxValue = tmp;}if(tmp<minValue){minValue = tmp;}}System.out.println(minValue);System.out.println(maxValue);// 反转数组int[] newArr = new int[arr4.length];for(int j=0;j<arr4.length;j++) {newArr[j] = arr4[arr4.length-j-1];}System.out.println(Arrays.toString(newArr));}
}

三、方法(熟悉)

​ Python中的函数, 是将具有独立功能的代码块组织成为一个整体,使其成为具有特殊功能的代码集。Java中也是如此。只不过,Java中的函数也叫方法.

1、定义格式

修饰符 返回值的数据类型 方法名(参数类型 参数名1, 参数类型 参数名2) { //这里可以写多个参数//方法体;return 具体的返回值;	
}修饰符: 目前记住这里是固定格式public static返回值的数据类型: 用于限定返回值的数据类型的.注意: 1.返回值的数据类型是int类型, 则说明该方法只能返回int类型的整数.2.如果方法没有具体的返回值, 则返回值的数据类型要用void来修饰,不能省略.方法名: 方便我们调用方法.  定义的时候 要遵循小驼峰的命名法参数类型: 用于限定调用方法时传入的数据的数据类型.例如: 参数类型是String类型, 说明我们调用方法时, 只能传入字符串.参数名: 用于接收调用方法时传入的数据的变量. 方法体: 完成特定功能的代码。不建议一个方法的内部代码行数过多。return 返回值: 用来结束方法的, 并把返回值返回给调用者. 解释: 如果方法没有明确的返回值, 则return关键字可以省略不写.

注意事项:

1.方法与方法之间是平级关系, 不能嵌套定义.
2.方法的定义和调用没有先后顺序的要求
3.方法自身不会直接运行, 而是需要我们手动调用方法后, 它才会执行, 该过程称为方法调用.
4.方法的功能越单一越好. 
5.定义方法的时候写在参数列表中的参数, 都是: 形参. 形参: 形容调用方法的时候, 需要传入什么类型的参数.
6.调用方法的时候, 传入的具体的值(变量或者常量都可以), 叫实参. 实参: 调用方法时, 实际参与运算的数据.

示例:

需求一: 编写一个方法, 接收数组参数, 实现遍历数组的功能

需求二: 获取数组最值(例如: 最大值)

package com.itheima;public class Test10_method {// main 方法public static void main(String[] args) {int[] arr1 = {1,4,6,3,8,10,15};// 调用方法foreachArr(arr1); // 传入的参数为实参// 获取数组中最大值int maxNum = getMaxNum(arr1);System.out.println("最大值为:"+maxNum);}// 方法的定义public static void foreachArr(int[] arr){ // 定义参数为形参// 遍历数组for (int e : arr) {System.out.println(e);}}// 定义方法: 实现获取数组中最大值public static int getMaxNum(int[] arr){int max = arr[0];for (int e : arr) {if(e > max)  max = e;}return max;}}

2、方法重载overload

补充:重写override

​ 同一个类中, 出现方法名相同, 但是参数列表不同的两个或以上的方法时**称为方法重载. **方法重载与方法的返回值的数据类型无关.

注意: 参数列表不同分为两种情况
1.参数的个数不同.
2.对应参数的数据类型不同.方法重载的总结:只关注方法名称  和  形参列表,与返回值类型没关系要求方法名称必须相同,而形参列表不同。这里的不同不包括形参的名称

需求

演示方法的重载

package com.itheima.day02;public class 方法的重载 {public static void main(String[] args) {System.out.println(myAdd(1, 2));System.out.println(myAdd(1.99, 2.0));}/*方法重载的总结:只关注方法名称  和  形参列表,与返回值类型没关系要求方法名称必须相同,而形参列表不同。这里的不同不包括形参的名称*/public static int myAdd(int num1,int num2){return num1+num2;}// 这种不叫方法的重载
//    public static int myAdd(int num1,int num2222){
//        return num1+num2222;
//    }public static double myAdd(double num1,double num2){return num1+num2;}
}

四、面向对象(掌握)

​ 和Python一样, Java也是一门以面向对象为编程思想的语言, 也有类, 对象的概念, 并且面向对象的三大特征: 封装, 继承, 多态, 在Java中也都是有的, 接下来, 我们来研究下Java中的面向对象应该如何运用.

1、类的定义与使用

定义类其实就是定义类的成员(成员属性/变量和成员方法)

  • 成员变量:

    • 1- 和以前定义变量是一样的, 只不过位置发生了改变, 写到类中, 方法外
    • 2- 而且成员变量还可以不用赋值, 因为它有默认值.
  • 成员方法:

    • 1- 和以前定义方法是一样的, 只不过把static关键字去掉.
    • 2- 这点先记忆即可, 后面我们再讲解static关键字的用法.

定义类的格式:

public class 类名 {
//成员变量, 私有化, 类似于Python中的 __
//构造方法, 空参, 全参, 类似于Python的魔法方法之 __init__(self)
//getXxx(), setXxx()方法, 用来获取或者设置对象的属性值的//成员方法, 就是普通的函数
}

使用类中成员的格式:

1.创建该类的对象, 格式如下: 类名 对象名 = new 类名();
2.通过对象名.的形式, 调用类中的指定成员即可, 格式如下: //成员变量对象名.成员变量//成员方法对象名.成员方法(参数列表中各数据类型对应的值...)

需求:

1- 定义手机类Phone.

2- 创建测试类PhoneTest, 在类中定义main方法, 并访问手机类(Phone类)中的成员.

属性: 品牌(brand), 价格(price), 颜色(color)行为: 打电话(call), 发短信(sendMessage)

非私有方案:

package com.itheima.类的使用;public class Phone {// 成员变量String brand;double price;String color;public void call(){System.out.println("打电话");}public void sendMessage(){System.out.println("发短信");}
}// 测试类
package com.itheima.类的使用;public class Demo05_phoneTest {public static void main(String[] args) {//1. 创建 手机类的对象   构建对象 关键词  newPhone phone = new Phone();//2. 为成员属性赋值:phone.brand = "华为";phone.color = "祖母绿";phone.price = 19999.0;//3. 获取成员属性的值System.out.println(phone.brand);System.out.println(phone.color);System.out.println(phone.price);//4. 调用成员方法phone.call();phone.sendMessage();}
}

(推荐)私有化方案:

package com.itheima.类的使用;
/*权限修饰符public: 公共的  一旦方法 或者 类  成员变量 被标记, 可以在其他类中, 甚至其他的项目中 都可以加载到此内容private: 私有的  表示 仅在当前类中可用*/
public class Phone2 {// 成员变量 私有化private String brand;private double price;private String color;// 为私有的属性 提供 getter 和 setter方法// 快捷键:  alt + ins 键public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public void call(){System.out.println("打电话");}public void sendMessage(){System.out.println("发短信");}
}// 测试类
package com.itheima.类的使用;public class Demo06_phone2Test {public static void main(String[] args) {//1. 创建 手机类的对象   构建对象 关键词  newPhone2 phone2 = new Phone2();//2. 为成员属性赋值phone2.setBrand("三星");phone2.setColor("土豪金");phone2.setPrice(5888);//3. 获取成员属性的值System.out.println(phone2.getColor());System.out.println(phone2.getBrand());System.out.println(phone2.getPrice());//4. 调用方法phone2.call();phone2.sendMessage();}
}

2、构造方法

Java中的构造方法类似于Python中的魔法方法之_init_(), 就是用来创建对象的, 捎带着可以给对象的各个成员变量赋值.

大白话:

构造方法就是用来快速对对象的各个属性赋值的. 

格式:

  • 1.构造方法名必须和类名完全一致(包括大小写).
  • 2.构造方法没有返回值类型, 连void都不能写.
  • 3.构造方法没有具体的返回值, 但是可以写return(实际开发, 一般不写 基本没见过写的).
public 类名(参数类型 参数名1, 参数类型 参数名2) {  //这里可以写多个参数.//给对象的各个属性赋值即可.
}

演示构造的使用:

package com.itheima.类的使用;public class Stu {// 当不写构造方法的时候, 类会默认提供一个空参的构造, 一旦我们书写了构造方法, 默认的构造就不提供了, 如果需要空参的构造, 必须手动写出来// 快捷键: alt + inspublic Stu() {}public Stu(String name, int age) {this.name = name;this.age = age;}public Stu(String name) {this.name = name;}public Stu(int age) {this.age = age;}// 属性: 当创建对象的时候,不管是否有赋值操作, 先默认给成员属性进行初始化操作private String name;private int age;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;}
}package com.itheima.类的使用;public class Demo07_stuTest {public static void main(String[] args) {//1, 创建Stu对象//Stu stu = new Stu("张三",30);//Stu stu = new Stu();//Stu stu = new Stu(50);Stu stu = new Stu("李四");//2. 赋值//stu.setAge(50);//3. 获取值System.out.println(stu.getAge());System.out.println(stu.getName());}
}

相关的注意事项:

1.如果我们没有给出构造方法, 系统将给出一个默认的无参构造供我们使用. 
2.如果我们给出了构造方法, 系统将不再提供默认的构造方法给我们使用. 2.1 这个时候, 如果我们还想使用无参构造, 就必须自己提供.2.2 建议定义类时,我们给出无参构造, 方便用户调用(实际开发都这么做的).3- 如果需要将这个类构建为一个工具类, 此时这个类的构造方法必须私有化(不允许用户创建这个类对象)
4- Java中一个类里面能够有多个构造方法

3、封装

封装是面向对象编程思想的三大特征之一, 所谓的封装指的就是隐藏对象的属性和实现细节, 仅对外提供一个公共的访问方式.

记忆:

面向对象的三大特征: 封装, 继承, 多态.

问题一: 怎么隐藏?
答案: 通过private关键字实现.问题二: 公共的访问方式是什么?
答案: getXxx()和setXxx()方法

可能涉及的相关特殊关键词:

  • 1- private关键字
private是一个关键字, 也是访问权限修饰符的一种, 它可以用来修饰类的成员(成员变量和成员方法).特点: 被private修饰的内容(成员变量和成员方法)只能在本类中直接使用,外界无法直接访问。应用场景:1.在实际开发中, 成员变量基本上都是用private关键字来修饰的.2.如果明确知道类中的某些内容不想被外界直接访问, 都可以通过private来修饰. 
  • 2- this关键字
this代表本类当前对象的引用, 大白话翻译: 谁调用, this就代表谁. 作用:用来解决局部变量和成员变量重名问题的.类似于python中 self 关键词

4、继承

​ 多个类中存在相同属性和方法时, 将这些内容抽取到单独的一个类中, 那么这多个类就无需再定义这些属性和行为了, 只要继承那个类即可. 这个关系, 就叫继承, Java中, 类与类之间的继承只能单继承,不能多继承,但是可以多层继承.也就是现实生活中,一个人只有一个父亲,也就是单继承;但是还有爷爷,也就是多层继承。

格式:
public class 类A extends 类B {	//子承父业}解释:
类A: 叫子类, 或者派生类.
类B: 叫父类, 基类, 或者超类.
我们一般会念做: 子类和父类. 继承关键字是extends

需求:

  • 1.按照标准格式定义一个人类(Person类), 属性为姓名和年龄.

  • 2.定义老师类(Teacher), 继承自人类, 并在老师类中定义teach()方法.

  • 3.定义学生类(Student), 继承自人类, 并在学生类中定义study()方法.

  • 4.在PersonTest测试类的main方法中, 分别创建老师类和学生类的对象, 并调用各自类中的成员.

person类:
package com.itheima.继承;public class Person {private String name;private int age;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;}public void eat(){System.out.println("人人都要吃饭...");}}学生类:
package com.itheima.继承;public class Student extends Person {public void study(){System.out.println(super.getName()+"学生要上课, 课上不能睡觉......");}}老师类:
package com.itheima.继承;public class Teacher extends Person {public void  teach(){System.out.println(super.getName()+"老师,今年已经"+super.getAge()+"岁了, 依然也要教书......");}
}测试类
package com.itheima.继承;public class Demo08_PersonTest {public static void main(String[] args) {//1. 创建 学生类  和 老师类 对象Student stu = new Student();Teacher teacher = new Teacher();//2. 设置成员属性stu.setName("张三");stu.setAge(20);teacher.setName("张教授");teacher.setAge(40);//3. 获取值, 调用方法System.out.println(stu.getAge());System.out.println(stu.getName());stu.study();stu.eat();System.out.println(teacher.getAge());System.out.println(teacher.getName());teacher.teach();teacher.eat();}
}子类在继承父类的时候, 可以将父类中公共(public)的方法 和 属性 全部都继承, 如果父类中属性和方法被标记为私有化后, 我们无法继承

说明: 继承的好处和弊端

好处:1.提高了代码的复用性.2.提高了代码的可维护性.3.让类与类之间产生关系, 是多态的前提. 弊端:让类与类之间产生了关系, 也就让类的耦合性增强了. 解释:开发原则: 高内聚, 低耦合.内聚: 指的是类自己独立完成某些事情的能力.耦合: 指的是类与类之间的关系. 

方法的重写:

​ 子类中出现和父类一模一样的方法时, 称为方法重写. 方法重写要求返回值的数据类型也必须一样

方法名称、形参列表(参数个数、参数顺序、参数数据类型)、方法返回值数据类型都需要一样。另外子类方法的访问范围要大于等于父类的范围

什么时候需要使用方法重写:当子类需要使用父类的功能, 而功能主体又有自己独有需求的时候, 就可以考虑重写父类中的方法了, 这样, 即沿袭了父类的功能, 又定义了子类特有的内容. 

需求:

  • 1 定义Phone类, 并在类中定义call(String name)方法.

  • 2 定义NewPhone类, 继承Phone类, 然后重写call(String name)方法.

  • 3 在PhoneTest测试类中, 分别创建两个类的对象, 然后调用call()方法, 观察程序执行结果.

phone类:
package com.itheima.继承;public class Phone {public void call(String name){System.out.println(name + "打电话");}}newPhone类:
package com.itheima.继承;public class NewPhone extends Phone {@Override // 此注解表示是当前这个方法是一个重写的方法(仅仅是标记)public void call(String name) {super.call(name);System.out.println(name+"打电话,并且同时视频聊天");}}测试类
package com.itheima.继承;public class Demo09_PhoneTest {public static void main(String[] args) {//1. 创建 NewPhone类对象NewPhone newPhone = new NewPhone();newPhone.call("张三");System.out.println("=================");Phone phone = new Phone();phone.call("李四");}
}

注意事项:

1.子类重写父类方法时, 方法声明上要用@Override注解来修饰. 
2.父类中私有的方法不能被重写. 
3.子类重写父类方法时, 访问权限不能更低.

子类可以重写父类中公共的方法, 可以针对父类的方法进行增强

5、多态

多态指的是同一个事物(或者对象)在不同时刻表现出来的不同状态.

例如: 一杯水.

• 常温下是液体.

• 高温下是气体.

• 低温下是固体.

但是水还是那杯水, 只不过在不同的环境下, 表现出来的状态不同.

多态使用的前提条件:
1.要有继承关系.
2.要有方法重写.
3.要用父类引用指向子类对象.

简单理解: 父类接收子类对象 (父类指向子类的引用)

示例:

  • 1 定义动物类Animal, 并在类中定义一个成员方法: eat()

  • 2 定义猫类Cat, 继承Animal类, 并重写eat()方法.

  • 2 定义猫类Dog, 继承Animal类, 并重写eat()方法.

  • 3 在AnimalTest测试类的main方法中, 通过多态的方式创建猫类和狗类对象.

  • 4 通过类对象, 调用eat()方法.

package com.itheima.多态;public class Animal {public void eat(){System.out.println("动物都要吃......");}}package com.itheima.多态;public class Dog extends Animal {@Overridepublic void eat() {System.out.println("狗爱吃骨头......");}
}package com.itheima.多态;public class Cat extends Animal {@Overridepublic void eat() {System.out.println("猫爱吃鱼......");}}package com.itheima.多态;public class Demo10_AnimalTest {// 多态格式: 父类 = 子类对象// 多态特性: 编译看左边, 运行看右边public static void main(String[] args) {//1. 创建一个猫对象Animal cat = new Cat();cat.eat();//2. 创建一个狗 对象Animal dog = new Dog();dog.eat();}
}

多态的好处和弊端

好处: 提高了程序的扩展性. 弊端:
父类引用不能访问子类的特有功能. 
问:  那如何解决这个问题呢? 
答:  通过向下转型来解决这个问题. (强制类型转换)

上下转型的方式:

向上转型:
格式
父类型 对象名 = new 子类型();例如: Animal an = new Cat();向下转型:
格式
子类型 对象名 = (子类型)父类引用;例如: Cat c = (Cat)an;

示例:

// 向下转型
Animal animal3 = new Cat();
Cat cat = (Cat) animal3; // 向下转型
Dog dog = (Dog) animal3; // 直接报错(ClassCastException 类型转换异常), 因为本身就不是 Dog类型, 所以无法进行向下转型cat.seize();
System.out.println(animal3);

说明: 向下转型的目的是为了调用子类中特有的方法

package com.itheima.多态;public class Demo10_AnimalTest {// 多态格式: 父类 = 子类对象// 多态特性: 编译看左边, 运行看右边public static void main(String[] args) {//1. 创建一个猫对象Animal cat = new Cat();cat.eat();//2. 创建一个狗 对象Animal dog = new Dog();dog.eat();//3. 调用 execute 方法execute(new Dog());}public static  void execute(Animal animal){animal.eat();// 判断, 如果传入的类型是 Dog, 请强转为 dog类型, 调用action方法// 关键词: instanceof  类型判断 ,   格式:   对象  instanceof 需要判断类型  返回 True表示是这个类型的对象, 返回Flase表示不是这个类型的对象if( animal instanceof Dog ){Dog dog = (Dog) animal;dog.action();}}
}

6、两个关键字

  • 1- final关键字
final是一个关键字, 表示最终的意思, 可以修饰类, 成员变量, 成员方法. 
•修饰的类: 不能被继承, 但是可以继承其他的类.   称为 最终类
•修饰的变量: 是一个常量, 只能被赋值一次.   称为 常量
•修饰的方法: 不能被子类重写.   既需要别人调用, 又不想让别人重写内部内容, 需要添加final

需求

  • 1 定义Father类, 并定义它的子类Son.

  • 2 先用final修饰Father类, 看Son类是否还能继承Father类.

  • 3 在Son类中定义成员变量age, 并用final修饰, 然后尝试给其重新赋值, 并观察结果.

  • 4 在Father类中定义show()方法, 然后用final修饰, 看Son类是否能重写该方法.

package com.itheima.两个关键词;
// 如果使用final 修饰类, 此类为最终类, 无法被其他类所继承, 但是可以继承其他类
public /*final */  class Father {// 既想让其他用户使用, 又不想让其他用户改写我的函数, 此时可以将函数/方法 使用 final修饰public final void show(){System.out.println("xxxxxxxxxxxxxxxxxx");}}package com.itheima.两个关键词;public class Son extends Father {final int AGE = 18;  // 一旦被final所修饰, 当前这个变量 只能赋值 1次  称为常量/*@Overridepublic void show() {System.out.println("xxxxxxx");}*/
}package com.itheima.两个关键词;public class Demo12_final {public static void main(String[] args) {Son son = new Son();//son.age = 18;System.out.println(son.AGE);}
}
  • 2- static关键字
static是一个关键字, 表示静态的意思, 可以修饰成员变量, 成员方法. 但是不能修饰class类特点:
1.随着类的加载而加载. (当class文件被加载到JVM方法区的时候, 被static修饰的成员, 也会直接加载, 直接使用)
2.优先于对象存在.
3.被static修饰的内容, 能被该类下所有的对象共享.解释: 这也是我们判断是否使用静态关键字的条件. 
4.可以通过  类名.  的形式调用.也就是你不需要创建类的实例对象

静态方法的访问特点及注意事项

访问特点静态方法只能访问静态的成员变量和静态的成员方法.简单记忆: 静态只能访问静态. 
注意事项1.在静态方法中, 是没有this, super关键字的. 2.因为静态的内容是随着类的加载而加载, 而this和super是随着对象的创建而存在. 即: 先进内存的, 不能访问后进内存的. 

需求:

  • 1 定义学生类, 属性为姓名和年龄(静态修饰), 非静态方法show1(),show2(), 静态方法show3(), show4().

  • 2 尝试在show1()方法中, 调用: 姓名, 年龄, show2(), show4()

  • 3 尝试在show3()方法中, 调用: 姓名, 年龄, show2(), show4().

package com.itheima.两个关键词;public class Student3 {String name;static int age;public  void show1(){ // 在 非静态的方法中, 可以使用静态内容 也可以使用非静态的内容System.out.println("我是show1...."+name +"  "+ age);show2(); // 调用非静态的方法show4(); // 调用静态的方法}public void show2(){System.out.println("我是show2....");}public static void show3(){ // 在静态方法的中, 可以使用静态的成员, 但是不能使用非静态的成员System.out.println("我是show3...."+ age);//show2();show4();}public static void show4(){System.out.println("我是show4....");}
}

静态代码块: 通过 static 对代码块进行修饰, 修饰后 称为 静态代码块

特点: 随着类的加载而加载, 而且一般只会加载一次

放置的位置: 类中 方法外

package com.itheima.两个关键词;public class Teacher {String name;String address;int age;// 随着类的加载而加载, 而且一般只会加载一次// 基于静态代码块, 可以进行初始化的操作。例如:数据库连接的创建static{System.out.println("上课前, 需要进行备课...");}public  void teach(){System.out.println("老师要上某一阶段的课");}
}

范围的修饰符(访问范围由大到小排序):public > protected > 没有修饰符default > private

7、抽象类

​ 回想前面我们的猫狗案例, 提取出了一个动物类, 这个时候我们可以通过Animal an = new Animal(); 来创建动物对象, 其实这是不对的, 因为, 我说动物, 你知道我说的是什么动物吗? 只有看到了具体的动物, 你才知道, 这是什么动物. 所以说, 动物本身并不是一个具体的事物, 而是一个抽象的事物. 只有真正的猫, 狗才是具体的动物.

​ 同理, 我们也可以推想, 不同的动物吃的东西应该是不一样的, 所以, 我们不应该在动物类中给出具体的体现, 而是应该给出一个声明即可. 在Java中, 一个没有方法体的方法应该定义为抽象方法, 而类中如果有抽象方法, 该类必须定义为抽象类。抽象类中不是必须要有抽象方法.

​ **抽象类的使用场景:用来定义大多数子类都具备的规则,只不过具体的实现思路每个子类都是不一样的。**因为抽象类需要在下面创建对应的实现子类。

示例需求:

  • 1- 创建抽象类Animal.
  • 2- 在该类中定义抽象方法eat()
package com.itheima.抽象类;
// 说明: 有抽象方法的类 一定是一个抽象类,  在抽象类中可以有非抽象的方法
//  抽象类 和 抽象 方法 都使用 abstract关键词标注
public abstract class Animal {public abstract void eat();public void run(){System.out.println("xxxxx");}}package com.itheima.抽象类;public class Demo01_AnimalTest {public static void main(String[] args) {// 抽象类, 是无法被实例化的(无法创建对象)//Animal animal =  new Animal();}
}

抽象类的特点:

抽象类和抽象方法必须用abstract关键字修饰.
抽象类中不一定有抽象方法, 有抽象方法的类一定是抽象类
抽象类不能实例化.– 那抽象类如何实例化呢?– 可以通过多态的方式, 创建其子类对象, 来完成抽象类的实例化. 这也叫: 抽象类多态.
抽象类的子类:– 如果是普通类, 则必须重写父抽象类中所有的抽象方法.– 如果是抽象类, 则可以不用重写父抽象类中的抽象方法. 

需求:

  1. 定义抽象类Animal , 类中有一个抽象方法eat(), 还有一个非抽象方法sleep().
  2. 尝试在测试类中, 创建Animal类的对象, 并观察结果.
  3. 创建普通类Cat, 继承Animal类, 观察是否需要重写Animal#eat()方法.
  4. 创建抽象类Dog, 继承Animal类, 观察是否需要重写Animal#eat()方法.
package com.itheima.抽象类;
// 说明: 有抽象方法的类 一定是一个抽象类,  在抽象类中可以有非抽象的方法
//  抽象类 和 抽象 方法 都使用 abstract关键词标注
public abstract class Animal {public abstract void eat();public void sleep(){System.out.println("动物都要睡觉...");}}package com.itheima.抽象类;public class Cat extends Animal {@Overridepublic void eat() {System.out.println("猫吃鱼......");}
}package com.itheima.抽象类;public class Dog extends Animal {@Overridepublic void eat() {System.out.println("狗吃骨头......");}
}package com.itheima.抽象类;public class Demo01_AnimalTest {public static void main(String[] args) {// 抽象类, 是无法被实例化的(无法创建对象)//Animal animal =  new Animal();// 创建实例对象Dog dog = new Dog();dog.eat();dog.sleep();Cat cat = new Cat();cat.eat();cat.sleep();// 多态的方式Animal animal_1 = new Dog();Animal animal_2 = new Cat();animal_1.eat();  // 编译看左边, 运行看右边animal_1.sleep();}
}

8、接口

​ 继续回到我们的猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了。但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能

​ 所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被训练,只需要这部分猫狗把这些额外功能实现即可。

​ 接口中的内容, 都是抽象的, 一般是用于定义规则 协议

接口的使用场景:接口是一种特殊的抽象类。用来定义规则的,但是这些规则只有少部分类才具备的特点。

接口的特点:

1.接口用interface关键字修饰.
2.类和接口之间是实现关系, 用implements关键字表示.
3.接口不能实例化.– 那接口如何实例化呢?– 可以通过多态的方式, 创建其子类对象, 来完成接口的实例化. 这也叫: 接口多态.
4.接口的子类:– 如果是普通类, 则必须重写父接口中所有的抽象方法.– 如果是抽象类, 则可以不用重写父接口中的抽象方法. 

需求:

1 定义Jumpping接口, 接口中有一个抽象方法jump().

2 定义Cat类, 实现Jumpping接口, 重写jump()方法.

3 在测试类的main方法中, 创建Jumpping接口对象, 并调用其jump()方法

package com.itheima.接口;public interface Jumpping {public  void jump();
}package com.itheima.接口;public class Cat implements Jumpping {@Overridepublic void jump() {System.out.println("猫可以钻火圈......");}
}package com.itheima.接口;public class Demo02_jumppingTest {public static void main(String[] args) {Jumpping jumpping = new Cat();jumpping.jump();}}

类与接口之间的关系

  • 类与类之间: 继承关系, 只能单继承, 不能多继承, 但是可以多层继承.
  • 类与接口之间: 实现关系, 可以单实现, 也可以多实现. 还可以在继承一个类的同时实现多个接口.
  • 接口与接口之间: 继承关系, 可以单继承、多层继承, 也可以多继承.

综合案例:

  1. 已知有乒乓球运动员(PingPangPlayer)和篮球运动员(BasketballPlayer), 乒乓球教练(PingPangCoach)和篮球教练(BasketballCoach).
  2. 他们都有姓名和年龄, 都要吃饭, 但是吃的东西不同.
  3. 乒乓球教练教如何发球, 篮球教练教如何运球和投篮.
  4. 乒乓球运动员学习如何发球, 篮球运动员学习如何运球和投篮.
  5. 为了出国交流, 跟乒乓球相关的人员都需要学习英语.
package com.itheima.接口综合案例;public abstract class Person {private String name;private int age;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;}public abstract void eat();}package com.itheima.接口综合案例;public abstract class Coach extends Person {public abstract void teach();}package com.itheima.接口综合案例;public class BasketballCoach extends Coach {@Overridepublic void teach() {System.out.println("篮球教练教如何运球和投篮");}@Overridepublic void eat() {System.out.println("篮球教练喜欢吃鱼肉......");}
}package com.itheima.接口综合案例;public class PingPangCoach extends Coach implements Language{@Overridepublic void teach() {System.out.println("乒乓球教练教如何发球");}@Overridepublic void eat() {System.out.println("乒乓球教练喜欢吃高蛋白视频: 比如 鸡蛋");}@Overridepublic void studyLanguage() {System.out.println("学习英语");}
}package com.itheima.接口综合案例;public abstract class Player extends Person {public abstract void study();
}package com.itheima.接口综合案例;public class BasketballPlayer  extends Player{@Overridepublic void study() {System.out.println("篮球运动员学习如何运球和投篮......");}@Overridepublic void eat() {System.out.println("篮球运动员喜欢吃日料......");}
}package com.itheima.接口综合案例;public class PingPangPlayer extends Player implements Language {@Overridepublic void study() {System.out.println("乒乓球运动员学习如何发球");}@Overridepublic void eat() {System.out.println("乒乓球运动员喜欢吃麻辣烫......");}@Overridepublic void studyLanguage() {System.out.println("学习英语");}
}package com.itheima.接口综合案例;public interface Language {public void studyLanguage();
}

9、内部类

​ 类里边还有一个类, 外边那个类叫做外部类, 里边那个类叫做内部类,Java中不允许方法的嵌套定义。

示例:

public class A {public class B{}
}A: 外部类
B: 内部类

内部类的分类:

  • 1- 成员内部类(了解)
public class A {	//外部类public class B{	//成员内部类}
}
  • 2- 局部内部类(了解)
public class A {	//外部类//外部类的成员方法public void show() {//局部内部类class B {}}
}
  • 3- 匿名内部类(重要)

    • 匿名内部类指的就是没有名字的局部内部类.
    • 格式:
    xxx = new 类名或者接口名() {//重写类或者接口中所有的抽象方法
    };
    
    • 本质
    匿名内部类就是一个继承了类或者实现了接口的匿名的子类对象.简单理解:匿名内部类的本质就是一个子类对象. 
    
    • 应用场景
    •当对对象方法(即: 成员方法)仅调用一次的时候.
    •匿名内部类可以作为方法的实参进行传递.
    
    • 案例需求:

      定义Animal抽象类, 该类中有一个抽象方法eat().

      在测试类的main方法中, 通过匿名内部类的形式创建Animal抽象类的子类对象.

      调用Animal类中的eat()方法

    package com.itheima.内部类;public abstract class Animal {public abstract void eat();
    }package com.itheima.内部类;public class Demo03_AnimalTest {// 匿名内部类:  将匿名内部类作为抽象类的子类对象public static void main(String[] args) {//1. 创建Animal的对象// Animal animal = new Animal(); // 抽象类不能实例化对象Animal animal = new Animal(){@Overridepublic void eat() {System.out.println("吃东西");}};//animal.eat();execute(animal);}public static void execute(Animal animal){animal.eat();}
    }package com.itheima.内部类;public interface Jumpping {public  void jump();
    }package com.itheima.内部类;public class Demo04_JumppingTest {// 匿名内部类:  将匿名内部类作为接口的子类对象public static void main(String[] args) {// Jumpping jumpping = new Jumpping(); 接口不能创建实例对象Jumpping jumpping = new Jumpping() {@Overridepublic void jump() {System.out.println("钻火圈...");}};jumpping.jump();}
    }package com.itheima.内部类;import com.itheima.抽象类.Animal;public class Cat {public void eat() {System.out.println("猫吃鱼......");}
    }package com.itheima.内部类;public class Demo05_CatTest {// 匿名内部类, 作为类的子类对象public static void main(String[] args) {Cat cat = new Cat(){@Overridepublic void eat() {System.out.println("猫吃猫粮......");}};cat.eat();}
    }

    建议: 当接口或者抽象类中的抽象方法在3个(含)以下时,并且只需要使用一次的时候, 就可以考虑使用匿名内部类的形式来创建对象了

五、作业

 作业一: 场景题目: 有以下几个类, 分别为 人类  学生类 老师类 , 学生类和老师类需要继承人类在人类有以下成员:成员属性:  姓名 年龄 性别 地址 生日成员方法:  吃饭 跑步在学生类: 需要重写吃饭的方法, 学生爱吃麻辣烫属性: 职业: 学生 (固定值)在教师类:需要重写吃饭的方法, 老师爱吃米饭属性: 职业: 教师(固定值)创建一个测试类, 创建三个学生类分别为: 张三   18   男   ...李四   17   女   ...王五   19   男   ...并将三个学生对象, 放置到数组中创建三个教师类: 分别为: 自己写 随意并将三个老师对象, 放置到数组中对学生数组对象, 进行反转操作, 反转后, 通过Arrays将其打印出来对教师数组对象, 采用增强for循环, 遍历打印提示: 在类中,可以重写一个 toString的方法 此方法可以将对象的数据打印, 而不是打印对象的地址值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/71100.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux服务器防火墙白名单访问策略的配置示例

最近在做Linux系统应用部署配置过程中&#xff0c;为了确保应用的安全&#xff0c;简单学习了解了一些Linux中的动态防火墙管理工具的使用方法。本文测试实验主要采用Linux服务器的动态防火墙管理工具(即firewalld)&#xff0c;来实现服务或端口的访问控制&#xff0c;firewall…

【UCB CS 61B SP24】Lecture 17 - Data Structures 3: B-Trees学习笔记

本文以 2-3-4 树详细讲解了 B 树的概念&#xff0c;逐步分析其操作&#xff0c;并用 Java 实现了标准的 B 树。 1. 2-3 & 2-3-4 Trees 上一节课中讲到的二叉搜索树当数据是随机顺序插入的时候能够使得树变得比较茂密&#xff0c;如下图右侧所示&#xff0c;时间复杂度也就…

【手撕算法】支持向量机(SVM)从入门到实战:数学推导与核技巧揭秘

摘要 支持向量机&#xff08;SVM&#xff09;是机器学习中的经典算法&#xff01;本文将深入解析最大间隔分类原理&#xff0c;手撕对偶问题推导过程&#xff0c;并实战实现非线性分类与图像识别。文中附《统计学习公式手册》及SVM调参指南&#xff0c;助力你掌握这一核心算法…

西门子S7-1200比较指令

西门子S7-1200 PLC比较指令学习笔记 一、比较指令的作用 核心功能&#xff1a;用于比较两个数值的大小或相等性&#xff0c;结果为布尔值&#xff08;True/False&#xff09;。典型应用&#xff1a; 触发条件控制&#xff08;如温度超过阈值启动报警&#xff09;数据筛选&…

SDF,占用场,辐射场简要笔记

符号距离函数&#xff08;Signed Distance Function&#xff0c;SDF&#xff09;的数学公式用于描述空间中任意点到某个几何形状边界的最短距离&#xff0c;并通过符号区分点在边界内外。具体定义如下&#xff1a; 假设 Ω \Omega Ω 是一个几何形状的边界&#xff0c;对于空…

solidwork智能尺寸怎么对称尺寸

以构造轴为中心线就能画智能尺寸的对称尺寸。先点击边再点击构造线

如何从零开始理解LLM训练理论?预训练范式、模型推理与扩容技巧全解析

Part 1&#xff1a;预训练——AI的九年义务教育 &#x1f4da; 想象你往峨眉山猴子面前扔了1000本《五年高考三年模拟》-我那时候还在做的题&#xff08;海量互联网数据&#xff09;&#xff0c;突然有一天它开口唱起《我在东北玩泥巴》&#xff0c;这有意思的过程就是LLM的预…

工程化与框架系列(13)--虚拟DOM实现

虚拟DOM实现 &#x1f333; 虚拟DOM&#xff08;Virtual DOM&#xff09;是现代前端框架的核心技术之一&#xff0c;它通过在内存中维护UI的虚拟表示来提高渲染性能。本文将深入探讨虚拟DOM的实现原理和关键技术。 虚拟DOM概述 &#x1f31f; &#x1f4a1; 小知识&#xff1…

设计模式--spring中用到的设计模式

一、单例模式&#xff08;Singleton Pattern&#xff09; 定义&#xff1a;确保一个类只有一个实例&#xff0c;并提供全局访问点 Spring中的应用&#xff1a;Spring默认将Bean配置为单例模式 案例&#xff1a; Component public class MySingletonBean {// Spring 默认将其…

深入浅出:Spring AI 集成 DeepSeek 构建智能应用

Spring AI 作为 Java 生态中备受瞩目的 AI 应用开发框架&#xff0c;凭借其简洁的 API 设计和强大的功能&#xff0c;为开发者提供了构建智能应用的强大工具。与此同时&#xff0c;DeepSeek 作为领先的 AI 模型服务提供商&#xff0c;在自然语言处理、计算机视觉等领域展现了卓…

CSS浮动详解

1. 浮动的简介 浮动是用来实现文字环绕图片效果的 2.元素浮动后会有哪些影响 对兄弟元素的影响&#xff1a; 后面的兄弟元素&#xff0c;会占据浮动元素之前的位置&#xff0c;在浮动元素的下面&#xff1b;对前面的兄弟 无影响。 对父元素的影响&#xff1a; 不能撑起父元…

python数据类型等基础语法

目录 字面量 注释 变量 查数据类型 类型转换 算数运算符 字符串定义的三种方式 字符串占位 数据输入 字面量 被写在代码中固定的值 六种数据类型: 1 字符串 String 如"egg" 2 数字 Number: 整数int 浮点数float 复数complex :如43j 布尔…

Android 图片压缩详解

在 Android 开发中,图片压缩是一个重要的优化手段,旨在提升用户体验、减少网络传输量以及降低存储空间占用。以下是几种主流的图片压缩方法,结合原理、使用场景和优缺点进行详细解析。 效果演示 直接先给大家对比几种图片压缩的效果 质量压缩 质量压缩:根据传递进去的质…

Flutter状态管理框架GetX最新版详解与实践指南

一、GetX框架概述 GetX是Flutter生态中轻量级、高性能的全能开发框架&#xff0c;集成了状态管理、路由导航、依赖注入等核心功能&#xff0c;同时提供国际化、主题切换等实用工具。其优势在于代码简洁性&#xff08;减少模板代码约70%&#xff09;和高性能&#xff08;基于观…

【linux】详谈 环境变量

目录 一、基本概念 二、常见的环境变量 取消环境变量 三、获取环境变量 通过代码获取环境变量 环境变量的特性 1. getenv函数:获取指定的环境变量 2. environ获取环境变量 四、本地变量 五、定义环境变量的方法 临时定义&#xff08;仅对当前会话有效&#xff09; 永…

LangChain教程 - RAG - PDF问答

系列文章索引 LangChain教程 - 系列文章 在现代自然语言处理&#xff08;NLP&#xff09;中&#xff0c;基于文档内容的问答系统变得愈发重要&#xff0c;尤其是当我们需要从大量文档中提取信息时。通过结合文档检索和生成模型&#xff08;如RAG&#xff0c;Retrieval-Augment…

大白话前端性能优化方法的分类与具体实现

大白话前端性能优化方法的分类与具体实现 一、资源加载优化 1. 压缩与合并文件 大白话解释&#xff1a; 咱们的网页代码里&#xff0c;就像一个房间堆满了东西&#xff0c;有很多没用的“杂物”&#xff0c;比如代码里的空格、注释啥的。压缩文件就是把这些“杂物”清理掉&a…

MySQL并发知识(面试高频)

mysql并发事务解决 不同隔离级别下&#xff0c;mysql解决并发事务的方式不同。主要由锁机制和MVCC(多版本并发控制)机制来解决并发事务问题。 1. mysql中的锁有哪些&#xff1f; 表级锁&#xff1a; 场景&#xff1a;表级锁适用于需要对整个表进行操作的情况&#xff0c;例如…

【Kubernets】K8S内部nginx访问Service资源原理说明

文章目录 原理概述**一、核心概念****二、Nginx 访问 Service 的流程****1. Service 的作用****2. Endpoint 的作用****3. Nginx Pod 发起请求****(1) DNS 解析****(2) 流量到达 kube-proxy****(3) 后端 Pod 处理请求** **三、不同代理模式的工作原理****1. iptables 模式****2…

HTML:自闭合标签简单介绍

1. 什么是自结束标签&#xff1f; 定义&#xff1a;自结束标签&#xff08;Self-closing Tag&#xff09;是指 不需要单独结束标签 的 HTML 标签&#xff0c;它们通过自身的语法结构闭合。语法形式&#xff1a; 在 HTML5 中&#xff1a;直接写作 <tag>&#xff0c;例如 …