Java 基础学习(七)final、static、抽象

1 final 关键字

1.1 final修饰变量

1.1.1 final概述

final单词直译为“最终的“,在Java中可以用来修饰变量、方法和类:

  • final修饰的变量:可以初始化,不能再更改
  • final修饰的方法:不能在子类中重写
  • final修饰的类:不能再被继承派生出子类了

1.1.2 final修饰局部变量

在方法中声明的变量称为局部变量。

局部变量加final修饰以后,只能初始化一次,不能再次更改。因此 final 修饰的变量可以在声明的同时初始化或者在构造函数中初始化。

注意:当引用类型变量被设置为final时候,表示其值就是引用对象的地址值不能再次修改了,但是此时被引用对象的属性或者元素是可以被修改的。

使用final的目的是保护局部变量的值不变,避免在方法运算期间被意外篡改。如果一个需要反复更改的局部变量就不要使用final修饰。

查看如下所示代码:

 

int 类型的变量a添加了 final 修饰符,则被初始化之后将不能被再次赋值。

另外, final 修饰的变量 arr 是int类型的数组,也是只能被初始化一次不能再次被修改。但是因为变量 arr 是引用类型,其值是数组对象的首地址(初始化以后不能再次被修改),即变量arr与数组之间的引用关系不能发生改变了;但是数组的内容是可以改变的。因此可以给数组的元素赋值,但是不能给 arr 重新定义。

1.1.3【案例】final修饰局部变量示例

编写代码,测试 final 修饰的基本类型变量和引用类型变量。

案例示意代码如下:

import java.util.Arrays;
public class FinalDemo1 {public static void main(String[] args) {final int a;a = 8; //第一次为变量赋值,称为初始化System.out.println(a); ////a = 9; //编译错误,a不能再次被修改final int b = 9; //声明变量直接初始化System.out.println(b);//b = 10; //编译错误,不能再次修改final变量//final修饰的引用类型变量://引用类型变量初始为一个地址值后不能再次修改final int[] arr = {5, 6};//arr中存储的数组地址不能再次修改类//arr引用不能修改,但是被引用对象的内容可以修改arr[0] = 9;System.out.println(Arrays.toString(arr)); //[9, 6]//不可以更改arr变量的值,因为arr是final类型的!//arr = new int[8];final Ball ball = new Ball();ball.d = 10;System.out.println(ball.d);//不能更换ball的值,也就是地址值//ball = null;}
}
class Ball{int d = 5;
}

1.1.4 final修饰方法的参数

Java中方法参数也是一种局部变量,只是其声明位置是方法参数,在接收到传递参数的时候初始化。

在方法参数上可以使用final修饰。final修饰以后也是初始化以后不能再次修改,由于方法参数是在调用方法传递参数值时候初始化的,所以在方法运行期间方法参数变量的值不能修改了。

使用final修饰方法参数的好处也是保护变量的值,避免在方法运行期间参数变量的值被意外篡改。

查看如下代码示例:

 

方法 test 的第二个参数被声明为 final,在方法内部不能再修改其数值了。

1.1.5【案例】final修饰方法参数示例

定义带两个参数的方法(其中一个参数用 final 修饰),编写代码,测试 final 修饰的参数的使用。

案例示意代码如下:

public class FinalDemo2 {public static void main(String[] args) {test(5,6);test(7,8);}public static void test(int a, final int b) {a = 9;//b = 8; //编译错误,不能再次更改变量bSystem.out.println("a:"+a+",b:"+b);}
}

1.1.6 final修饰实例变量

在类中声明的对象属性,由于是属于每个对象实例的变量所以也称为“实例变量”。

final可以修饰实例变量,在final修饰实例变量时候必须直接初始化或者在构造器中初始化,并且实例变量也是在初始化以后不能再次改变了。

使用final修饰实例变量的目的也是保护实例变量,使其值在初始化以后不能改变,避免程序的意外篡改。比如如果希望一个对象的唯一ID编号,在初始化以后不能改了,就可以利用final修饰。

在实际开发中很少使用final修饰的实例变量!主要原因是不方便对象的复用。很多Java底层框架都会利用对象池重复使用对象,避免反复创建销毁对象的性能开销,如果对象属性是final的,就无法再次进行赋值重用对象了!

查看如下代码示例:

 

类 Eoo 的实例变量 a 和 b,都声明为 final,在 main 方法中测试发现,创建 Eoo 对象后,可以访问该属性,但是不能修改它。

1.1.7【案例】final修饰实例变量示例

为类定义 final 修饰的实例变量并编写代码测试其特点。

案例示意代码如下:

public class FinalDemo3 {public static void main(String[] args) {Eoo eoo = new Eoo(8);System.out.println(eoo.a); //5System.out.println(eoo.b); //8//不能再次更改final的实例变量//eoo.a = 9;//eoo.b = 10;Eoo e2 = new Eoo(10);System.out.println(e2.a);System.out.println(e2.b);}
}
class Eoo {//final的属性必须初始化final int a = 5;final int b;public Eoo(int b) {this.b = b;}
}

1.2 final修饰方法

1.2.1 final修饰方法

方法上可以使用final修饰,final的方法在子类中不能被重写修改了。简单理解:final方法不能被重写。final修饰的方法不会影响方法在当前类中的使用,但是如果派生了子类,则在子类中不能重写修改父类中定义的final方法。

final方法的好处是避免被子类使用重写语法修改方法的功能,保护方法的功能是“最终”版本。如果需要保护方法的功能,避免在子类中重写修改,就可以使用final进行声明。

但是在实际工程项目中很少使用final方法,原因是很多框架工具都会采用“动态代理”技术代理(重写)对象的功能,实现灵活的软件功能,如果使用final的方法将直接影响这些框架功能!很多些软件开发企业在编程规范中明确规定:不能声明final方法!

查看如下示例:

 

类 Foo 中的方法 test() 添加了 final 修饰符,可以被子类继承但是不能被子类重写。

1.2.2【案例】final修饰方法示例

为类定义 final 修饰的方法并编写代码测试其特点。

案例示意代码如下:

public class FinalDemo4 {public static void main(String[] args) {Foo foo = new Foo();foo.test();SubFoo sf = new SubFoo();sf.test();}
}
class Foo{public final void test() {System.out.println("Foo.test()");}
}
class SubFoo extends Foo{//public void test() { //编译错误,不能重写Foo中的final方法//    System.out.println("SubFoo.test()");//}
}

1.3 final修饰类

1.3.1 final修饰类

类名也可以使用final修饰,被final修饰的类将不能再派生子类了,也就是终结了类的继承。简单理解:final类不能被继承。

final类的好处和final方法类似,也是可以避免被继承和重写,避免被子类修改功能。Java的很多核心API,都是final类型,这样就保护了这些非常重要的API功能。这些API包括:String、Math、Integer、Double、Long等。这些API都不能派生子类。

在开发中也不允许使用final声明类,原因也是因为声明final类以后,造成很多框架无法采用“动态代理”技术代理扩展对象的功能,很多些软件开发企业在编程规范中明确规定:不能声明final类!

查看如下示例:

 

类Goo添加了 final 修饰符,则不能被继承。

1.3.2【案例】final修饰类示例

定义 final 修饰的类,并编写代码测试其特点。

案例示意代码如下:

public class FinalDemo5 {public static void main(String[] args) {Goo goo = new Goo();goo.test();}
}
final class Goo{public void test() {System.out.println("test()");}
}
//class SubGoo extends Goo{ //编译错误,不能继承final类
//}

2 static 关键字

2.1 静态变量

2.1.1 成员变量

作为类的成员,在类体中声明的变量称为成员变量,成员变量有三种:

  • 一种是实例变量:是属于每个对象属性,每个对象中都有一份
  • 一种是静态变量:是属于类的变量,只有一份,全体对象共享的同一份变量
  • 一种是常量:是不变的常数

成员变量示例如下:

 

2.1.2 静态变量

使用static修饰类的成员变量,称为静态变量。静态变量只有一份,是可以被全体对象共享的一份变量,这点与实例变量有着巨大的差异。实例变量是每个对象实例都有一份的变量。而静态变量是无论用类创建多少对象,都始终唯一的变量。

静态变量和类的信息一起存储在方法区,是属于类的变量。

可以用静态变量存储程序中只有一个就够的数据,比如:办公软件项目中的公司名称和公司LOGO,地图应用中的各类图标,只需要加载一份就可以了。多份相同的数据反而会浪费大量的时间和存储空间。

2.1.3 静态变量的访问

因为静态变量是属于类的变量,所以使用“类名.变量名”访问,在类的内部可以省略类名。

静态变量关键点:

  • 静态变量只有一份,可以被全体对象共享
  • 软件中只有一份的数据应该使用static修饰

查看如下示例:

 

类Foo定义了静态变量 b,使用 Foo.b 访问。

2.1.4【案例】静态变量示例

在类中定义静态变量,并编写代码测试其特点。

案例示意代码如下:

public class StaticDemo1 {public static void main(String[] args) {Soo s1 = new Soo();Soo s2 = new Soo();s1.a = 8;s2.a = 10;Soo.b = 11; //使用类名访问静态变量System.out.println(s1.a + "," + s1.b); //8,11System.out.println(s2.a + "," + s2.b); //10,11System.out.println(Soo.b); //11 读取静态变量}
}
class Soo{int a;        //实例变量、对象属性static int b; //静态变量
}

2.1.5 静态变量工作原理

在面试中经常有问起静态变量工作原理的。简单的说就是静态变量在类加载期间在方法区中分配,静态变量是属于类的变量。

静态变量的具体工作原理是:

1、Java源文件经过编译得到字节码文件,每个类编译为一个class文件

2、当执行Java程序时候,每用到一个类Java就会自动将对应的字节码加载到方法区

  • 创建对象时候会自动加载类
  • 访问类的静态属性时候会自动加载类
  • 执行类中的静态方法时候会自动加载类
  • 字节码文件只加载一次

3、如果类中有静态变量,Java就会在加载类期间将其在方法区中分配出来,静态变量也初始化一次,只有一份

4、创建对象时候按照类中声明的实例变量分配对象的属性,每创建一个对象,就会分配一组对象属性。

工作原理如下图所示:

 

2.1.6 static final

Java中同时使用static final关键字声明“常量”,常量用于声明不会变化的量。比如:数学中的圆周率PI、自然常数e,物理学中的光速C,都是常量。在软件开发中也会将固定不变的数值声明为常量。比如程序中给用户的提示信息,一般是固定值,就可以声明为常量。 如下所示:

public class Message {public static final String MSG_LOGINFAILED = “用户名或密码错误”;public static final String MSG_LOGINSUCC = “登录成功”;
}

2.1.7 常量的细节

软件中不能改变的数据,应该都定义为常量 :同时使用static final修饰,两个关键字的顺序可以调换。

常量必须初始化,其命名建议都是大写字母,多个单词使用下划线隔开,比如 MAX_VALUE。

Java API中提供了很多常量:

  • Math.PI、 Math.E
  • Integer.MAX_VALUE、Integer.MIN_VALUE
  • Long.MAX_VALUE、Long.MIN_VALUE

2.2 静态方法

2.2.1 静态方法

所谓的静态方法就是在方法声明时候添加static关键字。添加了静态关键字的方法称为静态方法,静态方法是属于类的方法。属于类的方法就可以直接使用类名直接引用方法。比如:Math.random()就是一个静态方法。

查看如下示例:

 

对于 Person 类的 add() 方法,它没有用到当前的属性,则可以定义为静态方法。在使用时,使用类名.方法名() 的方式调用。

2.2.2 静态方法的细节

当一个方法其方法体中没有用到任何当前对象的属性时候,则此方法就可以定义为静态方法。相反如果方法用到了当前对象的数据,就不能定义为静态方法。这也是是否在方法前面添加static关键字的原则。由于静态方法与对象数据无关,所以静态方法可以使用类名直接访问。

静态方法和对象方法还有一个区别就是,静态方法没有隐含的局部变量this。而对象方法中是保护隐含局部变量this,对象方法就是通过这个this引用访问了当前对象的属性和方法。由于这个差别,就有一个现象:静态方法不能访问实例变量和对象方法。

因为main方法也是静态方法,所以main方法也不能访问当前类型的实例变量和对象方法。

2.2.3【案例】静态方法示例

在类中定义静态方法,并编写代码测试其特点。

案例示意代码如下:

public class StaticDemo2 {public static void main(String[] args) {Person.add(7, 8); //用类名调用静态方法Person tom = new Person("Tom");tom.whoru(); //用对象引用调用对象的方法}
}
class Person{String name;public Person(String name) {this.name = name;}public void whoru() {//对象方法中包含隐含局部变量thisSystem.out.println("我是"+this.name);}//如果方法中没有用到当前对象的属性/方法就声明为staticpublic static void add(int a, int b) {//静态方法中没有隐含局部变量thisSystem.out.println(a+b);}
}

2.3 static 其他用法

2.3.1 代码块

在类中可以使用{}定义代码块,代码块在创建对象时候按照顺序执行,其功能与构造器类似,可以用于初始化对象属性。代码示意如下:

class Cell{int a;{//代码块,在创建对象时候执行a = (int)(Math.random()*8);}
}

大多情况下优先使用构造器初始化对象属性,代码块很少被使用,了解即可。

2.3.2 静态代码块

类中使用static修饰的代码块称为静态代码块。

静态代码块在类加载期间执行,因为Java类只加载一次,所以静态代码块也只执行一次。就是因为这个特性,经常用静态代码块初始化类中的静态属性。如:将图片资源定义为静态属性,然后利用静态代码块加载图片文件,初始化静态图片属性。

静态代码块的使用示例如下:

 

2.3.3【案例】静态代码块示例

定义并测试静态代码块,案例示意代码如下:

public class StaticDemo3 {public static void main(String[] args) {//Java会在创建对象之前自动加载类CircleCircle c1 = new Circle();Circle c2 = new Circle();System.out.println(Circle.angle);}
}
class Circle{static double angle; //角static {//静态代码块,在类加载期间执行,只执行一次System.out.println("初始化angle");angle = Math.PI * 2;}
}

2.3.4 静态导入

Java 8 提供了静态导入语法,用于简化静态资源的编码,其语法为:import static。例如:

import static java.lang.Math.PI;
import static java.lang.Math.sin;
import static java.lang.Math.*;

使用示例如下:

 

3 abstract 抽象

3.1 抽象类

3.1.1 什么是抽象类

使用抽象关键字abstract声明的类是抽象类,抽象类不能直接实例化创建对象。

这个定义看上去非常茫然,究其原因是因为在面向对象设计时候,会利用“泛化”将子类的共同属性和方法抽取出来设计出父类,此时的父类往往是半成品类,只包含部分属性和方法,甚至属性值都没有合理初始化,如下图所示:

 

如果直接创建对象并且使用有可能造成各种不理想结果,甚至是异常故障。

可以用抽象父类来解决这个问题。

3.1.2 抽象类示例

为便于理解抽象类的作用,我们先开发一个不使用抽象类的案例,查看此时可能存在的问题。

/*** Person类的作用是为子类提供代码复用*/
public class Person {String name;int age;public void whoru() {System.out.println("我是"+name);}
}
package day07.abstract01;
public class Student extends Person{public Student(String name, int age) {this.name = name;this.age = age;}public void study() {System.out.println("学习");}
}
package day07.abstract01;
public class Teacher extends Person{public Teacher(String name, int age) {this.name = name;this.age = age;}public void teach() {System.out.println("讲课");}
}
package day07.abstract01;
public class Worker extends Person{public Worker(String name, int age) {this.name = name;this.age = age;}public void work() {System.out.println("工作");}
}
package day07.abstract01;
public class AbstractDemo1 {public static void main(String[] args) {Student s = new Student("Tom", 12);Teacher t = new Teacher("Andy", 28);Worker w = new Worker("Jerry", 28);s.whoru();s.study();t.whoru();t.teach();w.whoru();w.work();//问题:如果能够直接创建Person对象,其方法运算结果不理想Person p = new Person();p.whoru();}
}

上面案例的运行结果如下所示:

 

上述运行结果中创建Person类型对象,调用其whoru()方法,得到结果是null。

这个结果并不理想,就像生活中问一个人是谁,回答“佚名”一样。造成这个结果的原因是:泛化出来的父类Person 是个半成品类,创建其对象后,其name属性没有合理初始化,导致输出了name的默认值 null。

如何解决上述问题呢?需要明确表示 Person是一个半成品类,不能直接实例化。

因此,就可以使用abstract修饰一下Person类型,使其成为抽象类,这样Java的编译器就会限制Person类型,不允许其直接实例化创建对象。不能被实例化,就不可能造成后续结果了。所以合理使用abstract类,可以避免创建不应该创建的对象,减少程序的错误。

将上述案例中的Person类声明为抽象类,可避免出现创建半成品实例的情况。案例代码示意如下:

/*** Person类的作用是为子类提供代码复用*/
public abstract class Person {String name;int age;public void whoru() {System.out.println("我是"+name);}
}
package day07.abstract02;
public class AbstractDemo2 {public static void main(String[] args) {Student s = new Student("Tom", 12);Teacher t = new Teacher("Andy", 28);Worker w = new Worker("Jerry", 28);s.whoru();s.study();t.whoru();t.teach();w.whoru();w.work();//问题:如果能够直接创建Person对象,其方法运算结果不理想//Java编译器检查,不允许创建抽象类型的对象!//Person p = new Person();//p.whoru();}
}

3.1.3 抽象类不可以实例化

面向对象设计时候根据子类泛化得到的半成品父类,应该定义为抽象类,这样可以限制创建半成品类的对象,减少意外的错误发生。

正因为抽象类不可以被实例化,因此 abstract 和 final 不可以同时修饰一个类:final 关键字使得类不可被继承,而抽象类既不能能被继承,又不能被实例化,则没有任何意义。

使用抽象类时:

1、在类名前面添加abstract关键字以后就是抽象类了

2、抽象类可以作为父类被子类继承,可以定义变量

3、抽象类不能直接创建对象

3.2 抽象方法

3.2.1 什么是抽象方法

使用abstract关键字声明,不包含方法体的方法称为抽象方法。

这个定义同样晦涩,究其原因是因为在利用泛化设计父类时候,有这种情况全体子类都有相同的方法,但是每个具体方法实现都并不相同,这样只能将方法名抽取到父类,方法体留在每个子类中,这种只有方法名称的方法,就是抽象方法。

3.2.2 抽象方法的语法

抽象方法的语法:

1、使用abstract声明方法,不能有方法体

2、包含抽象方法的类必须声明为抽象类,因为包含抽象方法的类一定是不完整的半成品类

3、子类继承抽象类时候必须重写(实现)抽象方法,否则出现编译错误

  • 可以将抽象方法看作父类对子类的行为约定,必须被子类重写实现

实际使用时,如何选择抽象方法?建议规则:每个子类都有,但是每个子类实现都不同的方法泛化为抽象方法!

3.2.3【案例】抽象方法示例

定义抽象类,并包含抽象方法;定义子类继承自抽象类,并重写抽象方法。编写代码测试其特点。

案例示意代码如下:

/*** Person类的作用是为子类提供代码复用* 设计为抽象类,只能被继承,不能创建对象*/
public abstract class Person {String name;int age;public void whoru() {System.out.println("我是"+name);}/*** 日程计划*/public abstract void schedule();
}
package day07.abstract03;
public class Student extends Person {public Student(String name, int age) {this.name = name;this.age = age;}public void study() {System.out.println("学习");}public void schedule() {System.out.println("吃饭、听课");}
}
package day07.abstract03;
public class Student extends Person {public Student(String name, int age) {this.name = name;this.age = age;}public void study() {System.out.println("学习");}public void schedule() {System.out.println("吃饭、听课");}
}
package day07.abstract03;
public class Worker extends Person {public Worker(String name, int age) {this.name = name;this.age = age;}public void work() {System.out.println("工作");}public void schedule() {System.out.println("吃饭、开车");}
}
package day07.abstract03;
public class AbstractDemo3 {public static void main(String[] args) {Student s = new Student("Tom", 12);Teacher t = new Teacher("Andy", 28);Worker w = new Worker("Jerry", 28);s.schedule();t.schedule();w.schedule();}
}

3.2.4 抽象类的意义

综合抽象类和抽象方法的讲解,可以简单理解抽象类的意义如下:

  • 为其子类提供一个公共的类型
  • 封装子类中的重复内容(成员变量和方法)
  • 定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的

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

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

相关文章

C - 语言->内存函数

目录 系列文章目录 前言 1. memcpy使⽤和模拟实现 1.2 memcpy函数的模拟实现: 2. memmove 使⽤和模拟实现 2.1memmove的模拟实现: 3. memset 函数的使⽤ 4. memcmp 函数的使⽤ 系列文章目录 ✅作者简介:大家好,我是橘橙黄又青&#xff…

C++[面向对象的程序设计]_基础入门(中)(万字总结)(建议收藏!!!)

目录 2. C 核心编程 2.1 程序的内存模型 2.1.1 内存四区 - 代码区 2.1.2 内存四区 - 全局区 2.1.3 内存四区 - 栈区 2.1.4 内存四区 - 堆区 2.1.5 new 运算符 2.2 C 中的引用 2.2.1 引用的基本语法 2.2.2 引用的注意事项 2.2.3 引用做函数参数 2.2.4 引用做函数返回…

VMALL 商城系统

SpringBoot MySQL Vue等技术实现 技术栈 核心框架:SpringBoot 持久层框架:MyBatis 模板框架:Vue 数据库:MySQL 阿里云短信,对象存储OSS 项目包含源码和数据库文件。 效果图如下:

双十二哪款超声波清洗机性价比高?性价比高超声波清洗机推荐

距离双十二还有一天时间了,有没有眼镜党朋友还没有选购好超声波清洗机。眼镜清洗用超声波清洗机清洗可以非常省事,不仅能清洗眼镜还可以清洗日常生活中的一些小物件,可以说是非常方便的一个智能清洁工具,非常适合上班族以及眼镜党…

SpringDataJPA基础

简介 Spring Data为数据访问层提供了熟悉且一致的Spring编程模版,对于每种持久性存储,业务代码通常需要提供不同存储库提供对不同CURD持久化操作。Spring Data为这些持久性存储以及特定实现提供了通用的接口和模版。其目的是统一简化对不同类型持久性存储…

静态SOCKS5的未来发展趋势和新兴应用场景

随着网络技术的不断发展和进步,静态SOCKS5代理也在不断地完善和发展。未来,静态SOCKS5代理将会呈现以下发展趋势和新兴应用场景。 一、发展趋势 安全性更高:随着网络安全问题的日益突出,用户对代理服务器的安全性要求也越来越高…

Java项目-瑞吉外卖Day2

完善登录功能: 完善未登录不能访问/backend/index.html。使用拦截器或过滤器。 创建过滤器。 重写doFilter方法。 查看是否过滤成功。 处理流程如下: 添加员工功能: 点击保存,可以看到请求信息。 再看前端代码&a…

「大模型摇摇乐」硬核教程:零基础搞定文案生成应用!

大模型趣味赛「大模型摇摇乐」活动火热进行中。想要更加了解本次活动的规则并拿到更丰富的奖励吗?快来看本教程吧!本文将以“AI 一键生成文案”为例进行教程讲解~ 项目简介 设计背景 为什么做这个项目 在社交媒体日益流行的时代&#xff…

PC端视频网站系统源码 系统自带采集功能 附带完整的搭建教程

近年来,视频内容已成为人们日常生活中不可或缺的一部分。下面罗峰给大家分享一款PC端视频网站系统源码,该系统具有强大的采集功能,可轻松实现视频内容的自动更新和丰富。并附带完整的搭建教程,帮助您快速构建属于自己的视频网站。…

Java+Swing: 连接数据库并完成登录验证 整理10

1. 封装连接数据库的工具类 package com.utils;import java.sql.*;/*** Author:xiexu* Date:2023/12/11 10:13*/ // 连接数据库的工具类 public class DBUtil {private static final String URL "jdbc:mysql://localhost:3306/student_score?use…

tidb安装 centos7单机集群

安装 [rootlocalhost ~]# curl --proto https --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh [rootlocalhost ~]# source .bash_profile [rootlocalhost ~]# which tiup [rootlocalhost ~]# tiup playground v6.1.0 --db 2 --pd 3 --kv 3 --host 192.168.1…

智能优化算法应用:基于缎蓝园丁鸟算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于缎蓝园丁鸟算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于缎蓝园丁鸟算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.缎蓝园丁鸟算法4.实验参数设定5.算法…