Java 零基础入门学习(小白也能看懂!)三

简介: Java 零基础入门学习(小白也能看懂!)三

6.2.3 引用变量

public class Main {
    public static void main(String[] args) {
        int[] arr1 = new int[3];
        arr1[0] = 1;
        arr1[1] = 2;
        arr1[2] = 3;

        int[] arr2 = new int[]{1,2,3,4,5};
        arr2[0] = 100;
        arr2[1] = 200;

        arr1 = arr2;
        arr1[2] = 300;
        arr1[3] = 400;
        arr2[4] = 500;

        for (int x : arr1) {
            System.out.println(x);
        }
    }
}


6.2.4 认识 null

null 在 Java 中表示“空引用”,也就是一个不指向对象的引用

public class Main {
    public static void main(String[] args) {
        int[] arr = null;
        System.out.println(arr[0]);
    }
}

null的作用类似于C语言中的NULL(空指针),都是表示一个无效的内存位置。因此不能对这个内存进行任何读写操作。一旦尝试读写,就会抛出NullPointerException

【注意】:Java 中并没有约定 null 和 0 下标地址的内存有任何关联。


6.3 数组应用场景

6.3.1 保存数据

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3};
        for (int x : arr) {
            System.out.println(x);
        }
    }
}


6.3.2 作为方法的参数

  1. 参数传基本数据类型
public class Main {
    public static void main(String[] args) {
        int num = 0;
        func(num);
        System.out.println("num = " + num);// 0
    }

    private static void func(int x) {
        x = 10;
        System.out.println("x = " + x); // 10
    }
}
  1. 上述代码我们可以发现func方法中修改了形参x的值,不影响实参的num值。
  2. 参数传引用数据类型
public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3};
        fun1(arr);
        System.out.println(Arrays.toString(arr)); // [1,2,3]
        
        fun2(arr);
        System.out.println(Arrays.toString(arr)); // [99,2,3]
    }

    public static void fun1(int[] arr) {
        arr = new int[]{11,22,33,44,55}; // 修改了形参的指向
    }

    public static void fun2(int[] arr) {
        arr[0] = 99; // 形参改变了实惨的值
    }
}


上述代码我们可以发现fun1方法中修改了形参的指向,不影响实参数组的值


fun2方法内部修改了数组的内容,方法外部的数组内容也发生了改变。因为数组是引用类型,按照引用类型进行传递,是可以修改其中存放的内容的。


【总结】:所谓的“引用”本质只是存了地址。Java 将数组设定为引用类型,这样的话后续进行数组参数传参,其实只是将数组的地址传入函数形参中,这样可以避免对整数数组的拷贝(数组可能比较长,那么拷贝开销就会很大)。

6.3.3 作为方法的返回值

public class Main {
    public static void main(String[] args) {
        int[] ret = fun();
        System.out.println(Arrays.toString(ret)); // [1, 2, 3, 4, 5]
    }
    public static int[] fun() {
        int[] arr = new int[]{1,2,3,4,5};
        return arr;
    }
}


6.4 二维数组

二维数组本质上也就是一维数组,只不过每个元素又是一个一维数组

基本语法:

数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };


代码示例:

public class Main {
    public static void main(String[] args) {
        int[][] arr = {{1, 2, 3},{4,5,6}};
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println("=======");

        for (int[] tempArr : arr) {
            for (int x : tempArr) {
                System.out.print(x + " ");
            }
            System.out.println();
        }

        System.out.println("=======");
        String ret = Arrays.deepToString(arr); // deepToString()深度打印
        System.out.println(ret);
    }
}


Java 二维数组在定义的时候是可以省略列的

int[][] arr = new int[2][];


二维数组的用法和一维数组并没有明显差别, 因此我们不再赘述.

同理, 还存在 “三维数组”, “四维数组” 等更复杂的数组, 只不过出现频率都很低.

6.5 不规则数组

代码示例:

public class Main {
    public static void main(String[] args) {
        int[][] arr = new int[2][];

        // 每一个一维数组 进行初始化
        arr[0] = new int[3];
        arr[1] = new int[5];

        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }
}
// 运行结果
0 0 0 
0 0 0 0 0 


7. 类和对象

7.1 面向对象程序设计概述

面向对象程序设计(object-oriented programming,OOP),是当今主流的程序设计范畴,它取代了20世纪70年代的”结构化“或过程式编程技术。

面向对象的程序是由对象组成的,每个对象包含对用户公开的特点功能部分和隐藏的实现部分。

7.1.1 类

(class)是构造对象的模板或蓝图。由类构造(construct)对象的过程称为类的实例(instance)。

封装(encapsulation,有时称为数据隐藏)是处理对象的一个重要概念。封装就是将数据和行为组合在一个包中,并对对象的使用者隐藏具体的实现方式。对象的数据称为实例字段(instance field),操作数据的过程称为方法(method)。


实现封装的关键在于,绝对不能让类中的方法直接访问其他类的实例字段。程序只能通过对象的方法与对象数据进行交互。封装给对象赋予了“黑盒”特征,这是提高重用性和可靠性的关键。这意味着一个类可以完全改变存储数据的方式,只要仍旧使用同样的方法操作数据,其他对象就不会知道也不用关心这个类所发生的变化。

7.1.2 对象

要想使用OOP,一定要清楚对象的三个主要特性:


对象的行为(behavior)——可以对对象完成哪些操作,或者可以对对象应用哪些方法?

对象的状态(state)—当调用那些方法时,对象会如何响应?

对象的标识(identity)——如何区分具有相同行为与状态的不同对象?

同一个类的所有对象实例,由于支持相同的行为而具有家族式的相似性。对象的行为是可调用的方法来定义的。

7.1.3 类之间的关系

在类之间,最常见的关系有:

  • 依赖(uses-a);
  • 聚合(has-a);
  • 继承(is-a)。


依赖(dependence),即“uses-a”关系,是一种最明显、最常见的关系。如果一个类的方法使用或操纵另一个类的对象,我们就说一个类依赖于另一个类。


聚合(aggregation),即“has-a”关系,很容易理解,因为这种关系很具体。包含关系意味着类A的对象包含类B的对象。


继承(inheritance),即“is-a”关系,表示一个更特殊的类与一个更一般类之间的关系。

7.2 类的定义和使用

面向对象程序设计关注的是对象,而对象是现实生活中的实体。

7.2.1 简单认识类

类是用来对一个实体(对象)来进行描述,主要描述该实体(对象)具有哪些属性,哪些功能,描述完成后计算机就可以识别了。

7.2.2 类的定义格式

java中定义 类需要使用class关键字,具体语法如下:

class ClassName{
    field;// 字段 或 成员变量
    method;// 方法 或 成员方法
}


class为定义类的关键字,ClassName为类的名字,{}中为类的主体。

类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类**成员变量**。方法主要说明类具有哪些功能,称为类的成员方法

7.2.3 自定义类

7.2.3.1 定义一个狗类
class Dog {
    // 狗的属性
    public String name;// 狗的名字
    public String color;// 狗的颜色

    // 狗的行为
    public void barks() {
        System.out.println(name + "在旺旺叫");
    }

    public void wag() {
        System.out.println(name + "在摇尾巴");
    }
}

注意事项:

  1. 一般一个文件当中只定义一个类。
  2. main方法所在的类一般要使用public修饰。
  3. public修饰的类必须要和文件相同。


7.3 类的实例化

7.3.1 什么是实例化

定义一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的Dog类。它就是类(一种新定义的类型)有了这些自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)。


用类类型创建对象的过程,称为类的实例化,在java采用new关键字,配合类名来实例化对象。

public class Test {
    public static void main(String[] args) {
        Dog dog1 = new Dog();
        dog1.name = "大黄";
        dog1.color = "黄色";
        dog1.barks();
        dog1.wag();

        Dog dog2 = new Dog();
        dog2.name = "哈士奇";
        dog2.color = "白黑色";
        dog2.barks();
        dog2.wag();
    }
}

// 运行结果:
大黄在旺旺叫
大黄在摇尾巴
哈士奇在旺旺叫
哈士奇在摇尾巴


注意事项

  1. new 关键字用于创建一个对象的实例。
  2. 使用.来访问对象中属性和方法。
  3. 同一个类可以创建多个实例。

7.3.2 类和对象的说明

类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员。

类是一种自定义的类型,可以用来定义常量

一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量

做个比方,类的实例化出对象就像现实中使用建筑设计圈造出房子,类就是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化的对象才能实际存储数据,占用物理空间。

7.4 this 引用

7.4.1 为什么要使用this引用

先看一个日期类的例子:

class Date{
    public int year;
    public int month;
    public int day;

    public void setDate(int y, int m, int d){
        year = y;
        month = m;
        day = d;
    }

    public void printDate(){
        System.out.println(year + "/" + month + "/" + day);
    }
}

public class Test2 {
    public static void main(String[] args) {
        // 构造三个日期类型的对象 d1 d2 d3
        Date d1 = new Date();
        Date d2 = new Date();
        Date d3 = new Date();
        
        // 对d1,d2,d3的日期设置
        d1.setDay(2020,9,15);
        d2.setDay(2020,9,16);
        d3.setDay(2020,9,17);
       
        // 打印日期中的内容
        d1.printDate();
        d2.printDate();
        d3.printDate();
    }
}


以上代码定义了一个日期类,然后main方法中创建了三个对象,并通过Date类中的成员方法对对象进行设置和打

印,代码整体逻辑非常简单,没有任何问题。

但是细思之下有以下两个疑问:


形参名不小心与成员变量名相同

public void setData(int year, int month, int day){
        year = year;
        month = month;
        day = day;
}

那函数体中到底是谁给谁赋值?成员变量给成员变量?参数给参数?参数给成员变量?成员变量参数?估计

自己都搞不清楚了。


三个对象都在调用setDate和printDate函数,但是这两个函数中没有任何有关对象的说明,setDate和

printDate函数如何知道打印的是那个对象的数据呢?

7.4.2 什么是this引用


this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

public void setData(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
}


注意:this引用的是调用成员方法的对象

public class Test {
    public static void main(String[] args) {
        Date d = new Date();
        d.setData(2020,9,15);
        d.printDate();
    }
}


7.4.3 this引用的特性


this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型。

this只能在“成员方法”中使用。

在"成员方法"中,this只能引用当前对象,不能再引用其他对象。

this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器负责将调用成员方法对象的引用传递给该成员方法,this负责来接收。

7.5 对象的构造及初始化

7.5.1 如何初始化对象

java方法内部定义一个局部变量,必须初始化,否则就会编译失败。

要上诉代码编译成功,只需要是在使用a之前,给a设置一个初始值。如果是对象:

public class Test {
    public static void main(String[] args) {
        Date d = new Date();
        d.setData(2020,9,15);
        d.printDate();
    }
}
// 代码正常通过编译

需要调用之前写的setDate方法才可以将具体的日期设置到对象中。通过上述例子发现两个问题:

  1. 每次对象创建好后调用setDate方法设置具体日期,比较麻烦,那对象该如何初始化?
  2. 局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?



7.5.2 构造方法

7.5.2.1 概念

构造方法(也称为构造器)是一种特殊的成员方法,名字必须与类名相同,在创建对象时,编译器自动调用并且在整个对象的生命周期内调用一次

class Date{
    public int year;
    public int month;
    public int day;

    // 构造方法
    public Date(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
        System.out.println("Date(int year, int month, int day)被调用了");
    }

    public void printDate(){
        System.out.println(this.year + "/" +this.month + "/" + this.day);
    }
}

public class Test {
    public static void main(String[] args) {
        Date d = new Date(2020,9,15);
        d.printDate();
    }
}


注意:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。

7.5.2.2 特性


  1. 构造器与类同名
  2. 每一个类可以有一个以上的构造器
  3. 构造器可以有0个、1个或多个参数
  4. 构造器没有返回值
  5. 构造器总是伴随着new操作符一起调用
  6. 构造方法可以重载
class Date{
    public int year;
    public int month;
    public int day;

    // 构造方法
    // 无参构造方法
    public Date() {
    }

    // 带3个参数的构造方法
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public void printDate(){
        System.out.println(this.year + "/" +this.month + "/" + this.day);
    }
}

public class Test {
    public static void main(String[] args) {
        Date d = new Date(2020,9,15);
        d.printDate();
    }
}
// 上述两个构造方法:名字相同,参数列表不同,因此构成了方法重载。


如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的

class Date{
    public int year;
    public int month;
    public int day;

    public void printDate(){
        System.out.println(this.year + "/" +this.month + "/" + this.day);
    }
}

public class Test {
    public static void main(String[] args) {
        Date d = new Date();
        d.printDate();
    }
}

  1. 上述Date类,没有定义任何构造方法,编译器会默认生成一个无参构造器。
    注意:一旦用户定义,编译器就不会生成

  2. 构造方法中,可以通过this调用其他构造方法来简化代码
class Date{
    public int year;
    public int month;
    public int day;

    public Date() {
        this(2005,5,9);// 必须是构造方法的第一条语句
    }

    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public void printDate(){
        System.out.println(this.year + "/" +this.month + "/" + this.day);
    }
}

public class Test2 {
    public static void main(String[] args) {
        Date d = new Date();
        d.printDate();
    }
}


  1. 注意:this(…)必须是构造方法的第一条语句

7.5.3 默认初始化

在上文中提出的第二个问题:为什么局部变量在使用时必须要初始化,而成员变量可以不用呢?

class Date{
    public int year;
    public int month;
    public int day;

    public Date(int year, int month, int day) {
        // 成员变量在定义时,并没有给初始值, 为什么就可以使用呢?
        System.out.println(this.year);
        System.out.println(this.month);
        System.out.println(this.day);
    }

    public void printDate(){
        System.out.println(this.year + "/" +this.month + "/" + this.day);
    }
}

public class Test2 {
    public static void main(String[] args) {
        Date d = new Date(2023,9,17);
    }
}


要搞清楚这个过程,就需要知道new 关键字背后所发生的一些事情:

Date d = new Date(2023,9,17);

在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍一下:

  1. 检测对象对应的类是否加载了,如果没有加载则加载
  2. 为对象分配内存空间
  3. 处理并发安全问题
    比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突

初始化所分配的空间

即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如:

数据类型 默认值
byte 0
char ‘\u0000’
short 0
int 0
long 0L
boolean false
float 0.0f
double 0.0
reference null


  1. 设置对象头信息
  2. 调用构造方法,给对象中各个成员赋值

7.5.4 就地初始化

在声明成员变量的时候,就可以给出初始值。

class Date{
    public int year = 2021;
    public int month = 5;
    public int day = 19;

    public Date() {
    }

    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public void printDate(){
        System.out.println(this.year + "/" +this.month + "/" + this.day);
    }
}

public class Test2 {
    public static void main(String[] args) {
        Date d = new Date(2023,9,17);
        d.printDate();
        Date d1 = new Date();
        d1.printDate();

    }
}
// 运行结果
// 2023/9/17
// 2021/5/19

注意:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中。

8. 封装、继承和多态

面向对象三大特性:封装、继承和多态。

8.1 封装

8.1.1 封装的概念

在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。

封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。

要访问该类的代码和数据,必须通过严格的接口控制。

封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。

适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

8.1.2 为什么封装

封装的目的是保护数据的安全和完整性,同时隐藏数据的实现细节,提高代码的可维护性和可扩展性,具体有以下几个方面的好处:


  • 良好的封装能够减少耦合。
  • 类内部的结构可以自由修改。
  • 可以对成员变量进行更精确的控制。
  • 隐藏信息,实现细节。

8.1.3 封装的实现步骤

  1. 修改属性的可见性来限制属性的访问(用private来修饰),如:
public class Test {
    private String name;
    private int age;
}
  1. 这段代码中,将name age 属性设置为私有的,只有在本类中被访问,其他类访问不了,就实现对信息的隐藏。
  2. 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问,例如:
public class Test {
    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;
    }
}
  1. 采用 this 关键字是为了解决实例变量和局部变量之间发生的同名的冲突。

8.2 继承

8.2.1 继承的概念

继承是 java 面向对象编程技术的一块基石,因为它允许创建分等级层次的类。

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

生活中的继承

兔子和羊属于食草动物,狮子和老虎属于食肉动物。

食草动物和食肉动物又是属于动物。

所有的继承需要符合的关系:is-a,父类更通用,子类更具体

虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性

8.2.2 继承的格式

Java 中通过关键字 extends 来声明一个类是从另一个类继承而来的,一般格式如下:

class 父类 {
    
}
class 子类 extends 父类 {
    
}


8.2.3 为什么继承

接下来我们通过实例的说明这个需求。

开发动物类,其中动物分别为狗和猫,要求如下:


  • 狗:属性(姓名,颜色),方法(吃,叫)
  • 猫:属性(姓名,颜色),方法(吃,叫)
class Dog{
    private String name;
    private String color;

    public void eat() {
        System.out.println(this.name + "正在吃...");
    }

    public void cry() {
        System.out.println(this.name + "正在叫...");
    }
}
class Cat {
    private String name;
    private String color;

    public void eat() {
        System.out.println(this.name + "正在吃...");
    }

    public void cry() {
        System.out.println(this.name + "正在叫...");
    }
}

从这两段代码可以看出来,代码存在重复了,导致后果就是代码量大且臃肿,而且维护性不高(维护性主要是后期需要修改的时候,就需要修改很多的代码,容易出错),所以要从根本上解决这两段代码的问题,就需要继承,将两段代码中相同的部分提取出来组成 一个父类:

class Animal {
    private String name;
    private String color;

    public Animal(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public void eat() {
        System.out.println(this.name + "正在吃...");
    }

    public void cry() {
        System.out.println(this.name + "正在叫...");
    }
}

这个Animal类就可以作为一个父类,然后狗类和猫类继承这个类之后,就具有父类当中的属性和方法,子类就不会存在重复的代码,维护性也提高,代码也更加简洁,提高代码的复用性(复用性主要是可以多次使用,不用再多次写同样的代码) 继承之后的代码:

  • 狗类
class Dog extends Animal{
   public Dog(String name , String color) {
       super(name, color);
   }
}
  • 猫类
class Cat extends Animal {
    public Cat(String name , String color) {
        super(name, color);
    }
}

8.2.4 继承类型

Java 中不支持多继承,但支持多重继承。

8.2.5 继承特性

子类拥有父类非 private 的属性、方法。

子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。

子类可以用自己的方式实现父类的方法。

Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 A 类继承 B 类,B 类继承 C 类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。

提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

8.2.6 super 与 this 关键字

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类

this关键字:指向自己的引用。

class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}

class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}

public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}
// 运行结果
//animal : eat
//dog : eat
//animal : eat


8.2.7 final 关键字

final关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写;

  • 声明类
final class 类名 {
    // 类体
}


  • 声明方法
访问限定符 final 返回值类型 方法名(){
    // 方法体
}

注意:实例变量也可以被定义为final,被定义为final 的变量不能被修改。被声明为final 的类的方法自动声明为final,但是实例变量并不是final


8.3 多态

8.3.1 多态的概念


多态是同一个行为具有多个不同表现形式或形态的能力。

多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:

多态性是对象多种表现形式的体现。

同一个事件发生在不同的对象上会产生不同的结果。

8.3.2 多态的优点

  • 消除类型之间的耦合关系
  • 可替换性
  • 可扩充性
  • 接口性
  • 灵活性
  • 简化性


8.3.3 多态存在的三个必要条件

  1. 继承
  2. 重写
    重写:子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变。即外壳不变,核心重写

重写的好处:在于子类可以根据需要,定义特定于自己的行为。也就是说子类能够根据需要实现父类的方法。

class Animal {
    public void eat() {
        System.out.println("正在吃...");
    }
}

class Dog extends Animal {
    public void eat() {
        System.out.println("狗正在吃狗粮...");
    }
}

class Bird extends Animal {
    public void eat() {
        System.out.println("鸟正在吃鸟粮...");
    }
}

public class Test1 {
    public static void fun(Animal animal) {
        animal.eat();
    }
    
    public static void main(String[] args) {
        Dog dog = new Dog();
        fun(dog);

        Bird bird = new Bird();
        fun(bird);
    }
}
// 运行结果
狗正在吃狗粮...
鸟正在吃鸟粮...
  1. 重写(覆盖)的规则:
  • 方法名相同
  • 参数列表相同【顺序、个数、类型】
  • 返回值相同
  1. 父类引用指向子类对象

比如:

Animal dog = new Dog();

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。

多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理

以下是多态的例子:

abstract class Animal {  
    abstract void eat();  
}  

class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
    public void work() {  
        System.out.println("抓老鼠");  
    }  
}  

class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
    public void work() {  
        System.out.println("看家");  
    }  
}
// 测试类
public class Test {
    
     public static void show(Animal a)  {
      a.eat();  
        // 类型判断
        if (a instanceof Cat)  {  // 猫做的事情 
            Cat c = (Cat)a;  
            c.work();  
        } else if (a instanceof Dog) { // 狗做的事情 
            Dog c = (Dog)a;  
            c.work();  
        }  
    }  
    
    public static void main(String[] args) {
      show(new Cat());  // 以 Cat 对象调用 show 方法
      show(new Dog());  // 以 Dog 对象调用 show 方法

      Animal a = new Cat();  // 向上转型: 子类对象 -> 父类对象 
      a.eat();               // 调用的是 Cat 的 eat
      Cat c = (Cat)a;        // 向下转型: 父类对象 -> 子类对象
      c.work();        // 调用的是 Cat 的 work
  }     
}

// 运行结果
吃鱼
抓老鼠
吃骨头
看家
吃鱼
抓老鼠

8.3.4 instanceof 关键字

Java中可以使用instanceof 关键字判断对象是否是某个类的实例,语法格式如下:

对象 instanceof 类

在上述格式中,如果对象是指定类的实例对象,则返回true,否则返回false

class Animal {
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println(this.name + "正在吃...");
    }
}

class Dog extends Animal {
    public String color;

    public Dog(String name, int age,String color) {
        super(name,age);
        this.color = color;
    }

    public void eat() {
        System.out.println(this.name + "正在吃狗粮...");
    }

    public void barks() {
        System.out.println(this.name + "正在旺旺叫...");
    }
}

class Bird extends Animal {
    public Bird(String name, int age) {
        super(name, age);
    }

    public void eat() {
        System.out.println(this.name + "正在吃鸟粮...");
    }

    public void fly() {
        System.out.println(this.name + "正在飞...");
    }
}

public class Test1 {
    public static void main(String[] args) {
        Animal animal1 = new Dog("旺财",10,"黄色");
        if (animal1 instanceof Bird){ // 判断 dog对象是否是Bird类的实例 如果是则实例化对象,否则打印hell
            Bird bird2 = (Bird)animal1;
            bird2.fly();
        }else {
            System.out.println("hell");
        }
    }
}

9. 接口和抽象类

9.1 抽象类

9.1.1 抽象类的概念

在面向对象的概念中,所有的对象都是通过类来描绘的,但是放过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类

9.1.2 抽象类的语法

在Java 中,一个类如果被abstract 修饰的类成为抽象类,抽象类中被abstract 修饰的方法称为抽象方法,抽象方法不用给出具体的实现体。

抽象类的定义格式如下:

abstract class 抽象类名{
    属性;
    
    // 普通方法
    访问权限 返回值类型 方法名称(参数){
        return [返回值];
    }
    
    // 抽象方法,无方法体
    访问权限 abstract 返回值类型 抽象方法名称(参数);
}

从以上格式可以看出,抽象类的定义比普通类多了抽象方法,类的其他功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样

9.1.3 抽象类的特性

  1. 抽象类不能直接实例化对象


  1. 抽象方法不能是被 private 修饰的

  2. 抽象方法不能被finalstatic修饰,因为抽象方法要被子类重写

抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰,如果一个非抽象类继承了抽象类,那么这个子类必须实现抽象类中的全部抽象方法。

abstract class Shape {
    // 抽象方法
    public abstract  void draw();
}

abstract class A extends Shape {
    public abstract void testA();
}

class B extends A {
    @Override
    public void testA() {

    }
    @Override
    public void draw() {

    }
}


  1. 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
  2. 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量

9.2 接口


接口用来描述类应该做什么,而不指定它们具体应该如何做。一个类可以实现一个或多个接口。有些情况可能要求符合这些接口,主要有这种要求,就可以使用实现了这个接口的类(即实现类)的对象。

9.2.1 接口的概念

在Java程序设计语言中,接口不是类,而是对希望符合这个接口的类的一组需求。

接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用

在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型


9.2.2 接口的语法规则

接口的定义格式与定义类的格式基本相同,将class 关键字换成interface关键字,就定义了一个接口。

public interface 接口名称{
    // 抽象方法
}

注意事项:

  1. 创建接口时,接口的命名一般以大写字母I开头
  2. 接口命名一般使用“形容词”词性的单词。

9.2.3 接口的使用

接口不能直接被使用,必须有一个"实现类"来实现该接口,实现接口的所有的抽象方法。

public class 类名 interface 接口名称{ // 可以使用,分隔,实现多个接口
    // ...
}


注意:子类和父类之间是extends 继承关系,类与接口之间是implements 实现关系。

9.2.4 接口的特性

  1. 接口类型是一种引用类型,但是不能直接new 接口的对象

接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract(只能是

public abstract,其他修饰符都会报错)


  1. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现

  2. 重写接口中方法时,不能使用默认的访问权限

  3. 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量

  1. 接口中不能有静态代码块和构造方法(编译错误)

  2. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
  3. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类

9.2.5 实现多个接口

在Java中,类和类之间是单继承的,一个类只能有一个父类,即Java中不支持多继承但是一个类可以实现多个接口。下面通过类来表示一组动物。

abstract public class Animal {
    public String name;

    public Animal(String name) {
        this.name = name;
    }
}


另外我们再提供一组接口, 分别表示 “会飞的”, “会跑的”, “会游泳的”。

interface IFly {
    void fly();
}

interface IRun {
    void run();
}

interface ISwim {
    void swim();
}


接下来我们创建几个具体的动物:

猫, 是会跑的。

public class Cat extends Animal implements IRun{
    public Cat(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println(this.name + "正在用四条腿跑");
    }
}

鱼,是会游泳的

public class Fish extends Animal implements ISwim{

    public Fish(String name) {
        super(name);
    }
    
    @Override
    public void swim() {
        System.out.println(this.name + "正在游泳");
    }
}

青蛙,既能跑,又能游泳(两栖动物)

public class Fish extends Animal implements IRun,ISwim{

    public Fish(String name) {
        super(name);
    }
    
    @Override
    public void run() {
        System.out.println(this.name + "正在用两条腿跑");
    }
    
    @Override
    public void swim() {
        System.out.println(this.name + "正在游泳");
    }
}


注意:一个类实现多个接口,每个接口的抽象方法都要实现,否则类必须设置为抽象类

而鸭子即可以飞,又能跑、还可以游泳。

public class Duck extends Animal implements IFly,IRun,ISwim{

    public Duck(String name) {
        super(name);
    }

    @Override
    public void fly() {
        System.out.println(this.name + "正在用两个翅膀飞");

    }

    @Override
    public void run() {
        System.out.println(this.name + "正在用两条腿跑");
    }

    @Override
    public void swim() {
        System.out.println(this.name + "正在用两条腿游泳");

    }
}


上面的代码展示了 Java 面向对象编程中最常见的用法: 一个类继承一个父类, 同时实现多种接口。


继承表达的含义是 is-a 语义, 而接口表达的含义是 具有 xxx 特性 .


猫是一种动物,具有跑的特性。


鱼是一种动物,具有游泳的特性。


青蛙是一种,具有跑和游泳的特性。


鸭子是一种动物,具有跑、游泳和飞的特性。


这样设计有什么好处呢? 时刻牢记多态的好处, 让程序猿忘记类型. 有了接口之后, 类的使用者就不必关注具体类型,而只关注某个类是否具备某种能力.例如:现在定义一个方法:testRun

public static void testRun(IRun iRun) {
    iRun.run();
}

在这个testRun方法内部, 我们并不关注到底是哪种动物, 只要参数是会跑的, 就行。

public static void main(String[] args) {
    testRun(new Bird("布谷"));
    testRun(new Duck("唐老鸭"));
    testRun(new Dog("旺财"));
}
// 运行结果
布谷正在用两条腿跑
唐老鸭正在用两条腿跑
旺财正在用四条腿跑


甚至参数可以不是 “动物”, 只要会跑!

class Roboot implements IRun{

    @Override
    public void run() {
        System.out.println("机器人正在用两条腿跑");
    }   
}

public class Test {
    public static void testRun(IRun iRun) {
    iRun.run();
  }
    
    public static void main(String[] args) {
        testRun(new Roboot());
    }
}

// 运行结果
机器人正在用两条腿跑


9.2.6 接口之间的继承

在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到多继承的目的

接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字.

interface IRun {
    void run();
}

interface ISwim {
    void swim();
}

// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRun,ISwim{
    
}
public class Frog extends Animal implements IAmphibious{
    ...
}


通过接口继承创建一个新的接口IAmphibious 表示 “两栖的”. 此时实现接口创建的 Frog 类, 就继续要实现 run 方法, 也需要实现 swim 方法.

接口间的继承相当于把多个接口合并在一起.

9.3 抽象类和接口的区别

抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别。


核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法。


如之前写的 Animal 例子. 此处的 Animal 中包含一个 name 这样的属性, 这个属性在任何子类中都是存在的. 因此此处的 Animal 只能作为一个抽象类, 而不应该成为一个接口.

public class Animal {
    public String name;

    public Animal(String name) {
        this.name = name;
    }
}
区别 抽象类 接口
结构组成: 普通类 + 抽象方法 抽象方法 + 静态常量
权限: 各种权限 public
子类使用: 使用extends关键字继承抽象类 使用implements 关键字实现接口
关系: 一个抽象类可以实现若干接口 接口不能继承抽象类,但是接口可以使用extends 关键字继承多个父接口
子类权限: 一个子类只能继承一个抽象类 一个子类可以实现多个接口


10. String字符串

在程序开发中经常会用到字符串。字符串是指一连串的字符,它是由许多单个字符连接而成的,如多个英文字母所组成的英文单词。字符串可以包含任意字符,这些字符必须包含在一对双引号""之内,例如:“abc”。Java定义了3个封装字符串的类,分别是String类、StringBuffer类和StringBulider类。它们位于java.lang 包中,并提供了一系列操作字符串的方法,这些方法不需要导包就可以直接使用。下面将对String类、StringBuffer类和StringBulider类进行讲解。

10.1 String类

10.1.1 字符串的构造

String类提供了构造方法非常多,常用的就以下三种:

public class Main {
    public static void main(String[] args) {
        // 使用常量串构造
        String s1 = "hello";
        System.out.println(s1);

        // 直接new String对象
        String s2 = new String("hello");
        System.out.println(s2);

        // 使用字符数组进行构造
        char[] chars = {'h','e','l','l','o'};
        String s3 = new String(chars);
        System.out.println(s3);
    }
}


其他方法需要用到时,大家参考Java在线文档:String官方文档

【注意】:

  1. String是引用类型,内部并不存储字符串本身,在String类的实现源码中,String类实例变量如下:




public class Main {
    public static void main(String[] args) {
        // s1和s2引用的是不同对象  s1和s3引用的是同一对象
        String s1 = new String("hello");
        String s2 = new String("world");
        String s3 = s1; // s3这个引用指向了s1这个引用的对象
        System.out.println(s3); // hello

        System.out.println(s1.length());// 获取字符串的长度
        System.out.println(s1.isEmpty());// 如果字符串长度为0,返回true,否则返回false

        String s4 = "";
        System.out.println(s4.length()); // 0
        System.out.println(s4.isEmpty());// true
}


  1. 内存图:

  1. 在Java中""引起来的也是String类型对象
// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());// 5


10.1.2 String对象的比较

字符串的比较是常见操作之一,比如:字符串排序。Java中总共提供了4种方式:

1. ==比较是否引用同一个对象

注意:对于内置类型,==比较的是变量中的值;对于引用类型==比较的是引用中的地址。

public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int c = 10;

        // 对于基本类型变量,==比较两个变量中存储的值是否相同
        System.out.println(a == b);    // false
        System.out.println(a == c);    // true

        // 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
        String s1 = new String("hello");
        String s2 = new String("hello");
        String s3 = new String("world");
        String s4 = s1;
        System.out.println(s1 == s2);   // false
        System.out.println(s2 == s3);   // false
        System.out.println(s1 == s4);   // true
    }
}


2. equals()方法:按照字典序比较

字典序:字符大小的顺序

String类重写了父类Objectequals方法,Objectequals默认按照==比较,String重写equals方法后,按照 如下规则进行比较,比如:s1.equals(s2)


public class Main {
    public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");
        String s3 = new String("Hello");

        // s1、s2、s3引用的是三个不同对象,因此==比较结果全部为false
        System.out.println(s1 == s2);       // false
        System.out.println(s1 == s3);       // false

        // equals比较:String对象中的逐个字符
        // 虽然s1与s2引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true
        // s1与s3引用的不是同一个对象,而且两个对象中内容也不同,因此输出false
        System.out.println(s1.equals(s2));  // true
        System.out.println(s1.equals(s3));  // false
    }
}

【注意】:为什么以下代码输出的结果都是true

答:因为在 Java 中有一块特殊的内存(常量池),存储在堆上。

它的作用是什么呢?


  1. 只要是""双引号括起来的字符串存放在这里。
  2. 存储字符串之前它会找常量池里是否存在这个字符串,如果有就不存放了(常量池不会重复存放相同的值),所以上述代码中s1s2都指向常量池hello的地址。


3. compareTo()方法: 按照字典序进行比较

与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:


先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值

如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值

public class Main {
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("abc");
        String s4 = new String("abcdef");
        // s1 和 s2 比较大小 s1 > s2 返回大于0的数字 s1 < s2 返回小于0的数字 否则返回0
        // 返回差值就是对应acsii码的差值
        System.out.println(s1.compareTo(s2));   // 不同输出字符差值-1
        System.out.println(s1.compareTo(s3));   // 相同输出 0
        System.out.println(s1.compareTo(s4));   // 前k个字符完全相同,输出长度差值 -3
    }
}
4. 忽略大小写比较
  • equalsIgnoreCase()方法:与equals()方式相同,但是忽略大小写比较。
  • compareToIgnoreCase()方法:与compareTo()方式相同,但是忽略大小写比较。
public class Main {
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("Abc");
        System.out.println(s1.equals(s2)); // false
        System.out.println(s1.equalsIgnoreCase(s2)); // true

        System.out.println(s1.compareTo(s2));//32
        System.out.println(s1.compareToIgnoreCase(s2));// 0
    }
}


10.1.3 字符串查找

字符串查找也是字符串中非常常见的操作,String类提供的常用查找的方法

方法 功能
char charAt(int index) 返回index位置上字符,如果index为负数或者越界,抛出 IndexOutOfBoundsException异常
int indexOf(int ch) 返回ch第一次出现的位置,没有返回-1
int indexOf(int ch, int fromIndex) 从fromIndex位置开始找ch第一次出现的位置,没有返回-1
int indexOf(String str) 返回str第一次出现的位置,没有返回-1
int indexOf(String str, int fromIndex) 从fromIndex位置开始找str第一次出现的位置,没有返回-1
int lastIndexOf(int ch) 从后往前找,返回ch第一次出现的位置,没有返回-1
int lastIndexOf(int ch, int fromIndex) 从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返 回-1
int lastIndexOf(String str) 从后往前找,返回str第一次出现的位置,没有返回-1
int lastIndexOf(String str, int fromIndex) 从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返 回-1
public class Main {
    public static void main(String[] args) {
        String s1 = new String("hello");
        // 返回字符串对应下标的字符
        System.out.println(s1.charAt(1)); // e

        //返回对应字符出来的下标位置 从头开始查找
        System.out.println(s1.indexOf('e')); // 1
        //返回对应字符出来的下标位置 从指定位置查找
        System.out.println(s1.indexOf('l', 3)); // 3

        // 字符串查找 从一个字符串找另一个字符串
        System.out.println(s1.indexOf("llo")); // 2
        System.out.println(s1.indexOf("ll", 2));// 2

        // 返回对应字符出来的下标位置 从尾开始向前查找
        System.out.println(s1.lastIndexOf('l'));// 3
        // 返回对应字符出来的下标位置 从指定位置向前查找
        System.out.println(s1.lastIndexOf('l', 1));// -1

        System.out.println(s1.lastIndexOf("ll")); // 2

        System.out.println(s1.indexOf("ll", 1));// 2
    }
}

10.1.4 转换

1. 数值和字符串转化
public class Main {
    public static void main(String[] args) {
        // 数字转字符串
        String s1 = String.valueOf(123);
        System.out.println(s1);

        String s2 = String.valueOf(12.34);
        System.out.println(s2);

        String s3 = String.valueOf(true);
        System.out.println(s3);

        // 字符串转数字
        int num1 = Integer.parseInt("1234");
        System.out.println(num1);
        
        double num2 = Double.parseDouble("12.34");
        System.out.println(num2);
    }
}


2. 大小写转化
public class Main {
    public static void main(String[] args) {
        // 小写转大写
        String s1 = "hello";
        System.out.println(s1.toUpperCase());

        // 大写转小写
        String s2 = "HELLO";
        System.out.println(s2.toLowerCase());
    }
}


问题:转化为大写/小写是在原来的字符串上进行修改的?

答:不是!!!,转化为大写/小写之后,是产生了一个新的对象

通过String类源码中的toUpperCase()方法和toLowerCase()方法返回的都是一个新的字符串。

验证:


3. 字符串转数组
public class Main {
    public static void main(String[] args) {
        // 字符串转数组
        String s1 = "hello";
        char[] chars = s1.toCharArray();
        for (char ch  : chars) {
            System.out.println(ch);
        }
        
        // 数组为字符串
        String s2 = new String(chars);
        System.out.println(s2);
    }
}


4. 格式化
public class Main {
    public static void main(String[] args) {
        String s1 = String.format("%d-%d-%d",2021,5,19);
        System.out.println(s1);
    }
}


10.1.5 字符串替换

使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:

方法 说明
String replaceAll(String regex, String replacement) 替换所有的指定内容
String replaceFirst(String regex, String replacement) 替换收个内容


public class Main {
    public static void main(String[] args) {
        String s1 = "abcabcdeabcd";
        System.out.println(s1.replace('a', 'p')); // pbcpbcdepbcd

        System.out.println(s1.replace("ab","haha")); // hahachahacdehahacd

        System.out.println(s1.replaceAll("ab", "uuu")); // uuucuuucdeuuucd

        System.out.println(s1.replaceFirst("ab", "ha")); // hacabcdeabcd
    }
}

10.1.6 字符串拆分

可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。

方法 功能
String[] split(String regex) 将字符串全部拆分
String[] split(String regex, int limit) 将字符串以指定的格式,拆分为limit组
public class Main {
    public static void main(String[] args) {
        String s1 = "name = zhangsan&age = 18";
        String[] strings = s1.split("&");
        for (int i = 0; i < strings.length; i++) {
            System.out.println(strings[i]);
        }
        
        String s2 = "Hello handsome hello beautiful give me some attention"; 
        // 帅哥美女点点关注
        String[] strings1 = s2.split(" ",12); 
        // 虽然不能分割12次 但是它能够保证能分割的最大次数 不够就不分了
        for (int i = 0; i < strings1.length; i++) {
            System.out.println(strings1[i]);
        }
    }
}


特殊情况:

public class Main {
    public static void main(String[] args) {
        String s1 = "192.168.1.2";
        String[] strings = s1.split("\\.");
        for (int i = 0; i < strings.length; i++) {
            System.out.println(strings[i]);
        }
        System.out.println("=========");

        String s2 = "C:\\APP\\Java\\jdk1.8\\bin\\java.exe";
        String[] strings1 = s2.split("\\\\");
        for (int i = 0; i < strings1.length; i++) {
            System.out.println(strings1[i]);
        }
        System.out.println("=========");
        

        String s3 = "name=zhangsan&age=18";
        String[] strings2 = s3.split("&|=");
        for (int i = 0; i < strings2.length; i++) {
            System.out.println(strings2[i]);
        }
    }
}

【注意事项】:

  1. 字符"|“,”*“,”+“都得加上转义字符,前面加上”\".
  2. 而如果是"“,那么就得写成”\\".
  3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符.


多次拆分:

public class Main {
    public static void main(String[] args) {
        String s1 = "name=zhangsan&age=18";
        String[] strings = s1.split("&");
        for (String x:strings) {
            String[] strings2 = x.split("=");
            for (String x1 :strings2) {
                System.out.println(x1);
            }
        }
    }
}

10.1.7 字符串的截取

从一个完整的字符串之中截取出部分内容。可用方法如下:

方法 功能
String substring(int beginIndex) 从指定索引截取到结尾
String substring(int beginIndex, int endIndex) 截取部分内容


public class Main {
    public static void main(String[] args) {
        String s1 = "helloworld" ;
        System.out.println(s1.substring(5)); // world
        System.out.println(s1.substring(0, 5)); 
        // hello 包含 0 下标的字符, 不包含 5 下标
    }
}


相关文章
|
2月前
|
缓存 安全 Java
《volatile使用与学习总结:》多层面分析学习java关键字--volatile
《volatile使用与学习总结:》多层面分析学习java关键字--volatile
21 0
|
4天前
|
前端开发 Java 编译器
【前端学java】如何从前端视角快速学习Maven
【8月更文挑战第12天】如何从前端视角快速学习Maven
12 2
【前端学java】如何从前端视角快速学习Maven
|
18天前
|
存储 算法 Java
Java零基础(1) - 从零开始学习数组
【8月更文挑战第1天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
24 1
|
11天前
|
Java 测试技术 开发者
Java零基础教学(07):学习正确的命名规范
【8月更文挑战第7天】Java零基础教学篇,手把手实践教学!
39 0
|
2月前
|
安全 Java 编译器
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
25 1
|
2月前
|
消息中间件 负载均衡 Java
学习Java中的反应式编程
学习Java中的反应式编程
|
1月前
|
设计模式 算法 Oracle
Java语言学习路径及学习资源推荐
Java语言学习路径及学习资源推荐
|
2月前
|
Java
JAVA高级部分学习小结(2023.11.4)
JAVA高级部分学习小结(2023.11.4)
|
2月前
|
算法 Java 测试技术
滚雪球学Java(54):从零开始学习Java中的Math类,轻松解决数学难题
【6月更文挑战第8天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
28 0
滚雪球学Java(54):从零开始学习Java中的Math类,轻松解决数学难题
|
2月前
|
缓存 NoSQL Java
Redis系列学习文章分享---第四篇(Redis快速入门之Java客户端--商户查询缓存+更新+双写一致+穿透+雪崩+击穿+工具封装)
Redis系列学习文章分享---第四篇(Redis快速入门之Java客户端--商户查询缓存+更新+双写一致+穿透+雪崩+击穿+工具封装)
40 0