【Java核心技术】面向对象编程

news2024/11/18 8:51:05

在这里插入图片描述

面向对象编程

      • 1、面向过程与面向对象
        • 面向过程(POP)与面向对象(OOP)
        • 面向对象的三大特征
        • 面向对象的思想概述
      • 2、Java语言基本元素:类和对象
        • 类和对象
        • 类和对象的使用(面向对象思想落地的实现)
        • 对象的创建和使用:内存解析
      • 3、类的成员之一:属性
        • 属性(成员变量) VS 局部变量
      • 4、类的成员之二:方法
        • 方法的声明
        • 返回值类型:有返回值 VS 没有返回值
        • return 关键字的使用
        • 方法的使用
        • 理解“万事万物皆对象”
        • 方法的重载(overload)
        • 可变个数的形参
        • 方法参数的值传递机制
      • 5、面向对象特征之一:封装性
        • 四种访问权限修饰符
        • 什么是封装性?
        • 封装性的体现
      • 6、类的成员之三:构造器
      • 7、拓展知识
      • 8、关键字:this
      • 9、关键字:package
      • 10、关键字:import
      • 11、面向对象特征之二:继承性
        • 继承性的好处
        • 继承性的说明
        • Java中关于继承性的规定
        • 方法的重写(override/overwrite)
      • 12、关键字:super
        • 子类对象实例化的全过程
      • 13、面向对象特征之三:多态性
        • 区分方法的重载与重写
        • instanceof 操作符
        • ==和equals的区别
        • Java中的JUnit单元测试
      • 14、包装类(Wrapper)的使用
        • 基本类型、包装类与String类间的转换
      • 15、关键字:static
      • 16、类的成员之四:代码块(或初始化块)
        • 属性赋值的过程
      • 17、关键字:final
      • 18、关键字:abstract
        • 匿名对象
      • 19、关键字:interface
      • 20、类的内部成员之五:内部类

1、面向过程与面向对象

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

  • 二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
  • 面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。

面向对象的三大特征

  • 封装性
  • 继承性
  • 多态性

面向对象的思想概述

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

2、Java语言基本元素:类和对象

类和对象

  • 类(Class)和对象(Object)是面向对象的核心概念。
    • 类是对一类事物的描述,是抽象的、概念上的定义
    • 对象是实际存在的的该类事物的每个个体,因而也称为实例

类和对象的使用(面向对象思想落地的实现)

  • 创建类,设计类的成员
  • 创建类的对象
  • 通过"对象.属性"或"对象.方法"调用对象的结构

如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的(非static的)属性。意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。

对象的创建和使用:内存解析

  • 堆(Heap),此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。
  • 通常所说的栈(Stack),是指虚拟机栈。虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,是对象在堆内存的首地址)。方法执行完,自动释放。
  • 方法区(Method Area),用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

3、类的成员之一:属性

属性(成员变量) VS 局部变量

  • 相同点
    • 定义变量的格式:数据类型 变量名 = 变量值
    • 先声明,后使用
    • 变量都有其对应的作用域
  • 不同点
    • 在类中声明的位置不同。属性直接定义在类的一对{}内;局部变量声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
    • 关于权限修饰符的不同。属性可以在声明属性时,指明其权限,使用权限修饰符。常用的权限修饰符:private、public、缺省、protected。局部变量不可以使用权限修饰符。
    • 默认初始化值的情况
      • 属性:类的属性,根据其类型,都有默认初始化值。整型(byte、short、int、long):0;浮点型(float、double):0.0;字符型(char):0(或’\u0000’);布尔型(boolean):false;引用数据类型(类、数组、接口):null
      • 局部变量:没有默认初始值。意味着,我们在调用局部变量之前,一定要显式赋值。特别地,形参在调用时,我们赋值即可。
    • 在内存中加载的位置:属性加载在堆空间中(非static);局部变量加载在栈空间

4、类的成员之二:方法

方法的声明

权限修饰符 返回值类型 方法名(形参列表){
  方法体
}
// 注意:static、final、abstract来修饰的方法,后面再讲

返回值类型:有返回值 VS 没有返回值

  • 如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用return关键字来返回指定类型的变量或常量:“return 数据”。
  • 如果方法没有返回值,则方法声明时,使用void来表示。通常,没有返回值的方法中,就不需要使用return。但是,如果使用的话,只能“return;”表示结束此方法的意思。

return 关键字的使用

  • 使用范围:使用在方法体中
  • 作用:1、结束方法;2、针对于有返回值类型的方法,使用"return 数据"方法返回所要的数据。
  • 注意点:return关键字后面不可以声明执行语句。

方法的使用

  • 方法的使用中,可以调用当前类的属性或方法。特殊的,方法A中又调用了方法A:递归方法
  • 方法中不可以定义方法。

理解“万事万物皆对象”

  • 在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能接口
    • Scanner, String等
    • 文件:File
    • 网络资源:URL
  • 涉及到Java与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类和对象。

方法的重载(overload)

  • 重载的概念:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
  • 重载的特点:与返回值类型无关,只看参数列表,且参数列表必须不同(参数个数或参数类型)。调用时,根据方法参数列表的不同来区分。
// 返回两个整数的和
int add(int x, int y) {return x+y;}
// 返回三个整数的和
int add(int x, int y, int z) {return x+y+z;}
// 返回两个小数的和
double add(double x, double y) {return x+y;}

可变个数的形参

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

// JDK 5.0以前:采用数组形参来定义方法,传入多个同一类型的变量
public static void test(int a, String[] books);
// JDK 5.0:采用可变个数形参来定义方法,传入多个同一类型变量
public static void test(int a, String...books);
  • 声明格式:方法名(参数的类型名…参数名)
  • 可变参数:方法参数部分指定类型的参数个数是可变多个:0个,1个或多个
  • 可变个数形参的方法和同名的方法之间,彼此构成重载
  • 可变参数方法的使用与方法参数部分使用数组是一致的
  • 方法的参数部分有可变形参,需要放在形参声明的最后
  • 在一个方法的形参位置,最多只能声明一个可变个数形参
public static void main(String[] args) {
  DemoTest test = new DemoTest();
  test.show(12); // show(int i)
  test.show("hello"); // show(String s)
  test.show("hello","hello"); // show(String ... s)
  test.show(); // show(String ... s)
  test.show(new String[] {"AA", "BB", "CC"}); // show(String ... s)
}

public void show(int i) {
  System.out.println("show(int i)");
}

public void show(String s) {
  System.out.println("show(String s)");
}

public void show(String ... s) {
  System.out.println("show(String ... s)");
}

方法参数的值传递机制

Java的实参值如何传入方法呢?

  • Java里方法的参数传递方式只有一种:值传递。即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
    • 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
    • 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
int[] arr = new int[] {1,2,3};
System.out.println(arr); //地址值
char[] arr1 = new char[] {'a', 'b', 'c'};
// println()方法被重载,所以输出的不是地址值
System.out.println(arr1); //abc

5、面向对象特征之一:封装性

四种访问权限修饰符

  • Java权限修饰符public、protected、private置于类的成员定义前,用来限定对象对该类成员的访问权限
修饰符类内部同一个包不同包的子类同一个工程
privateYes
(缺省)YesYes
protectedYesYesYes
publicYesYesYesYes

对于class的权限修饰只可以用public和default(缺省)。

  • public类可以在任意地方被访问。
  • default类只可以被同一个包内部的类访问。

什么是封装性?

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

封装性的体现

  • Java规定的四种权限(从小到大排列):private、缺省、protected、public
  • 4种权限可以修饰类及类的内部结构:属性、方法、构造器、内部类
  • 具体的,4中权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类;修饰类的话,只能使用:缺省、public

总结:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小

6、类的成员之三:构造器

构造器的作用

  • 创建对象
  • 初始化对象的信息

说明

  • 如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器,默认构造器的权限修饰符与类修饰符一致
  • 定义构造器的格式:权限修饰符 类名(形参列表){}
  • 一个类中定义的多个构造器,彼此构成重载
  • 一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
  • 一个类中,至少会有一个构造器

属性赋值的过程

  • 默认初始化
  • 显式初始化
  • 构造器中的初始化
  • 通过“对象.属性”或“对象.方法”的方式赋值

7、拓展知识

JavaBean

  • JavaBean是一种Java语言写成的可重用组件。
  • 所谓JavaBean,是指符合如下标准的Java类:
    • 类是公共的
    • 有一个无参的公共的构造器
    • 有属性,且有对应的get、set方法

UML类图

  • +表示public类型,-表示private类型,#表示protected类型
  • 方法的写法:方法的类型(+、-) 方法名(参数名: 参数类型): 返回值类型
  • 属性::前是属性名,:后是属性的类型

8、关键字:this

  • this可以用来修饰、调用:属性、方法、构造器
  • this修饰属性和方法时可以理解为:当前对象或当前正在创建的对象
    • 在类的方法中,我们可以使用“this.属性”或者“this.方法”的方式,调用当前对象属性或方法。但是通常情况下,我们都选择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显示的使用“this.变量”的方式,表明此变量是属性,而非形参。
    • 在类的构造器中,我们可以使用“this.属性”或“this.方法”的方式,调用当前正在创建的对象属性或方法,但是通常情况下,我们都选择省略"this."。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的使用“this.变量”的方式,表明此变量是属性,而非形参。
  • this调用构造器
    • 我们在类的构造器中,可以显式的使用“this(形参列表)”方式,调用本类中指定的其他构造器
    • 构造器中不能通过“this(形参列表)”方式调用自己
    • 如果一个类中有n个构造器,则最多有n-1个构造器中使用了“this(形参列表)”
    • 规定,“this(形参列表)”必须声明在当前构造器的首行,因此构造器内部,最多只能声明一个“this(形参列表)”,用来调用其他的构造器

9、关键字:package

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

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

10、关键字:import

  • 在源文件中使用import显示的导入指定包下的类或接口
  • 声明在包的声明和类的声明之间
  • 如果需要导入多个类或者接口,那么就并列显式多个import语句即可
  • 举例:可以使用java.util.*的方式,一次性导入util包下的所有的类或接口
  • 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句
  • 如果在代码中使用不同包下的同名的类。那么就需要使用类的全类名的方式指明调用的是哪个类
  • 如果已导入java.a包下的类。那么如果需要使用a包的子包下的类的话,仍然需要导入。
  • import static组合的使用:调用指定类或接口下的静态的属性或方法

11、面向对象特征之二:继承性

继承性的好处

  • 减少了代码的冗余,提高了代码的复用性
  • 便于功能的拓展
  • 为之后多态性的使用,提供了前提

继承性的说明

  • 继承性的格式: class A extends B{}
  • 体现:一旦子类A继承父类B以后,子类A中就获取了父类B中的声明的所有的属性和方法。特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中的私有的结构。只是因为封装性的影响,使得子类不能直接调用父类的结构而已。
  • 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展

Java中关于继承性的规定

  • 一个类可以被多个子类继承
  • Java中类的单继承性:一个类只能有一个父类
  • 子父类是相对的概念
  • 子类直接继承的父类称为直接父类;间接继承的父类称为间接父类
  • 子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法

补充说明

  • 如果我们没有显示的声明一个类的父类的话,则此类继承于java.lang.Object类
  • 所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
  • 意味着,所有的java类都具有java.lang.Object类声明的功能。

方法的重写(override/overwrite)

  • 重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
  • 应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法
  • 重写的规定
    • 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
    • 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
      • 特殊情况:子类不能重写父类中声明为private权限的方法
    • 返回值类型:
      • 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
      • 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
      • 父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的。
    • 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
    • 子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)。

12、关键字:super

  • super可以用来调用:属性、方法、构造器
  • super的使用
    • 我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."
    • 特殊情况:当子类和父类中定义了同名的属性时,我们要想要在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性,否则默认是调用子类的属性。
    • 特殊情况:当子类重写了父类中的方法以后,我们想在子类中的方法中调用父类中被重写的方法时,则必须显式使用"super.方法"的方式,表明调用的是父类中被重写的方法,否则默认是调用子类的方法。
  • super调用构造器
    • 我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
    • "super(形参列表)"的使用,必须声明在子类构造器的首行
    • 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现
    • 在构造器的首行,没有显示的声明"this(形参列表)“或"super(形参列表)”,则默认调用的是父类中的空参的构造器
    • 在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)",调用父类中的构造器

子类对象实例化的全过程

  • 从结果上来看:(继承性)
    • 子类继承父类以后,就获取了父类中声明的属性或方法。
    • 创建子类的对象,在堆空间中,就会加载所有父类中声明的属性
  • 从过程上来看:
    • 当我们通过父类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用。
  • 明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。

13、面向对象特征之三:多态性

  • 理解多态性:可以理解为一个事物的多种形态。
  • 何为多态性:
    • 对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
  • 多态的使用,虚拟方法调用
    • 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
    • 总结:编译,看左边;运行,看右边。
  • 多态性的使用前提:
    • 类的继承关系
    • 方法的重写
  • 对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)

区分方法的重载与重写

  • 二者定义的不同:
    • 重载:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
    • 重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
  • 从编译和运行的角度看:
    • 重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。
    • 所以:对于重载而言,在方法调用之前,编译期就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”
    • 而对于多态,只有等到方法调用的那一刻,解释器运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。

instanceof 操作符

  • instanceof 关键字的使用:a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false
  • 使用情境: 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,就不进行向下转型。
  • 如果类B是类A的父类,且a instanceof A返回true,则a instanceof B也返回true

==和equals的区别

  • ==既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址
  • equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也是==;我们可以看到String等类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点
  • 具体要看自定义类里有没有重写Object的equals方法来判断
  • 通常情况下,重写equals方法,会比较类中的相应属性是否都相等

Java中的JUnit单元测试

  • 创建Java类,进行单元测试。此时的Java类要求:
    • 此类是public的
    • 此类提供公共的无参的构造器
  • 此类中声明单元测试方法。此时的单元测试方法的权限是public,没有返回值,没有形参
  • 此单元测试方法上需要声明注解:@Test
  • 写完代码后,左键双击单元测试方法名,右键:run as - JUnit Test
  • 说明:如果执行结果没有任何异常:绿条;如果执行结果出现异常:红条

14、包装类(Wrapper)的使用

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter

Byte、Short、Integer、Long、Float、Double的父类为Number;Boolean、Character的父类为Object

基本类型、包装类与String类间的转换

  • 基本数据类型 --> 包装类:自动装箱
  • 包装类 --> 基本数据类型:自动拆箱
  • 基本数据类型 --> String类:String类的valueOf()方法
  • String类 --> 基本数据类型:调用相应包装类的parseXxx(String)静态方法
  • 包装类 --> String类:包装类对象的toString()方法
// 使用parseBoolean时,如果s非空且在忽略大小写的情况下等于true,则返回true;否则返回false
public static boolean parseBoolean(String s) {
    return "true".equalsIgnoreCase(s);
}
// 三元运算符运算过程中会尽量使两边的类型一致,所以new Integer(1)被自动提升了类型
Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1); // 1.0

Object o2;
if (true) {
  o2 = new Integer(1);
} else {
  o2 = new Double(2.0);
}
System.out.println(o2); // 1
  • Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128到127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在-128到127范围内时,可以直接使用数组中的元素,不用再去new了。目的为了提高效率
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);// false

Integer m = 1;
Integer n = 1;
System.out.println(m == n);// true

Integer x = 128;
Integer y = 128;
System.out.println(x == y);// false

15、关键字:static

  • 使用static修饰属性:静态变量(或类变量)
    • 属性,按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
      • 实例变量:我们创建了类的多个对象,每个对象都独立拥有一套类中的非静态属性。当修改其中一个对象的非静态属性时,不会导致其他对象中同样的属性值修改
      • 静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的
    • static修饰属性的其他说明
      • 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
      • 静态变量的加载要早于对象的创建
      • 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中
  • 使用static修饰方法:静态方法
    • 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
    • 静态方法中,只能调用静态的方法或属性;非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
  • static注意点
    • 在静态的方法内,不能使用this关键字、super关键字
  • 开发中,如何确定一个属性是否要声明为static的?
    • 属性可以被多个对象所共享的,不会随着对象的不同而不同
    • 类中的常量也常常声明为static
  • 开发中,如何确定一个方法是否要声明为static的?
    • 操作静态属性的方法,通常设置为static的
    • 工具类中的方法,习惯上声明为static的
/**
 * 单例设计模式:
 * 1、所谓的类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。
 * 2、如何实现?
 * 	饿汉式 vs 懒汉式
 * 3、区分饿汉式和懒汉式
 * 	饿汉式:
 * 		坏处:对象加载时间过长。
 * 		好处:饿汉式是线程安全的
 * 	懒汉式:
 * 		好处:延迟对象的创建。
 * 		目前的写法坏处:线程不安全。(到多线程内容时,再修改)
 */

// 饿汉式
class Bank {
	// 1、私有化类的构造器
	private Bank() {
		
	}
	// 2、内部创建类的对象
	// 4、要求此对象也必须声明为静态的
	private static Bank instance = new Bank();
	// 3、提供公共的静态的方法,返回类的对象
	public static Bank getInstance() {
		return instance;
	}
}

// 懒汉式
class Order {
	// 1、私有化类的构造器
	private Order() {
		
	}
	// 2、声明当前类对象,没有初始化
	// 4、此对象也必须声明为static的
	private static Order instance = null;
	// 3、声明public、static的返回当前类对象的方法
	public static Order getInstance() {
		if (instance == null) {
			instance = new Order();
		}
		return instance;
	}
}

16、类的成员之四:代码块(或初始化块)

  • 代码块的作用:用来初始化类、对象
  • 代码块如果有修饰的话,只能使用static
  • 分类:静态代码块 VS 非静态代码块
  • 静态代码块
    • 内部可以有输出语句
    • 随着类的加载而执行,而且只执行一次
    • 作用:初始化类的信息
    • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
    • 静态代码块的执行要优先于非静态代码块的执行
    • 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
  • 非静态代码块
    • 内部可以有输出语句
    • 随着对象的创建而执行
    • 每创建一个对象,就执行一次非静态代码块
    • 作用:可以在创建对象时,对对象的属性等进行初始化
    • 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
    • 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

总结:由夫及子,静态先行

属性赋值的过程

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

显式初始化和在代码块中赋值的顺序先后取决于代码先后顺序

17、关键字:final

  • final可以用来修饰的结构:类、方法、变量
  • final用来修饰一个类:此类不能被其他类所继承。
  • final用来修饰方法:表明此方法不可以被重写
  • final用来修饰变量:此时的"变量"就称为是一个常量
    • final修饰属性:可以考虑赋值的位置有:显示初始化、代码块中初始化、构造器中初始化
    • final修饰局部变量:尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

static final 用来修饰属性:全局变量

18、关键字:abstract

  • abstract可以用来修饰的结构:类、方法
  • abstract修饰类:抽象类
    • 此类不能实例化
    • 抽象类中一定要有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
    • 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
  • abstract修饰方法:抽象方法
    • 抽象方法只要方法的声明,没有方法体
    • 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
    • 若子类重写了父类中的所有抽象方法后,此子类才可以实例化;若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

注意点:abstract不能用来修饰:属性、构造器等结构;abstract不能用来修饰私有方法、静态方法、final的方法、final的类

匿名对象

method(new Student()); //匿名对象

Worker worker = new Worker();
method1(worker); //非匿名的类非匿名的对象

method1(new Worker()); //非匿名的类匿名的对象

// 创建匿名子类的非匿名对象
Person p = new Person() {
  @Override
  public void eat() {
    System.out.println("吃东西");
  }
}

// 创建匿名子类的匿名对象
method1(new Person() {
  @Override
  public void eat() {
    System.out.println("吃东西");
  }
});

19、关键字:interface

  • Java中,接口和类是并列的两个结构
  • 如何定义接口,定义接口中的成员
    • JDK7及以前:只能定义全局变量和抽象方法
      • 全局常量:public static final的,但是书写时,可以省略不写
      • 抽象方法:public abstract的
    • JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
  • 接口中不能定义构造器!意味着接口不可以实例化
  • Java开发中,接口通过让类去实现(implements)的方式来使用。如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化;如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类。
  • Java类可以实现多个接口:弥补了Java单继承性的局限性。格式:class AA extends BB implements CC,DD,EE
  • 接口与接口之间可以继承,而且可以多继承。格式:interface AA extends BB,CC
  • 接口的具体使用,体现了多态性
  • 接口,实际上可以看做是一种规范
interface Flyable {
  // 全局变量
  public static final int MAX_SPEED = 7900;
  int MIN_SPEED = 1; // 省略了public static final

  // 抽象方法
  public abstract void fly();
  // 省略了public abstract
  void stop();
  // Interfaces cannot have constructors
  // public Flyable() {}
}
interface A {
  int x = 0;
}

class B {
  int x = 1;
}

class C extends B implements A {
  public void pX() {
    // 编译不通过,因为x是不明确的
    // System.out.println(x);
    System.out.println(super.x); // 1
    System.out.println(A.x); // 0
  }
}

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

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

class SubClass extends SuperClass implements CompareA, CompareB {
  public void method2() {
    System.out.println("SubClass:上海");
  }
  public void method3() {
    System.out.println("SubClass:深圳");
  }
  // 知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
  public void myMethod() {
    method3();//调用了自己定义的重写的方法
    super.method3(); //调用的是父类中声明的
    //调用接口中的默认方法
    CompareA.super.method3();
    CompareB.super.method3();
  }
}

public class SubClassTest {
  public static void main(String[] args) {
    SubClass s = new SubClass();
    // 知识点1:接口中定义的静态方法,只能通过接口来调用
    // s.method1(); // 编译错误
    // SubClass.method1(); // 编译错误
    CompareA.method1();
    // 知识点2:通过实现类的对象,可以调用接口中的默认方法。
    // 如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法。
    s.method2();
    // 知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,
    // 那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法(类优先原则)。
    // 知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
    //那么在实现类没有重写此方法的情况下,会报错——接口冲突
    //这就需要我们必须在实现类中重写此方法
    s.method3();
  }
}

20、类的内部成员之五:内部类

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

  • 内部类的分类:成员内部类(静态、非静态) VS 局部内部类(方法内、代码块内、构造器内)

  • 成员内部类:

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

// 创建Dog实例(静态的成员内部类):
Person.Dog dog = new Person.Dog();
dog.show();
// 创建Bird实例(非静态的成员内部类):
// Person.Bird bird = new Person.Bird(); // 编译错误
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
  • 如何在成员内部类中区分调用外部类的结构
public void sing() {
  // 调用外部类的非静态方法
  Person.this.eat();
  eat();
  // 调用外部类的非静态属性
  System.out.println(age);
}

public void display(String name) {
  System.out.println(name); // 方法的形参
  System.out.println(this.name); // 内部类的属性
  System.out.println(Person.this.name); // 外部类的属性
}
  • 开发中局部内部类的使用
public Comparable getComparable() {
  return new Comparable() {
    @Override
    public int compareTo(Object o) {
      return 0;
    }
  }
}
  • 在局部内部类的方法中(比如:show),如果要调用外部类所声明的方法(比如:method)中的局部变量(比如:num)的话,要求此局部变量声明为final的。
    • JDK 7及之前版本:要求此局部变量显式的声明为final的
    • JDK 8及之后版本:可以省略final的声明
public void method() {
  //局部变量-JDK 8及之后,final可以省略
  final int num = 10;
  class AA {
    public void show () {
      // num = 20;
      System.out.print(num);
    }
  }
}
  • 成员内部类和局部内部类,在编译之后,都会生成字节码文件。格式:
    • 成员内部类:外部类$内部类名.class
    • 局部内部类:外部类$数字 内部类名.class

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

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

相关文章

【瑞萨RA6系列】CoreMark移植完全指南——UART输出和SysTick计时

一、CoreMark简介 什么是CoreMark? 来自CoreMark首页的解释是: CoreMark is a simple, yet sophisticated benchmark that is designed specifically to test the functionality of a processor core. Running CoreMark produces a single-number scor…

tomcat进程注入

跟随上一篇《java进程注入》 这里使用memShell https://github.com/rebeyond/memShell 将agent.jar和inject.jar放到tomcta的web目录下 然后输入命令注入 效果: 注入成功后 可以看到agent.jar文件为了防止发现,自动清除,而且重启电脑之后&…

【Python数据分析】Python中axis的理解

axis用来为超过一维的数组定义属性。 理解时从数据变化的方向入手! 以二维数据为例,在二维数据中,1表示横轴,方向从左到右;0表示纵轴,方向从上到下从数轴的方向入手,理解数据变化,a…

测试这碗饭,你还拿得稳吗?

今年测试行业格外寒冷,大部分人为了糊口饭吃,紧紧地捂住了本来已经很嫌弃的饭碗,以便挺过寒冬迎接春天。 公司天天加班,新出了各种扣款制度,为了上老下小我忍了。 2022年度的绩效,2023年都要过完了&#xf…

Windows同时安装两个版本JDK,并实现动态切换

1、载安装两个版本的JDK 安装后,默认路径C:\Program Files\Java。 实际上JDK8有两个包一个jdk1.8.0_311,一个jre1.8.0_311。 JDK11只有一个jdk-11.0.16.1。 2、系统环境配置 设置JAVA_HOME 在环境变量中选中Path,点击编辑 点击新建&…

DARAZ使用虚拟信用卡购物教程

Daraz为阿里巴巴南亚电商平台,市场覆盖巴基斯坦、孟加拉、斯里兰卡、尼泊尔和缅甸超过5亿人口级别市场,是南亚地区最受欢迎的在线购物网站,购物APP NO.1。 注册一个DARAZ的买家账号。 找到需要购买的商品,点击Buy Now进行购买 填…

Sip通话,qq通话,微信通话,普通的通话的条件和过程描述

SiP通话 SIP电话是基于SIP(Session Initiation Protocol,会话初始化协议)协议实现的通信。SIP是一种应用层协议,用于建立、修改和终止多媒体会话,如语音通话、视频通话等。SIP电话通过SIP协议进行信令交换和媒体流传输…

【MySQL学习笔记】(二)MySQL操作库基础

库的操作 1 创建数据库2 关于字符集和校验规则2.1 查看系统字符集以及校验规则2.2 查看数据支持的字符集2.3 查看数据库支持的字符集校验规则3 删除数据库4 查看并使用数据库5 修改数据库6 查看连接情况7 备份和恢复 1 创建数据库 1)创建数据库 在学习笔记&#xf…

ChatGLM-6b本地安装手把手教学

什么是ChatGLM-6B ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型,基于 General Language Model (GLM) 架构,具有 62 亿参数。结合模型量化技术,用户可以在消费级的显卡上进行本地部署(INT4 量化级别下最低只需 6GB 显存&…

Redis【入门篇】---- Redis的Java客户端-SpringDataRedis

Redis【入门篇】---- Redis的Java客户端-SpringDataRedis 1. 快速入门1. 导入pom坐标2. 配置文件3. 测试代码 2. 数据序列化器3. StringRedisTemplate4. Hash结构操作 SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块…

网络安全|渗透测试入门学习,从零基础入门到精通—静态分析技术详解

目录 前言 1、文件类型分析 2、反汇编引擎 2.1、OllyDbg的ODDisasm 2.2、BeaEngine 2.3、Udis86 2.5、AsmJit 2.6、Keystone 2.7、小结 前言 用高级语言编写的程序有两种形式。一种程序是被编译成机器语言在CPU上执行的,例如Visual C。机器语言与汇编语言几乎…

【Docker】docker启动oracle11g并初始化数据,部署和使用

前提:已经在docker中安装好Oracle 1.启动docker: docker run --name oracle11 -p 1521:1521 -e ORACLE_ALLOW_REMOTEtrue -e ORACLE_PWDoracle -d oracleinanutshell/oracle-xe-11g出现问题,请查看:Exited 139解决Window下docke…

web漏洞-反序列化之JAVA全解(38)

首先第一个就是概念。第二个是他的利用,一个好用的工具ysoserial,主要用来生成工具的paload,修复大差不差。 #概念:我们有时候需要保存某一个对象的信息,会进行一些操作,类似于反序列化,序列化…

Mysql 逗号‘,’拼接的字符串怎么查询包含的匹配数据?

上数据 : 可以看到sn 存储的方式的逗号拼接的方式。 那么怎么去做sn这个字段的匹配查找呢? ① like (不考虑) 首先 like 是不行的, 除非你能保证 你的 逗号拼接这里面的数据不包含 重复的值, 比如 1 和…

Unreal 5 实现骨骼网格体转静态网格体顶点动画

如果需要大批量的渲染具有动作的模型,如果使用骨骼网格体渲染模型,量级上去以后,性能肯定扛不住的。如果需要实现大批量的渲染相同的带有动画的模型,我们需要实现将骨骼网格体烘焙成静态网格体,然后将骨骼网格体动画转…

D. Dot(思维+记忆化搜索dfs)

翻译: D. 点 时间限制:3秒 内存限制:256兆字节 输入:标准输入 输出:标准输出 Anton和Dasha喜欢在棋盘纸上玩不同的游戏。到11年级时,他们成功玩过了所有这类游戏,并请程序员Vova想出一个新…

基于 Leaflet 的缩放功能:在最后一层瓦片缺失时进行优化

这里写自定义目录标题 第一种方式第二种方式第三种方式 引言:Leaflet 是一个广泛使用的开源 JavaScript 库,用于创建交互式、可定制的地图应用程序。在 Leaflet 中,默认情况下,瓦片地图是通过切分成多个瓦片来展示的,这…

华为防火墙之NAT技术

1.源NAT 源NAT技术对IP报文的源地址进行转换,将私网IP地址转换成公网IP地址,使大量私网用户可以利用少量公网IP地址访问Internet,大大减少了对公网IP地址的消耗。 源NAT转换的过程如下图所示,当私网用户访问Internet的报文到达防…

Ubuntu终端最大化的3种方法

摘要:Ubuntu 系统下,使用Ctrl Alt T 快捷键唤醒终端时默认大小为 80 列 x 24 行。在某些测试中我们需要更大的窗口,而通过鼠标将窗口最大化太慢了,所以本文介绍了快速实现终端窗口最大化的 3 种方法。 声明:本文所有…

java安全——Java 默认沙箱

Java安全 Java 默认沙箱 程序设计者或者管理员通过改变沙箱的参数从而完成权限的变动更新 Java默认沙箱的设计目的是为了保护系统和用户的安全。Java虚拟机提供了一种机制,让Java应用程序在一个受限的环境中运行,也就是“沙箱”。这个沙箱能够在应用程序…