第四章:面向对象编程

news2025/7/27 6:37:50

第四章:面向对象编程

4.1:面向过程与面向对象

  1. 面向过程(POP)与面向对象(OOP)

    • 二者都是一种思想,面向对象是相对于面向过程而言的。
    • 面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。
    • 面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
  2. 面向对象的三大特征

    封装Encapsulation、继承Inheritance、多态Polymorphism

  3. 面向对象的思想概述

    • 程序员从面向过程的执行者转化成了面向对象的指挥者
    • 面向对象分析方法分析问题的思路和步骤:
      1. 根据问题需要,选择问题所针对的现实世界中的实体
      2. 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类
      3. 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
      4. 类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。

4.2:Java的基本元素:类和对象

  1. Class和对象Object是面向对象的核心概念

    • 类:是对一类事物的描述,是抽象的、概念上的定义。
    • 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
    • 面向对象程序的重点是类的设计
    • 设计类,就是设计类的成员
  2. Java类及类的成员

    • 属性:对应类中的成员变量。Field = 属性 = 成员变量
    • 行为:对应类中的成员方法。Methon = (成员)方法 = 函数
  3. 类的语法格式

    修饰符 class 类名{
    	属性声明;
    	方法声明;
    }
    
    class Person{
    	// 属性
    	String name;
    	int age = 1;
    	boolean isMale;
    	
    	// 方法
    	public void eat(){
    		System.out.println("人可以吃饭");
    	}
    	public void sleep() {
    		System.out.println("人可以睡觉");
    	}
    	public void talk(String language) {
    		System.out.println("人可以说话,使用的是:" + language);
    	}
    }
    

4.3:对象的创建和使用

  1. 创建对象

    类名 对象名 = new 类名();
    
    Person p1 = new Person();
    
  2. 调用对象的结构:属性、方法

    • 属性:对象名.属性

      p1.name = "Tom";
      p1.isMale = true;
      
    • 方法:对象名.方法

      p1.eat();
      p1.sleep();
      p1.talk("Chinese");
      

    注意:如果创建了一个类的多个对象,对于类中定义的属性,每个对象都拥有各自的一套副本,且互不干扰。

  3. 内存解析
    在这里插入图片描述

    • Heap:此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
    • 栈(Stack):是指虚拟机栈。虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型、对象引用。方法执行完,自动释放。
    • 方法区(Method Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
      在这里插入图片描述
  4. 匿名对象的使用

    • 理解:我们创建的对象,没有显式的赋给一个变量名。即匿名对象。
    • 特征:匿名对象只能调用一次。
    • 使用:
      1. 如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。
      2. 我们经常将匿名对象作为实参传递给一个方法调用。

4.4:类的成员之一:属性

  1. 语法格式

    修饰符 数据类型 属性名 = 初始化值;
    
  2. 成员变量与局部变量

    • 在方法体外,类体内声明的变量称为成员变量。
    • 在方法体内部声明的变量称为局部变量。
  3. 成员变量(属性)和布局变量的区别

    成员变量局部变量
    声明的位置直接声明在类中方法形参或内部、代码块内、构造器内等
    修饰符privatepublicstaticfinal不能用权限修饰符修饰,可以用final修饰
    初始值有默认初始化值没有默认初始化值,必须显示赋值,方可使用
    内存加载位置堆空间或静态域内栈空间
  4. 对象属性的默认初始化赋值

    当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。

    数组元素类型元素默认初始化值
    byte0
    short0
    int0
    long0L
    float0.0F
    double0.0
    char0或\u0000
    booleanfalse
    引用类型null

4.5:类的成员之二:方法

  1. 什么是方法(函数)

    • 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
    • 将功能封装为方法的目的是,可以实现代码重用,简化代码。
    • Java里的方法不能独立存在,所有的方法必须定义在类里。
  2. 声明格式

    修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ....) {
    	方法体程序代码;
    	return 返回值;
    }
    
    public void eat() {
        System.out.println("客户吃饭");
    }
    
    public void sleep(int hour) {
        System.out.println("休息了" + hour + "个小时");
    }
    
    public String getName() {
        return name;
    }
    
    public String getNation(String nation) {
        String info = "我的国籍是:" + nation;
        return info;
    }
    

    说明:

    • 返回值类型
      1. 如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用return关键字来返回指定类型的变量或常量:return 数据
      2. 如果方法没有返回值,则方法声明时,使用void来表示。通常,没有返回值的方法中,就不需要使用return。但是,如果使用的话,只能return;表示结束此方法的意思。
    • return关键字的使用
      1. 使用范围:使用在方法体中。
      2. 作用:
        • 结束方法。
        • 针对于有返回值类型的方法,使用return 数据方法返回所要的数据。
      3. 注意点:return关键字后面不可以声明执行语句。
    • 方法的使用中,可以调用当前类的属性或方法,特殊的,方法A中又调用了方法A【递归方法】。方法中,不可以定义方法。
  3. 方法的分类

    方法的分类:按照是否有形参及返回值

    无返回值有返回值
    无形参void 方法名() {}返回值的类型 方法名() {}
    有形参void 方法名(形参列表) {}返回值的类型 方法名(形参列表) {}
  4. 方法的重载

    • 定义:在同一个类中,允许存在一个以上的同名方法,只要他们的参数个数或者参数类型不同即可。

      两同一不同:同一个类、相同方法名,参数列表不同【参数个数不同,参数类型不同】。

    • 判断是否是重载

      跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!

  5. 可变个数的参数

    JavaSE 5.0中提供了Varargs(variable number of arguments)机制,允许直接定义能和多个实参相匹配的形参。从而,可以用一种更简单的方法,来传递个数可变的实参。

    • 可变个数形参的格式:数据类型 ... 变量名
    • 当调用可变个数形参的方法时,传入的参数个数可以是:0个、1个、2个…
    • 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载。
    • 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
    • 可变个数形参在方法的形参中,必须声明在末尾。
    • 可变个数形参在方法的形参中,最多只能声明一个可变形参。
  6. 方法参数的值传递机制

    方法,必须由其所在类或对象调用才有意义。若方法含有函数:

    • 形参:方法声明时的参数。
    • 实参:方法调用时实际传给形参的参数值。

    java的实参值如何传入方法:

    • Java里方法的参数传递方式只有一种:值传递。即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响
      1. 形参时基本数据类型:将实参基本数据类型变量的数据值传递给形参。
      2. 形参时引用数据类型:将实参引用数据类型变量的地址值传递给形参。
  7. 递归方法

    • 递归方法:一个方法体内调用它自身。
    • 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。递归一定要向已知方法递归,否则这种递归就变成了无穷递归,类似于死循环。

4.6:封装与隐藏

  1. 高内聚、低耦合

    • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
    • 低耦合:仅对外暴露少量的方法用于使用。

    ​ 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想

  2. 信息的封装和隐藏

    Java中通过将数据声明为私有的private,在提供公共的public方法:getXxx()setXxx()实现对该属性的操作,以实现下述目的:

    • 隐藏一个类中不需要对外提供的实现细节。
    • 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作。
    • 便于修改,增强代码的可维护性。
    public class AnimalTest {
    
    	public static void main(String[] args) {
    		Animal a = new Animal();
    	
    		a.name = "大黄";
    		a.show();
    		
    		a.setLegs(6);
    		a.setLegs(-6);
    		
    		a.show();
    		System.out.println(a.name);
    	}
    	
    }
    
    class Animal{
    	
    	String name;
    	private int age;
    	private int legs;
    	
    	public void setLegs(int l) {
    		if(l >= 0 && l % 2 == 0) {
    			legs = l;
    		} else {
    			legs = 0;
    		}
    	}
        public int getLegs() { return legs; }
        
        public int getAge() { return age; }
    	public void setAge(int a) { age = a; }
    	
    	public void eat() {
    		System.out.println("动物进食");
    	}
    	public void show() {
    		System.out.println("name = " + name + ", age = " + age + ", legs = " + legs);
    	}
    		
    }
    
  3. 四种访问权限修饰符

    Java权限修饰符publicprotected、(缺省)、private置于类的成员定义前,用于来限定对象对该类成员的访问权限。

    修饰符类内部同一个包不同包的子类同一个过程
    privateYes
    (缺省)YesYes
    protectedYesYesYes
    publicYesYesYesYes

    总结:

    • 修饰类的话,只能使用:缺省、public
    • Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。

4.7:类的成员之三:构造器

  1. 构造器的作用

    • 创建对象。
    • 初始化对象的信息。
  2. 格式

    权限修饰符 类名(形参列表) {
    	
    }
    
  3. 说明

    • 如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器。
    • 一个类中定义的多个构造器,彼此构成重载。
    • 一旦我们显示的定义类的构造器之后,系统就不再提供默认的空参构造器。
    • 一个类中,至少会有一个构造器。
  4. 代码示例

    public class PersonTest {
    
    	public static void main(String[] args) {
    		Person p1 = new Person();
    		
    		p1.eat();
    		Person p2 = new Person("Tom");
    		System.out.println(p2.name);
    	}
    	
    }
    
    class Person{
    	String name;
    	int age;
    	
        // 构造器
    	public Person() {
    		System.out.println("Person()....");
    	}
    	public Person(String n) {
    		name = n;
    	}
    	public Person(String n, int a) {
    		name = n;
    		age = a;
    	}
    
    }
    
  5. 属性赋值过程

    • 赋值的位置
      1. 默认初始化
      2. 显式初始化
      3. 构造器中初始化
      4. 通过对象.属性对象.方法的方式赋值。
    • 赋值的先后顺序:1 - 2 - 3 - 4
  6. JavaBean

    • JavaBean是一种Java语言写成的可重用组件。
    • 所谓JavaBean,是指符合如下标准的Java
      1. 类是公共的。
      2. 有一个无参的公共的构造器。
      3. 有属性,且有对应的getset方法。
    • 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBeanapplet程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。

4.8:this的使用

  1. this关键字的使用

    this可以用来修饰、调用:属性、方法、构造器。

  2. this修饰属性和方法

    this理解为:当前对象或当前正在创建的对象。

    • 在类的方法【或构造器】中,我们可以使用this.属性this.方法的方式,调用当前对象【或当前正在创建的】对象属性或方法。但是,通常情况下,我们都选择省略this.。特殊情况下,如果方法【构造器】的形参和类的属性同名时,我们必须显式的使用this.变量的方式,表名此变量是属性,而非形参。
  3. this调用构造器

    • 我们在类的构造器中,可以显式的使用this(形参列表)方式,调用本类中指定的其他构造器。
    • 构造器中不能通过this(形参列表)方式调用自己。
    • 如果一个类中有n个构造器,则最多有n - 1构造器中使用了this(形参列表)
    • 规定:this(形参列表)必须声明在当前构造器的首行。
    • 构造器内部,最多只能声明一个this(形参列表),用来调用其他的构造器。

4.9:关键字:package、import

  1. package关键字的使用

    • 为了更好的实现项目中类的管理,提供包的概念。
    • 使用package声明类或接口所属的包,声明在源文件的首行。
    • 包,属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意”
    • .一次,就代表一层文件目录。

    补充:同一个包下,不能命名同名的接口、类。不同的包下,可以命名同名的接口、类。

  2. MVC设计模式

    MVC是常用的设计模式之一,将整个程序分为三个层次:视图模型层、控制器层、与数据模型层。这种将程序输入输出、数据处理,以及数据的展示分离开来的设计模式使程序结构变的灵活而且清晰,同时也描述了程序各个对象间的通信方式,降低了程序的耦合性。

    • 模型层model:主要处理数据
      1. 数据对象封装:model.bean/domain
      2. 数据库操作类:model.dao
      3. 数据库:model.db
    • 控制层controller:处理业务逻辑
      1. 应用界面相关:controller.activity
      2. 存放fragmentcontroller.fragment
      3. 显示列表的适配器:controller.adapter
      4. 服务相关的:controller.service
      5. 抽取的基类:controller.base
    • 视图层view:显示数据
      1. 相关工具类:view.utils
      2. 自定义viewview.ui
  3. import关键字的使用

    • 在源文件中显式的使用import结构导入指定包下的类、接口。
    • 声明在包的声明和类的声明之间。
    • 如果需要导入多个结构,则并列写出即可。
    • 可以使用xxx.*的方式,表示可以导入xxx包下的所有结构。
    • 如果使用的类或接口是java.lang包下定义的,则可以省略import结构。
    • 如果使用的类或接口是本包下定义的,则可以省略import结构。
    • 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示。
    • 使用xxx.*方式表名可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入。
    • import static导入指定类或接口中的静态结构:属性或方法。

4.10:继承性

  1. 继承性的好处

    • 减少了代码的冗余,提高了代码的复用性。
    • 便于功能的扩展。
    • 为之后多态性的使用,提供了前提。
  2. 继承性的格式

    class A extends B {}
    // A:子类、派生类、subclass
    // B:父类、超类、基类、superclass
    
    • 体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。

      ​ 特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。只是因为封装性的影响,使得子类不能直接调用父类的结构而已。

    • 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。

  3. Java中关于继承性的规定

    • 一个类可以被多个子类继承。
    • Java中类的单继承性:一个类只能有一个父类。
    • 子父类是相对的概念。
    • 子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类。
    • 子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法。
    • 如果我们没有显示的声明一个类的父类的话,则此类继承于java.lang.Object类。
    • 所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类。
    • 意味着,所有的java类具有java.lang.Object类声明的功能。

4.11:方法的重写

  1. 重写

    子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作。

  2. 应用

    重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法。

  3. 重写的规定

    权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型 {
    	// 方法体
    }
    // 约定俗称:子类中的叫重写的方法,父类中叫被重写的方法
    
    • 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同。

    • 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符。

      特殊情况:子类不能重写父类中声明为private权限的方法。

    • 返回值类型:

      1. 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
      2. 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类。
      3. 父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型也是相同的基本数据类型
    • 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型。

    注意:子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)。

4.12:super关键字

  1. super理解为

    父类的

  2. super可以用来调用

    属性、方法、构造器

  3. super调用属性和方法

    • 我们可以在子类的方法或构造器中。通过使用super.属性super.方法的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略super
    • 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显示的使用super.属性的方式,表明调用的是父类中声明的属性。
    • 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用super.方法的方式,表明调用的是父类中被重写的方法。
  4. super调用构造器

    • 我们可以在子类的构造器中显式的使用super(形参列表)的方式,调用父类中声明的指定的构造器。
    • super(形参列表)的使用,必须声明在子类构造器的首行。
    • 我们在类的构造器中,针对于this(形参列表)super(形参列表)只能二选一,不能同时出现。
    • 在构造器的首行,没有显式的声明this(形参列表)super(形参列表),则默认调用的是父类中空参的构造器:super()
    • 在类的多个构造器中,至少有一个类的构造器中使用了super(形参列表),调用父类中的构造器。
  5. thissuper的区别

    区别点thissuper
    访问属性访问本类中的属性,如果本类没有此属性则从父类中继续查找直接访问父类中的属性
    调用方法访问本类中的方法,如果本类没有此方法则从父类中继续查找直接访问父类中的方法
    调用构造器调用本类构造器,必须放在构造器的首行调用父类的构造器,必须放在子类构造器的首行

4.13:多态性

  1. 理解多态性

    可以理解为一个事物的多种形态。

  2. 何为多态性

    对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)

    父类 变量名 = new 子类();
    
  3. 多态的使用

    • 虚拟方法调用

      ​ 有了对象的多态性以后,我们在编译器,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。

      总结:编译,看左边;运行,看右边。

    • 多态性的使用前提

      1. 类的继承关系
      2. 方法的重写
    • 对于对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)

  4. instanceof关键字

    // 对象a是类A的实例,返回true,不是,返回false
    boolean flag = a instanceof A;
    

    使用情境:

    ​ 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就向下转型。如果返回false,不进行向下转型。
    在这里插入图片描述

    子类 变量名 = (子类) 父类对象;
    

4.14:Object类的使用

Object类是所有Java类的根父类,如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类。Object类中的功能(属性、方法)就具有通用性。

public class ObjectTest {
	public static void main(String[] args) {
		Order order = new Order();
		System.out.println(order.getClass().getSuperclass());
	}	
}
class Order {}
  1. Object类中的主要结构

    方法名称类型描述
    public Object()构造构造器
    public boolean equals(Object obj)普通对象比较
    public int hashCode()普通取得Hash
    public String toString()普通对象打印时调用
  2. equals方法的使用

    • 是一个方法,而非运算符,只能使用于引用数据类型。

    • Object类中equals()的定义:和==的作用是相同的,比较两个对象的地址值是否相同。

      public boolean equals(Object obj) {
          return (this == obj);
      }
      
    • 通常情况下,我们自定义类的如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写。

  3. toString的使用

    • 当我们输出一个对象的引用时,实际上就是调用当前对象的toString()

    • Object类中toString()的定义

      public String toString() {
      	return getClass().getName() + "@" + Integer.toHexString(hashCode());
      }
      
    • 自定义类也可以重写toString()方法,当调用此方法时,返回对象的"实体内容"。

4.15:包装类的使用

java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征。
在这里插入图片描述

  1. 基本数据类型、包装类、String三者之间的相互转换

    public class WrapperTest {
    	
    	//String类型 --->基本数据类型、包装类:调用包装类的parseXxx(String s)
    	@Test
    	public void test5(){
    		String str1 = "123";
    		int num2 = Integer.parseInt(str1);
    		System.out.println(num2 + 1);
    	}
    	
    	//基本数据类型、包装类--->String类型:调用String重载的valueOf(Xxx xxx)
    	@Test
    	public void test4(){	
    		int num1 = 10;
    		//方式1:调用String的valueOf(Xxx xxx)
    		float f1 = 12.3f;
    		String str2 = String.valueOf(f1);
    		System.out.println(str2);
    	}
    	
    	// JDK 5.0 新特性:自动装箱 与自动拆箱
    	@Test
    	public void test3(){
    		//自动装箱:基本数据类型 --->包装类
    		int num2 = 10;
    		Integer in1 = num2;//自动装箱
    		//自动拆箱:包装类--->基本数据类型
    		System.out.println(in1.toString());
    		int num3 = in1;//自动拆箱
    	}
    	
    	//包装类--->基本数据类型:调用包装类Xxx的xxxValue()
    	@Test
    	public void test2(){
    		Integer in1 = new Integer(12);
    		int i1 = in1.intValue();
    		System.out.println(i1 + 1);
    	}
    	
    	//基本数据类型 --->包装类:调用包装类的构造器
    	@Test
    	public void test1(){	
    		int num1 = 10;
    		Integer in1 = new Integer(num1);
    		System.out.println(in1.toString());
    	}
    	
    }
    

4.16:static关键字

static可以用来修饰:属性、方法、代码块、内部类。

  1. 使用static修饰属性:静态属性

    • 我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
    • 静态变量随着类的加载而加载。可以通过类.静态变量的方式进行调用。
    • 静态变量的加载要早于对象的创建。
    • 由于类只会加载一次,则静态变量在内存中只会存在一份,存在方法区的静态域中。
  2. 使用static修饰方法:静态方法

    • 随着类的加载而加载,可以通过类.静态方法的方式进行调用。
    • 静态方法中,只能调用静态的方法或属性。
    • 非静态方法中,可以调用非静态的方法或属性,也可以调用静态的方法或属性。
  3. static注意点

    • 在静态的方法内,不能使用this关键字、super关键字。
    • 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。
  4. 单例设计模式

    • 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。

    • 饿汉式和懒汉式

      1. 饿汉式

        public class SingletonTest1 {
        	public static void main(String[] args) {
        		Bank bank1 = Bank.getInstance();
        		Bank bank2 = Bank.getInstance();
        		System.out.println(bank1 == bank2);
        	}
        }
        
        class Bank {
            // 私有化类的构造器
        	private Bank() {}
            // 内部创建类的对象
        	private static Bank instance = new Bank();
            // 提供公共的静态的方法,返回类的对象。
        	public static Bank getInstance() {
        		return instance;
        	}
        }
        
      2. 懒汉式

        public class SingletonTest2 {
        	public static void main(String[] args) {
        		Order order1 = Order.getInstance();
        		Order order2 = Order.getInstance();
        		System.out.println(order1 == order2);
        	}
        }
        
        class Order {
        	// 私有化类的构造器
        	private Order() {}
            // 声明当前类对象,没有初始化
        	private static Order instance = null;
            // 声明public、static的返回当前类对象的方法
        	public static Order getInstance() {
        		if(instance == null) {
        			instance = new Order();
        		}
        		return instance;
        	}
        	
        }
        
    • 饿汉式和懒汉式的区别

      1. 饿汉式

        坏处:对象加载时间过长。

        好处:饿汉式是线程安全的。

      2. 懒汉式

        好处:延迟对象的创建。

    • 单例模式的应用场景

      1. 网站的计数器。
      2. 应用程序的日志应用。
      3. 数据库连接池。
      4. 项目中,读取配置文件的类。
      5. Application也是单例的典型应用。
      6. WindowsTask Manager(任务管理器)就是很典型的单例模式。
      7. WindowsRecycle Bin(回收站)也是典型的单例应用。

4.17:代码块

​ 代码块的作用是用来初始化类、对象。代码块如果有修饰的话,只能使用static

  1. 静态代码块

    • 格式

      static{
          语句;
      }
      
    • 随着类的加载而执行,而且只执行一次。

    • 作用:初始化类的信息。

    • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行。

    • 静态代码块的执行要优先于非静态代码块的执行。

    • 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构。

  2. 非静态代码块

    • 格式

      {
      	语句;
      }
      
    • 随着对象的创建而执行。

    • 每创建一个对象,就执行一次非静态代码块。

    • 作用:可以在创建对象时,对对象的属性等进行初始化。

    • 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行。

    • 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法。

  3. 对属性可以赋值的位置

    • 默认初始化。
    • 显示初始化 / 在代码块中赋值。
    • 构造器中初始化。
    • 有了对象以后,可以通过对象.属性对象.方法的方式,进行赋值。

4.18:final关键字

final可以用来修饰的结构:类、方法、变量。

  1. final用来修饰一个类

    此类不能被其他类所继承。

  2. final用来修饰方法

    表明此方法不可以被重写。

  3. final用来修饰变量

    此时的变量就称为是一个常量。

    • final修饰属性

      可以考虑赋值的位置有:显示初始化、代码块中初始化、构造器中初始化。

    • final修饰局部变量

      尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

4.19:抽象类与抽象方法

​ 随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类

​ 其中,要把一个类变成抽象类的话要使用关键字abstractabstract可以用来修饰的结构有方法

  1. abstract修饰类

    • 格式

      权限修饰符 abstract class 类名 {}
      
    • 此类不能实例化。

    • 抽象类中一定有构造器,便于子类实例化时调用。【子类对象实例化的全过程】

    • 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作。

  2. abstract修饰方法

    • 格式

      权限修饰符 abstract 返回值类型 方法名(形参列表);
      
    • 抽象方法只有方法的声明,没有方法体。

    • 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。

    • 若子类重写了父类中的所有的抽象方法后,此子类方可实例化。若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰。

  3. abstract注意点

    • abstract不能用来修饰:属性、构造器等结构。
    • abstract不能用来修饰私有方法、静态方法、final的方法、final的类。
  4. 抽象类的匿名子类

    public class PersonTest{  
        public static void main(String[] args) {
            new Person() {
                public void eat(){
                    System.out.println("人要吃有营养的食物");
                }
    		   public void walk(){
                   System.out.println("人走路");
               }
            };
        }    
    }
    
    abstract class Person {
    	
    	String name;
    	int age;
    	
    	public Person() {}
    	public Person(String name, int age) {
    		this.name = name;
    		this.age = age;
        }
        
    	public abstract void eat();
    	public abstract void walk();	
    }
    
  5. 模板方法设计模式

    ​ 在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。

    public class BankTemplateMethodTest {
    	public static void main(String[] args) {
    		BankTemplateMethod btm = new DrawMoney();
    		btm.process();
    		
    		BankTemplateMethod btm2 = new ManageMoney();
    		btm2.process();
    	}	
    }
    
    abstract class BankTemplateMethod {
    	
    	public void takeNumber() {
    		System.out.println("取号排队");
    	}
    	public abstract void transact();
    	public void evaluate() {
    		System.out.println("反馈评分");
    	}
    	
    	public final void process() {
    		this.takeNumber();
    		this.transact();
    		this.evaluate();
    	}
    	
    }
    
    class DrawMoney extends BankTemplateMethod {
    	public void transact() {
    		System.out.println("我要取款!!!");
    	}	
    }
    
    class ManageMoney extends BankTemplateMethod {	
    	public void transact() {
    		System.out.println("我要理财!我这里有很多钱");
    	}	
    }
    

4.20:接口

​ 接口就是规范,定义的是一组规则,体现了现实世界中"如果你是/要…则必须能…"的思想。继承是一个"是不是",而接口实现则是"能不能"的关系。

接口的本质是契约,标准,规范。其中,接口使用interface来定义。

  1. JDK7及以前定义接口

    只能定义全局常量和抽象方法。

    • 全局常量

      interface Flyable {
          // 全局常量
      	public static final int MAX_SPEED = 7900;
          // 省略格式的全局常量
      	int MIN_SPEED = 1;
      }
      
    • 抽象方法

      interface Flyable {
      	// 抽象方法
      	public abstract void fly();
          // 省略格式的抽象方法
      	void stop();
      }
      
    • 接口中不能定义构造器的!意味着接口不可以实例化。

    • Java开发中,接口通过让类去实现【implements】的方式来使用。如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化;如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍认为一个抽象类。

    • Java类可以实现多个接口。

      权限修饰符 class AA extends BB implements CC, DD, EE {}
      
    • 接口与接口之间可以继承,而且可以多继承。

    • 接口的具体使用,体现多态性。

  2. JDK8定义接口

    除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法。

    • 静态方法

      public interface CompareA {
      	//静态方法
      	public static void method1(){
      		System.out.println("CompareA:北京");
      	}
      }
      
    • 默认方法

      public interface CompareA {
      	//默认方法
      	public default void method2(){
      		System.out.println("CompareA:上海");
      	}
          // 省略的默认方法
      	default void method3(){
      		System.out.println("CompareA:上海");
      	}
      }
      
    • 接口中定义的静态方法,只能通过接口来调用。

    • 通过实现类的对象,可以调用接口中的默认方法。如果实现类重写了接口中的默认方法,调用是,仍然调用的是重写以后的方法。

    • 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没有重写此方法的情况下,默认调用的是父类中同名同参数的方法。【类优先原则】

    • 如果实现类实现了多个接口,而这多个接口中定义了同名的默认方法。这时就必须在实现类中重写此方法。

    • 在子类(或实现类)的方法中调用父类、接口中被重写的方法。

      方法名();					// 调用自己定义的重写方法
      super.方法名();			// 调用的是父类中声明的方法
      接口名.super.方法名();	  // 调用接口中的默认方法
      

4.21:内部类

Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类。

​ 内部类的分类:成员内部类【静态、非静态】、局部内部类【方法内、代码块内、构造器内】

class Person{
	//静态成员内部类
	static class Dog{}
	//非静态成员内部类
	class Bird{}
	
	//局部内部类
	public void method(){
		class AA{}
	}
	{
		class BB{}
	}
	public Person(){
		class CC{}
	}
}
  1. 内部类的使用

    • 作为外部类的成员
      1. 调用外部类的结构。
      2. 可以被static修饰。
      3. 可以被4种不同的权限修饰。
    • 作为一个类
      1. 类内可以定义属性、方法、构造器等。
      2. 可以被final修饰,表示此类不能被继承。反之,则表示可以被继承。
      3. 可以被abstract修饰。
  2. 如何实例化成员内部类的对象

    // 静态成员内部类
    外部类名.内部类名 变量名 = new 外部类名.内部类名();
    
    // 非静态成员内部类
    外部类名 外部类变量名 = new 外部类名();
    外部类名.内部类名 内部类变量名 = 外部类变量名.new 内部类名();
    
  3. 如何在成员内部类中区分调用外部类的结构

    public class InnerClassTest {
    	public static void main(String[] args) {
    		Person p = new Person();
    		Person.Bird bird = p.new Bird();
    		
    		bird.display("黄鹂");
    	}
    }
    
    class Person {
    	String name = "小明";
    
    	class Bird{
    		String name = "杜鹃";
    		
    		public void display(String name) {
    			System.out.println(name); // 方法的形参
    			System.out.println(this.name); // 内部类的属性
    			System.out.println(Person.this.name); // 外部类的属性
    		}
    	}
    }
    

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

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

相关文章

2024秋招BAT核心算法 | 详解图论

图论入门与最短路径算法 图的基本概念 由节点和边组成的集合 图的一些概念: ①有向边(有向图),无向边(无向图),权值 ②节点(度),对应无向图,…

抓狂!谷歌账号又又登录异常?给你支招解决

最近,就有很多朋友向东哥反馈说,谷歌账号登录异常了,明明账号密码都是对的,愣是登不上去,严重影响工作进度,很是捉急。所以东哥今天就总结了一份谷歌账号登录异常的解决方案,希望能帮助到大家&a…

CAS详解

CAS详解一 简介二 CAS底层原理2.1.AtomicInteger内部的重要参数2.2.AtomicInteger.getAndIncrement()分析2.2.1.getAndIncrement()方法分析2.2.2.举例分析三 CAS缺点四 CAS会导致"ABA问题"4.1.AtomicReference 原⼦引⽤。4.2.ABA问题的解决(AtomicStampedReference 类…

Eslint、Stylelint、Prettier、lint-staged、husky、commitlint【前端代码校验规则】

一、Eslint yarn add typescript-eslint/eslint-plugin typescript-eslint/parser eslint eslint-config-prettier eslint-config-standard-with-typescript eslint-plugin-import eslint-plugin-n eslint-plugin-prettier eslint-plugin-promise eslint-plugin-react eslint-…

实验四:搜索

实验四:搜索 1.填格子 题目描述 有一个由数字 0、1 组成的方阵中,存在一任意形状的封闭区域,封闭区域由数字1 包围构成,每个节点只能走上下左右 4 个方向。现要求把封闭区域内的所有空间都填写成2 输入要求 每组测试数据第一…

Provisioning Edge Inference as a Service via Online Learning 阅读笔记

通过在线学习提供边缘推理服务 一、论文研究背景、动机和主要贡献 研究背景 趋势:机器学习模型训练从中央云服务器逐步转移到边缘服务器 好处: 与云相比:a.低延迟 b.保护用户隐私(数据不会上传到云)与on-device相…

如何理解元数据、数据元、元模型、数据字典、数据模型这五个的关系?如何进行数据治理呢?数据治理该从哪方面入手呢?

如何理解元数据、数据元、元模型、数据字典、数据模型这五个的关系?如何进行数据治理呢?数据治理该从哪方面入手呢?导读一、数据元二、元数据三、数据模型四、数据字典五、元模型导读 请问元数据、数据元、数据字典、数据模型及元模型的区别…

数仓治理之数据梳理

目录 1.定义 2.用途作用 3.实施方法 3.1自上而下 3.1.1数据域梳理 3.1.2数据主题梳理 3.1.3 数据实体梳理 3.1.4设计数据模型 3.1.5优点 3.1.5缺点 3.2自下而上 3.2.1需求分析 3.2.2展现 3.2.3分析逻辑 3.2.4数据建模 3.2.5优点 3.2.6缺点 1.定义 “数据梳理”即对…

SpringBoot 如何保证接口安全?

为什么要保证接口安全对于互联网来说,只要你系统的接口暴露在外网,就避免不了接口安全问题。 如果你的接口在外网裸奔,只要让黑客知道接口的地址和参数就可以调用,那简直就是灾难。举个例子:你的网站用户注册的时候&am…

【云原生kubernetes】k8s数据存储之Volume使用详解

目录 一、什么是Volume 二、k8s中的Volume 三、k8s中常见的Volume类型 四、Volume 之 EmptyDir 4.1 EmptyDir 特点 4.2 EmptyDir 实现文件共享 4.2.1 关于busybox 4.3 操作步骤 4.3.1 创建配置模板文件yaml 4.3.2 创建Pod 4.3.3 访问nginx使其产生访问日志 4.3.4 …

I.MX6ULL_Linux_系统篇(27) 系统烧录工具

前面我们已经移植好了 uboot 和 linux kernle,制作好了根文件系统。但是我们移植都是通过网络来测试的,在实际的产品开发中肯定不可能通过网络来运行,因此我们需要将 uboot、 linux kernel、 .dtb(设备树)和 rootfs 这四个文件烧写到板子上的…

Nginx学习 (2) —— 虚拟主机配置

文章目录虚拟主机原理域名解析与泛域名解析(实践)配置文件中ServerName的匹配规则技术架构多用户二级域名短网址虚拟主机原理 为什么需要虚拟主机: 当一台主机充当服务器给用户提供资源的时候,并不是一直都有很大的用户量&#…

数据库面试题总结——DBA面试battle指南

目录 前言 数据库复制 oracle和pg的同步原理 mysql的同步原理 mysql的GTID 主从架构如何保证数据不丢失 oracle的保护模式 pg的日志传输模​​​​​​​式 mysql同步模式 从库只读 oracle的只读 pg的只读 mysql的只读 索引结构和寻迹 B树索引 索引寻迹 绑定执…

nacos源码入门

nacos官方文档地址:nacos官方文档 Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 简单来说,nacos就是一个注册中心、配置中心&#xff0…

灯具照明行业MES系统,助力企业实现数字化转型

灯具照明行业在制造领域,是典型的高科技离散生产制造模式,大部分企业都设置:电源组件、光源组件、或光电一体组件 ,工艺以SMT、DIP等。 灯罩主要采用吸塑工艺及模具加工;其它金属的面盖、灯体、灯盒基本都是采用压铸、…

传送点遍历分析

由于《天涯明月刀》的地图较大,所以每个地图中会分布很多的传送点,而这些传送点都可以在访问过地图之后以“御风神行”这类技能进行传送。为了能够很好的利用这类技能,提高外挂的效率,传送点的遍历是必不可少的。 首先找一个可以…

代码随想录算法训练营第七天|454.四数相加II 、 383. 赎金信 、 15. 三数之和 、18. 四数之和

454.四数相加II 454.四数相加II介绍给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:思路因为是存放在数组里不同位置的元素,因此不需要考虑去重的操作,而…

深度学习算法简要总结系列

今天突发奇想,准备一个总结系列,以备面试只需,嘿嘿,忘了就回来看看,以框架流程为主,不涉及细节、 点云 pointnet 代码仓库 https://github.com/yanx27/Pointnet_Pointnet2_pytorch 参考博客 论文阅读笔记 …

java单元测试批处理数据模板【亿点点日志配合分页以及多线程处理】

文章目录引入相关资料环境准备分页查询处理,减少单次批量处理的数据量级补充亿点点日志,更易观察多线程优化查询_切数据版多线程_每个线程都分页处理引入 都说后端开发能顶半个运维,我们经常需要对大量输出进行需求调整,很多时候…

Umi + React + Ant Design Pro 项目实践(一)—— 项目搭建

学习一下 Umi、 Ant Design 和 Ant Design Pro 从 0 开始创建一个简单应用。 首先,新建项目目录: 在项目目录 D:\react\demo 中,安装 Umi 脚手架: yarn create umi # npm create umi安装成功: 接下来,…