JavaSE-04笔记【面向对象01】

文章目录

  • 1. final 关键字
    • 1.1 采用final修饰的类不能被继承
    • 1.2 采用 final 修饰的方法不能被覆盖
    • 1.3 采用 final 修饰的变量(基本类型)不能被修改
    • 1.4 采用final 修饰的变量必须显示初始化
    • 1.5 如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值,但被指向的对象是可以修改的
    • 1.6 如果final修饰实例变量,则系统不再会给该实例变量赋默认值
  • 2. 抽象类(也是引用数据类型)
    • 2.1 一道面试题
    • 2.2 抽象类不能实例化
    • 2.3 抽象的方法只需在抽象类中,提供声明,不需要实现,起到了一个强制的约束作用,要求子类必须实现
    • 2.4 如果这个类是抽象的,那么这个类被子类继承,抽象方法必须被覆盖。如果在子类中不覆盖该抽象方法,那么必须将此方法再次声明为抽象方法
    • 2.5 抽象类不能被 final 修饰
    • 2.6 抽象方法不能被 final 修饰
    • 2.7 抽象类中可以没有抽象方法
    • 2.8 抽象类虽无法实例化,但是可以有构造方法,供子类使用
  • 3. 接口(行为)
    • 3.1 接口中的方法默认都是 public abstract 的,不能更改
    • 3.2 接口中的变量是 public static final 类型的,不能更改,所以必须显式地初始化
    • 3.3 接口不能被实例化,接口中没有构造方法的概念
    • 3.4 接口之间可以继承,但接口之间不能实现
    • 3.5 如果一个类实现了接口,那么接口中所有的方法必须实现
    • 3.6 一类可以实现多个接口
    • 3.7 接口是一种特殊的抽象类,可以使用多态
    • 3.8 接口与接口之间进行强制类型转换时,没有继承关系,也可以强转,但是在运行时可能会出现`ClassCastException`异常
    • 3.9 一个类可以同时继承抽象类和实现接口
  • 4. 接口的进一步应用
  • 5. 抽象类与接口的区别

1. final 关键字

final 表示不可改变的含义

  • 采用 final 修饰的类不能被继承(String类就被final修饰了,其不可以被继承!!!);
  • 采用 final 修饰的方法不能被覆盖;
  • 采用 final 修饰的变量不能被修改,只能赋一次值;
  • final 修饰的变量必须显示初始化;
  • 如果修饰的引用,那么这个引用只能指向一个对象(该引用所保存的地址不不能改变,也不能重新赋值为null),也就是说这个引用不能再次赋值【因为引用也是一个变量!】,但被指向的对象是可以修改的;
  • 构造方法不能被 final 修饰;
  • 会影响 JAVA类的初始化:final 定义的静态常量调用时不会执行 java 的类初始化方法,也就是说不会执行 static 代码块等相关语句,这是由 java 虚拟机规定的。我们不需要了解的很深,有个概念就可以了。 【针对这句话可以查看博客:调用final static变量是否会触发类初始化(执行静态代码块)】

1.1 采用final修饰的类不能被继承

如下代码:

public class FinalTest01 {public static void main(String[] args) {}
}final class A{public void test01(){}
}//不能继承 A,因为 A 采用 final 修饰了
class B extends A{public void test01(){}
}

编译报错:
在这里插入图片描述

1.2 采用 final 修饰的方法不能被覆盖

如下代码:

public class FinalTest02 {public static void main(String[] args) {}
}class A1{//采用final修饰的方法public final void test01(){ }
}class B1 extends A1{//覆盖父类的方法,改变其行为//因为父类的方法是 final 修饰的,所以不能覆盖public void test01(){}
}

编译报错:
在这里插入图片描述

1.3 采用 final 修饰的变量(基本类型)不能被修改

如下代码:

public class FinalTest03 {private final long id = 24353465456575677L;public static void main(String[] args) {id = 454657686787987978L;}
}

编译报错:
在这里插入图片描述

1.4 采用final 修饰的变量必须显示初始化

如下代码:

public class FinalTest04 {// 如果是 final 修饰的变量必须初始化private final long id;public static void main(String[] args) {int i;// 局部变量如果要使用也必须初始化System.out.println(i);}
}

编译报错:
在这里插入图片描述
在这里插入图片描述

1.5 如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值,但被指向的对象是可以修改的

如下代码;

public class FinalTest05 {public static void main(String[] args) {Person p1 = new Person();//可以赋值p1.name = "张三";System.out.println(p1.name);final Person p2 = new Person();p2.name = "李四";System.out.println(p2.name);//不能编译通过//p2 采用 final 修饰,主要限制了 p2 指向堆区中的地址不能修改(也就是p2 只能指向一个对象)//p2 指向的对象的属性是可以修改的p2 = new Person();p2.name = "王五";}
}class Person {String name;
}

编译报错:
在这里插入图片描述

1.6 如果final修饰实例变量,则系统不再会给该实例变量赋默认值

如果final修饰实例变量,则系统不再会给该实例变量赋默认值【因为这样的话,该实例变量就无法再被赋值】,此时,必须由程序员手动赋值!!!
如下代码:

class Person {final String name;
}

编译报错:
在这里插入图片描述
手动赋值要么在声明后直接=,要么在构造方法中赋值!

  1. 在声明后直接=
class Person {final String name="Wang"; //可以,不报错
}
  1. 在构造方法中赋值
class Person {final String name;public Person(){this.name = "Wang"; //也可以实际上与声明时直接=是等价的,上面也是在构造方法执//行时才执行,声明时只是开辟空间,没有立刻赋值}
}

一个小回顾:实例变量在什么时候进行赋默认值(初始化)?
                      =>在构造方法执行过程中(new 的时候赋值!)

注意:一般final会与static联合使用,这样的变量为常量【其一般也是public的】。

2. 抽象类(也是引用数据类型)

看以前示例中的 Animal、Cat 和 Dog,从我们使用的角度来看要对 Cat 和 Dog 进行实例化,Person 中主要包含了一些公共的属性和方法,而 Animal 我们通常不会实例化,所以我们可以把它定义成抽象的:

  • 在 java 中采用 abstract 关键字定义的类就是抽象类,采用 abstract 关键字定义的方法就是抽象方法;
  • 抽象的方法只需在抽象类中,提供声明,不需要实现;
  • 如果一个类中含有抽象方法,那么这个类必须定义成抽象类;
  • 如果这个类是抽象的,那么如果这个类被子类继承,抽象方法必须被重写。如果在子类中不复写该抽象方法,那么必须将此类再次声明为抽象类【抽象类的子类也可以是抽象类 】;
  • 抽象的类是不能实例化的,就像现实世界中人其实是抽象的,张三、李四才是具体的;
  • 抽象类不能被 final 修饰;
  • 抽象方法不能被 final 修饰,因为抽象方法就是被子类实现的;
  • 抽象类中并不要求一定具有抽象方法;
  • 抽象类中可以定义一些普通方法和属性,将一些公共的代码放到抽象类中,另外在抽象类中可以定义一些抽象的方法,这样就会存在一个约束,而子类必须实现我们定义的方法,如:Cat 必须实现 move方法,Dog也必须实现 move方法,方法名称不能修改,必须为 move,这样就能实现多态的机制,有了多态的机制,我们在运行期就可以动态的调用子类的方法。所以在运行期可以灵活的互换实现。

图形的例子:
在这里插入图片描述

2.1 一道面试题

在java中凡是没有方法体的方法都是抽象方法吗?

=>不对,Object类中就有很多方法没有方法体,都是以’;'结尾的,但是他们都不是抽象方法,例如public native int hashcode();这个方法就没有用abstract修饰,其底层调用的是C++的动态链接库,其中native表示调用JVM本地程序。

2.2 抽象类不能实例化

public class AbstractTest01 {public static void main(String[] args) {//不能实例化抽象类//抽象类是不存在,抽象类必须有子类继承
//        Person p = new Person();//以下使用是正确的,因为我们 new的是具体类Person p1 = new Employee();p1.setName("张三");System.out.println(p1.getName());}
}
//采用 abstract 定义抽象类
//在抽象类中可以定义一些子类公共的方法或属性
//这样子类就可以直接继承下来使用了,而不需要每个
//子类重复定义
abstract class Person {private String name;public void setName(String name) {this.name = name;}public String getName() {return name;}//此方法各个子类都可以使用public void commonMethod1() {System.out.println("---------commonMethod1-------");}
}
class Employee extends Person {}
class Student extends Person {}

2.3 抽象的方法只需在抽象类中,提供声明,不需要实现,起到了一个强制的约束作用,要求子类必须实现

public class AbstractTest02 {public static void main(String[] args) {Person01 teacher = new Teacher();teacher.setName("Li");System.out.println(teacher.getName());teacher.commonMethod();teacher.abstractMethod();}
}
abstract class Person01{private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}// 此方法各个子类都可以使用public void commonMethod(){System.out.println("----commonMethod----");}//抽象方法,子类必须实现//如果有一个方法为抽象的,那么此类必须为抽象的public abstract void abstractMethod();
}class Teacher extends Person01 {@Overridepublic void abstractMethod() {System.out.println("对Person01抽象方法的实现!");}
}

运行结果:
在这里插入图片描述

2.4 如果这个类是抽象的,那么这个类被子类继承,抽象方法必须被覆盖。如果在子类中不覆盖该抽象方法,那么必须将此方法再次声明为抽象方法

public class AbstractTest03 {public static void main(String[] args) {// 此时Doctor类也是抽象的,不能再new
//        Person doctor = new Doctor();}
}
abstract class Person{private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}// 此方法各个子类都可以使用public void commonMethod(){System.out.println("----commonMethod----");}//抽象方法,子类必须实现//如果有一个方法为抽象的,那么此类必须为抽象的public abstract void abstractMethod();
}abstract class Doctor extends Person {//再次声明该方法为抽象的public abstract void abstractMethod();
}

2.5 抽象类不能被 final 修饰

如下代码;

final abstract class Person{private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}// 此方法各个子类都可以使用public void commonMethod(){System.out.println("----commonMethod----");}//抽象方法,子类必须实现//如果有一个方法为抽象的,那么此类必须为抽象的public abstract void abstractMethod();
}

编译报错:
在这里插入图片描述

2.6 抽象方法不能被 final 修饰

在这里插入图片描述

2.7 抽象类中可以没有抽象方法

abstract class Animal{//抽象类可以没有抽象方法,其依旧是抽象类// 普通方法,此方法各个子类都可以使用public void commonMethod(){System.out.println("----commonMethod----");}
}

2.8 抽象类虽无法实例化,但是可以有构造方法,供子类使用

public class AbstractTest04 {public static void main(String[] args) {Book paperBook = new PaperBook("解忧杂货店", 486);System.out.println(paperBook.getName());System.out.println(((PaperBook) paperBook).getPageNum());}
}//抽象书类
abstract class Book{private String name; //书名public String getName() {return name;}public void setName(String name) {this.name = name;}//抽象类可以定义构造方法public Book(String name) {this.name = name;}
}//纸质书类
class PaperBook extends Book{private int pageNum; //页数public int getPageNum() {return pageNum;}public void setPageNum(int pageNum) {this.pageNum = pageNum;}public PaperBook(String name, int pageNum) {super(name);this.pageNum = pageNum;}
}

3. 接口(行为)

接口我们可以看作是抽象类的一种特殊情况,在接口中只能定义抽象的方法和常量

  1. 在 java 中接口采用 interface 声明;
  2. 接口中的方法默认都是 public abstract 的,不能更改;
  3. 接口中的变量默认都是 public static final 类型的,不能更改,所以必须显式地初始化;
  4. 接口不能被实例化,接口中没有构造方法的概念,且子类实现的方法也必须是public修饰的
  5. 接口之间可以继承,但接口之间不能实现
  6. 接口中的方法只能通过类来实现,使用implements关键字;
  7. 如果一个类实现了接口,那么接口中所有的方法必须实现;
  8. 一个类可以实现多个接口;
  9. 接口编译后也是生成.class文件;
  10. 抽象类可以实现接口:abstract class 抽象类类名 implements 接口名{}
  11. 把接口就看成⼀种特殊的抽象类,那它也可以使用多态;
  12. 经过测试:接口与接口之间进行强制类型转换时,没有继承关系,也可以强转,但是在运行时可能会出现ClassCastException异常;
  13. 接口的父类也是Object

3.1 接口中的方法默认都是 public abstract 的,不能更改

如下代码:

public class InterfaceTest01 {public static void main(String[] args) {}
}//采用 interface 定义接口
//定义功能,没有实现
//实现委托给类实现
interface StudentManager {//正确,默认为 public abstract 等同 public abstract void addStudent(int id, String name);void addStudent(int id, String name);//正确,可以加入 public 修饰符,此种写法较多public void delStudent(int id);//正确,可以加入 abstract,这种写法比较少public abstract void modifyStudent(int id, String name);//编译错误,因为接口就是让其他人实现//采用 private 就和接口原本的定义产生矛盾了private String findStudentById(int id);
}

编译报错:
在这里插入图片描述

3.2 接口中的变量是 public static final 类型的,不能更改,所以必须显式地初始化

如下代码:

public class InterfaceTest02 {public static void main(String[] args) {//不能修改,因为是 final 的StudentManager02.YES = "YES";System.out.println(StudentManager02.NO);}
}
interface StudentManager02{//正确,默认加入 public static finalString YES = "yes";//正确, 开发中一般就按照下面的方式进行声明public static final String NO = "no";//错误,必须赋值,因为是 final 的int ON;//错误,不能采用 private 声明private static final int OFF = -1;
}

编译报错:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 接口不能被实例化,接口中没有构造方法的概念

如下代码;

public class InterfaceTest03 {public static void main(String[] args) {//接口是抽象类的一种特例,只能定义方法和变量,没有实现,所以不能实例化StudentManager03 studentManager03 = new StudentManager03();}
}
interface StudentManager03{void addStudent(int id,String name);
}

编译报错:
在这里插入图片描述

3.4 接口之间可以继承,但接口之间不能实现

如下代码:

public class InterfaceTest04 {public static void main(String[] args) {}
}interface inter1{public void method1();public void method2();
}
interface inter2{public void method3();
}//接口可以继承
interface inter3 extends inter1{public void method4();
}//接口不能实现接口
//接口只能被类实现
interface inter4 implements inter2{}

编译报错;
在这里插入图片描述

3.5 如果一个类实现了接口,那么接口中所有的方法必须实现

如下代码:

public class InterfaceTest05 {public static void main(String[] args) {//Iter1Impl 实现了 Inter1 接口//所以它是 Inter1 类型的产品//所以可以赋值Inter1 inter1 = new Inter1Impl();inter1.method1();//Iter1Impl123 实现了 Inter1 接口//所以它是 Inter1 类型的产品//所以可以赋值Inter1 inter123 = new Iter1Impl123();inter123.method2();//可以直接采用 Iter1Impl 来声明类型//这种方式存在问题//不利于互换,因为面向具体编程了Inter1Impl interImpl = new Inter1Impl();interImpl.method1();//不能直接赋值给 iter1Impl//因为 Iter1Impl123 不是 Iter1Impl 类型
//        iterImpl = new Iter1Impl123();}
}//定义接口
interface Inter1{public void method1();public void method2();public void method3();
}//接口中的方法必须全部实现
class Inter1Impl implements Inter1 {@Overridepublic void method1() {System.out.println("method1");}@Overridepublic void method2() {System.out.println("method1");}@Overridepublic void method3() {System.out.println("method1");}
}class Iter1Impl123 implements Inter1 {@Overridepublic void method1() {System.out.println("method1_123");}@Overridepublic void method2() {System.out.println("method2_123");}@Overridepublic void method3() {System.out.println("method3_123");}
}
abstract class IterImpl456 implements Inter1 {@Overridepublic void method1() {System.out.println("method1_123");}@Overridepublic void method2() {System.out.println("method2_123");}//再次声明为抽象方法abstract public void method3();
}

编译报错:
在这里插入图片描述
注释上述报错行后运行结果:
在这里插入图片描述

3.6 一类可以实现多个接口

public class InterfaceTest06 {public static void main(String[] args) {//可以采用 Inter1 定义Inter01 inter01 = new InterImpl01();inter01.method1();((InterImpl01) inter01).method2(); //调用非实现Inter01接口的方法必须进行强转//可以采用 Inter2 定义Inter02 inter02 = new InterImpl01();inter02.method2();//可以采用 Inter3 定义Inter03 inter03 = new InterImpl01();inter03.method3();}
}interface Inter01{public void method1();
}interface Inter02{public void method2();
}interface Inter03{public void method3();
}//粗粒度
/*
interface inter{public void method1();public void method2();public void method3();
}
*///实现多个接口,采用逗号隔开
//这样这个类就拥有了多种类型
//等同于现实中的多继承
//所以采用 java 中的接口可以实现多继承
//把接口粒度划分细了,可以使功能定义的含义更明确
//可以采用一个大的接口定义所有功能,替代多个小的接口,
//但这样定义功能不明确,粒度太粗了
class InterImpl01 implements Inter01,Inter02,Inter03{@Overridepublic void method1() {System.out.println("******method1******");}@Overridepublic void method2() {System.out.println("******method2******");}@Overridepublic void method3() {System.out.println("******method3******");}
}

运行结果:
在这里插入图片描述

3.7 接口是一种特殊的抽象类,可以使用多态

由上3.6即可以看出,也可看如下例子:

interface A{ 其中有方法m1 } interface B{ 其中有方法m2 }
情况1:若有类C:class C implementsA{}
若此时有:A a =new C(); B b = (B)a;//C与B没有关系,出现运行异常
情况2:若有类C:class C implements A,B{}
若此时有:A a =new C(); B b = (B)a;//为了调用m2(),进行接口转型,
可以运行 b.m2();//此时只能调用m2()方法,不能调用 m1()方法,要向下转型成C c = (C)a才可以。

对于以上不用太纠结,反正也没啥用,只要养成好习惯:向下转型前用if+instanceof判断即可。

情况1具体代码:

public class InterfaceTest07 {public static void main(String[] args) {A a = new C();a.m1();B b = (B)a; //C 和 B 没有关系,出现运行时异常}
}interface A{public void m1();}
interface B{public void m2();}class C implements A{@Overridepublic void m1() {System.out.println("=========m1==========");}
}

运行结果:
在这里插入图片描述

情况2具体代码:

public class InterfaceTest07 {public static void main(String[] args) {A a = new C();a.m1();B b = (B)a; //为了调用m2()进行接口转型b.m2();}
}interface A{public void m1();}
interface B{public void m2();}class C implements A,B{@Overridepublic void m1() {System.out.println("=========m1==========");}@Overridepublic void m2() {System.out.println("=========m2==========");}
}

运行结果:

在这里插入图片描述

3.8 接口与接口之间进行强制类型转换时,没有继承关系,也可以强转,但是在运行时可能会出现ClassCastException异常

另外,类在强制转换过程中,如果父类 引用转换成接口类型,那么父类和接口之间不需要存在实 现关系,也可以转换,java语法时允许的。(前提父类引用中实际保存的子类引用所指对象有实现该接口!否则运行阶段还是会有类型转换异常)

3.9 一个类可以同时继承抽象类和实现接口

语法:class 类名 extends 抽象类名 implements 接口名{}
只能extends在前,不能class 类名 implements 接口名 extends 抽象类名()
如下代码:

public class InterfaceTest08 {public static void main(String[] args) {E e = new F();e.m2();((F) e).m1(); //强转成子类型才可以调用m1D d = new F();d.m1();((F) d).m2();  //强转成子类型才可以调用m2}
}interface D{public void m1();
}abstract class E{abstract public void m2();
}
class F extends E implements D {@Overridepublic void m1() {System.out.println("----------m1----------");}@Overridepublic void m2() {System.out.println("----------m2----------");}
}

运行结果:
在这里插入图片描述

4. 接口的进一步应用

在 java 中接口其实᧿述了类需要做的事情,类要遵循接口的定义来做事,使用接口的本质好处可以归纳为:

  • 采用接口明确的声明了它所能提供的服务;
  • 解决了 Java 单继承的问题;
  • 实现了可接插性(重要),可以使用接口解耦合。

接口解耦合是解开的是调用者和实现者之间的耦合,调用者面向接口调用, 实现者面向接口编写实现。这样在开发时,项目组可以为围绕接口开发,根据接口将项目分成不同的模块,同步进行,提高开发效率。

示例:完成学生信息的增删改操作,系统要求适用于多个数据库,如:适用于 Oracle 和 MySQL。

  • 第一种方案,不使用接口,每个数据库实现一个类:

UML,统一建模语言:
在这里插入图片描述
代码:

//Oracle 的实现
public class StudentOracleImpl {public void add(int id, String name) {System.out.println("StudentOracleImpl.add()");}public void del(int id) {System.out.println("StudentOracleImpl.del()");}public void modify(int id, String name) {System.out.println("StudentOracleImpl.modify()");}
}
Mysql 的实现
public class StudentMysqlImpl {public void addStudent(int id, String name) {System.out.println("StudentMysqlImpl.addStudent()");}public void deleteStudent(int id) {System.out.println("StudentMysqlImpl.deleteStudent()");}public void udpateStudent(int id, String name) {System.out.println("StudentMysqlImpl.udpateStudent()");}
}

调用以上两个类完成向 Oracle 数据库和 Mysql 数据存储数据:

public class StudentManager {public static void main(String[] args) {//对 Oracle 数据库的支持StudentOracleImpl studentOracleImpl = new StudentOracleImpl();studentOracleImpl.add(1, "张三");studentOracleImpl.del(1);studentOracleImpl.modify(1, "张三");//需要支持 Mysql 数据库StudentMysqlImpl studentMysqlImpl = new StudentMysqlImpl();studentMysqlImpl.addStudent(1, "张三");studentMysqlImpl.deleteStudent(1);studentMysqlImpl.udpateStudent(1, "张三");}
}

以上代码不能灵活的适应需求,当需求发生改变需要改动的代码量太大,这样可能会导致代码的冗余,另外可能会导致项目的失败,为什么会导致这个问题,在开发中没有考虑到程序的扩展性,就是一味的实现,这样做程序是不行的,所以大的项目比较追求程序扩展性,有了扩展性才可以更好的适应需求

  • 第二种方案,使用接口
    UML,统一建模语言:
    在这里插入图片描述

代码:

public class InterfaceTest09 {public static void main(String[] args) {/*IStudent istudent = new Student4OracleImpl();IStudent istudent = new Student4MysqlImpl();istudent.add(1, "张三");istudent.del(1);istudent.modify(1, "张三");*///进一步简化,创建doCrud()方法doCrud(new Student4OracleImpl());doCrud(new Student4MysqlImpl());}//此种写法没有依赖具体的实现//而只依赖的抽象,就像你的手机电池一样:你的手机只依赖电池(电池是一个抽象的事物),//而不依赖某个厂家的电池(某个厂家的电池就是具体的事物了)//因为你依赖了抽象的事物,每个抽象的事物都有不同的实现//这样你就可以利用多态的机制完成动态绑定,进行互换,是程序具有较高的灵活//我们尽量遵循面向接口(抽象)编程,而不要面向实现编程public static void doCrud(IStudent istudent) {istudent.add(1, "张三");istudent.del(1);istudent.modify(1, "张三");}//以下写法不具有扩展性//因为它依赖了具体的实现//建议不要采用此种方法,此种方案是面向实现编程,就依赖于具体的东西了/*public static void doCrud(Student4OracleImpl istudent) {istudent.add(1, "张三");istudent.del(1);istudent.modify(1, "张三");}*/
}interface IStudent{public void add(int id, String name);public void del(int id);public void modify(int id, String name);
}class Student4OracleImpl implements IStudent {public void add(int id, String name) {System.out.println("Student4OracleImpl.add()");}public void del(int id) {System.out.println("Student4OracleImpl.del()");}public void modify(int id, String name) {System.out.println("Student4OracleImpl.modify()");}
}class Student4MysqlImpl implements IStudent {public void add(int id, String name) {System.out.println("Student4MysqlImpl.add()");}public void del(int id) {System.out.println("Student4MysqlImpl.del()");}public void modify(int id, String name) {System.out.println("Student4MysqlImpl.modify()");}
}

运行结果:
在这里插入图片描述

5. 抽象类与接口的区别

  1. 接口描述述了方法的特征,不给出实现,一方面解决 java 的单继承问题,实现了强大的可接插性;
  2. 抽象类提供了部分实现,抽象类是不能实例化的,抽象类的存在主要是可以把公共的代码移植到抽象类中;
  3. 面向接口编程,而不要面向具体编程(面向抽象编程,而不要面向具体编程);
  4. 优先选择接口(因为继承抽象类后,此类将无法再继承,所以会丧失此类的灵活性;而可以实现多个接口,达到类似“多继承”的效果)。

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

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

相关文章

云原生之容器编排实践-kubectl get pod -A没有coredns

背景 前面搭建的3节点 Kubernetes 集群,其实少了一个组件: CoreDNS ,这也是我后面拿 ruoyi-cloud 项目练手时,部署了 MySQL 和 Nacos 服务后才意识到的:发现Nacos无法通过服务名连接MySQL,这里 Nacos 选择…

MySQL-主从复制

目录 1. 主从复制概述 1.1 如何提升数据库并发能力 1.2 主从复制的作用 2. 主从复制的原理 2.1 原理剖析 三个线程 复制三步骤 复制的问题 2.2 复制的基本原则 3. 一主一从架构搭建 3.1 准备工作 3.2 主机配置文件 3.3 从机配置文件 3.4 主机:建立账户…

Vue packages version mismatch 报错解决

问题 npm run dev 运行项目的过程中,报错 Vue packages version mismatch 解决方法 根据报错不难看出是 vue 与 vue-template-compiler 版本产生了冲突,vue 与 vue-template-compiler 的版本是需要匹配的。所以解决的办法就是先修改其中一个的版本将 v…

Programming Abstractions in C阅读笔记:p293-p302

《Programming Abstractions in C》学习第73天,p293-p302总结,总计10页。 一、技术总结 1.时间复杂度 (1)quadratic time(二次时间) p293, Algorithms like selection sort that exhibit O(N^2) performance are said to run in quadratic time。 2…

如何利用EXCEL批量插入图片

目录 1.excel打开目标表格; 2.点开视图-宏-录制宏,可以改宏的名字或者选择默认; 3.然后点开视图-宏-查看宏 4.点编辑进去 5.修改代码: (1)打开之后会显示有一堆代码 (2)将这个…

Django入门指南:从环境搭建到模型管理系统的完整教程

环境安装: ​ 由于我的C的Anaconda 是安装在C盘的,但是没内存了,所有我将环境转在e盘,下面的命令是创建环境到指定目录中. conda create --prefixE:\envs\dj42 python3.9进入环境中: conda activate E:\envs\dj42…

一周学会Django5 Python Web开发-Http请求HttpRequest请求类

锋哥原创的Python Web开发 Django5视频教程: 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计25条视频,包括:2024版 Django5 Python we…

lxml库和Xpath提取网页数据的基础与实战:完整指南与实战【第92篇—提取网页】

使用lxml库和Xpath提取网页数据的基础与实战 在网络爬虫和数据抓取中,从网页中提取所需信息是一项常见的任务。lxml库和Xpath是Python中用于解析和提取HTML/XML数据的强大工具。本文将介绍lxml库的基础知识,以及如何使用Xpath表达式来准确地提取网页数据…

[HTML]Web前端开发技术30(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 网页标题:手机批发业务-商品备选区<

Swift Combine 使用 handleEvents 操作符调试管道 从入门到精通二十五

Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三Swift Combine 发布者publisher的生命周期 从入门到精通四Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五Swift Com…

【GO语言卵细胞级别教程】07.捕获异常和自定义错误

【GO语言卵细胞级别教程】07.捕获异常和自定义错误 &#x1f970;博主&#xff1a;GokuCode &#x1f970;微信公众号&#xff1a;【给点知识】分享小知识&#xff0c;快速成长,欢迎关注呀&#xff01;&#xff08;底部点击二维码&#xff09; &#x1f970;本项目演示代码仓库…

Windows Server 2012 IIS中发布ASP.NET CORE项目

服务器安装IIS&#xff1a; 微软官网下载SDK&#xff1a; 下载Runtime官网&#xff1a;https://dotnet.microsoft.com/download/dotnet-core 安装成功重启IIS&#xff1a; VS发布项目&#xff1a;

分享:如何做好Temu跨境电商项目的几点方法

Temu跨境电商项目作为中国电商巨头拼多多旗下的新兴跨境电商平台&#xff0c;近年来发展迅速&#xff0c;吸引了大量国内卖家参与。然而&#xff0c;由于跨境电商的复杂性和竞争激烈&#xff0c;如何在Temu平台上成功运营&#xff0c;实现良好的销售业绩&#xff0c;成为许多卖…

Chiplet技术与汽车芯片(二)

目录 1.回顾 2.Chiplet的优势 2.1 提升芯片良率、降本增效 2.2 设计灵活&#xff0c;降低设计成本 2.3 标准实行&#xff0c;构建生态 3.Chiplet如何上车 1.回顾 上一篇&#xff0c;我们将来芯粒到底是什么东西&#xff0c;本篇我们来看芯粒技术的优势&#xff0c;以及它…

软考39-上午题-【数据库】-关系代数运算1-传统的集合运算

一、笛卡尔积 二、关系代数 关系代数是施加于关系之上的集合代数运算。 关系代数包含&#xff1a; 传统的集合运算专门的关系运算 2-1、传统的集合运算 1、关系的并 示例&#xff1a; 2、关系的差 示例&#xff1a; 3、关系的交 示例&#xff1a; 关系的并、差、交&#xf…

微信小程序开发(实战案例):本地生活 - 列表页面开发(动态渲染处理)、节流防抖(节流阀应用)

文章目录 本地生活 - 列表页面开发一、将九宫格分类换成navigator组件二、动态设置商品列表页的 title三、动态渲染商品列表页面四、上拉触底加载数据五、添加Loading加载效果六、数据加载节流防抖处理 本地生活 - 列表页面开发 导入我们上次写的 本地生活 - 首页开发的项目 运…

二分算法(c++版)

二分的本质是什么&#xff1f; 很多人会认为单调性是二分的本质&#xff0c;但其实其本质并非单调性&#xff0c;只是说&#xff0c;有单调性的可以进行二分&#xff0c;但是有些题目没有单调性我们也可以进行二分。其本质其实是一个边界问题&#xff0c;给定一个条件&#xf…

【机器学习基础】一元线性回归(适合初学者的保姆级文章)

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习 欢迎订阅&#xff01;后面的内容会越来越有意思~ &#x1f4a1;往期推荐&#xff1a; 【机器学习基础】机器学习入门&#xff08;1&#xff09; 【机器学习基…

【深度学习:标记数据】为医生标记数据缓解疼痛

【深度学习&#xff1a;标记数据】为医生标记数据缓解疼痛 问题实验结果结论 我开始在物理学方面进行学术研究&#xff0c;但在第一年就退学了&#xff08;抱歉&#xff0c;休学了&#xff09;我的博士学位&#xff0c;并在定量金融领域做了很长一段时间。因此&#xff0c;在我…

宝塔面板安装了mysql5.7和phpMyadmin,但是访问phpMyadmin时提示502 Bad Gateway

操作流程截图如下&#xff1a; 原因是没有选择php版本 选择php版本 下一页找到phpMyAdmin&#xff0c;选择设置 目前只有纯净态&#xff0c;说明没有php环境&#xff0c;前去安装php环境 点击安装&#xff0c;选择版本&#xff0c;这里选择的是7.4版本&#xff0c;编译安…