Java基础学习笔记——面向对象(上)

来源:互联网 发布:mac 搜狗五笔偏好设置 编辑:程序博客网 时间:2024/06/05 10:12

面向对象(上)

1. 类和对象

  • 类是某一批对象的抽象,可以把类理解成某种概念;对象才是一个具体存在的实体。

  • 三种最常见的成员

    • 成员变量

用于定义该类或该类的实例所包含的状态数据

  • 构造器

用于构造该类的实例

  • 方法

用于定义该类或该类的实例的行为特征或者功能实现

  • static修饰

    • 没有static修饰的普通方法和成员变量,只可通过实例来调用

    • static修饰的方法和成员变量,既可通过类来调用,也可通过实例来调用

    • static的真正作用就是用于区分成员变量、方法、内部类、初始化块这四种成员到底属于类本身还是属于实例

  • 对象、引用和指针

    • 栈内存里的引用变量并未真正存储对象的成员变量,对象的成员变量数据实际存放在堆内存里;而引用变量只是指向该堆内存里的对象
  • 对象的this引用

    • 指向

      • this关键字总是指向调用该方法的对象
    • 与static不兼容

      • 如果在static修饰的方法中使用this关键字,则这个关键字就无法指向适合的对象。所以,static修饰的方法中不能使用this引用
    • 作用

      • this可以作为一个类中,构造器相互调用的特殊格式

      • 当形参与成员变量重名时,如果在方法内部需要使用成员变量,必须添加this来表明该变量时类成员

      • 在任意方法内,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的阅读性

    • 细节

      • Java允许对象的一个成员直接调用另一个成员,可以省略this前缀

      • 使用this作为方法的返回值可以让代码更加简洁,但可能造成实际意义的模糊

2. 方法详解

  • 方法的所属性

    • 方法不能独立定义,方法只能在类体里定义

    • 从逻辑意义上来看,方法要么属于该类本身,要么属于该类的一个对象

    • 永远不能独立执行方法,执行方法必须使用类或对象作为调用者

  • 方法的参数传递机制

    • Java里方法的参数传递方式只有一种:值传递

    • 所谓值传递,就是将实际参数值的副本(复制品)传入方法内,而参数本身不会受到任何影响。

  • 形参个数可变的方法

    • 在定义方法时,在最后一个形参的类型后面增加三点(…),则表明该形参可以接受多个参数值,多个参数值被当成数组传入。

    • 形参个数可变的参数本质就是一个数组参数,区别是对于可变形参的形式定义的方法,调用方法时更加简洁。

    • 即使是采用形参个数可变的形式来定义方法,调用该方法时也一样可以为个数可变的形参传入一个数组。

    • 数组形式的形参可以处于形参列表的任意位置,但个数可变的形参只能处于形参列表的最后,也就是说,一个方法中最多只能有一个长度可变的形参。

  • 递归方法

    • 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。

    • 定义递归方法时有一条重要的规定:递归一定要向已知方向递归

  • 方法重载

    • 如果一个类中包含了两个或以上方法的方法名相同,但形参列表不同,则被称为方法重载。

3. 成员变量和局部变量

  • 成员变量

    • 定义

      • 方法体外类体内声明的变量称为成员变量
    • 分类

      • 实例变量(不以static修饰)

      • 类变量(以static修饰)

  • 局部变量

    • 定义

      • 方法体内部声明的变量称为局部变量
    • 分类

      • 形参(方法签名中定义的变量)

      • 方法局部变量(在方法内定义)

      • 代码块局部变量(在代码块内定义)

  • 成员变量和局部变量的区别

    • 访问范围

      • 成员变量定义在类中,在整个类中都可以被访问。

      • 局部变量只定义在局部范围内,如:方法内,代码块内等。

    • 存储位置

      • 成员变量分为类成员变量和实例成员变量,实例变量存在于对象所在的堆内存中。

      • 局部变量存在于栈内存中。

    • 初始化

      • 成员变量有默认初始化值。

      • 局部变量没有默认初始化值,每次必须显式初始化。

    • 权限修饰符

      • 成员变量的权限修饰符可以根据需要,选择任意一个

      • 局部变量声明时不指定权限修饰符

  • 成员变量的初始化和内存中的运行机制

    • 在类的准备阶段,系统将会为该类的类变量分配内存空间,并指定默认初始化值。

    • 实例变量是在创建实例时分配内存空间并指定初始值的

  • 局部变量的初始化和内存中的运行机制

    • 定义局部变量后,系统并未为这个变量分配内存空间,直到等到程序为这个变量赋初始值时,系统才会为局部变量分配内存,并将初始值保存到这块内存中。

    • 如果局部变量是基本类型的变量,则直接把这个变量的值保存在该变量对应的内存中

    • 如果局部变量是一个引用类型的变量,则这个变量里存放的是地址,通过该地址引用到该变量实际引用的对象或数组

    • 栈内存中的变量无须系统垃圾回收,往往随方法或代码块的运行结束而结束

  • 变量的使用规则

    • 成员变量

      • 定义的变量是用于描述某个类或某个对象的固有信息

      • 定义的变量用于保存某个类或某个实例状态信息

      • 变量保存的某个信息需要在某个类的多个方法之间进行共享

    • 局部变量

      • 应尽可能地缩小局部变量的作用范围

      • 局部变量的作用范围越小,它在内存中停留的时间就越短,程序运行性能就越好

4. 隐藏和封装

  • 理解封装

    • 封装指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
  • 使用访问控制符

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

      • public类可以在任意地方被访问。

      • default类只可以被同一个包内部的类访问。
        这里写代码片

  • package、import

    • 位于包中的类,在文件系统中也必须有与包名层次相同的目录结构

    • 虚拟机在装载带包名的类时,会先搜索CLASSPATH环境变量指定的目录,然后在这些目录中按与包层次对应的目录结构去查找class文件

    • 为Java类添加包必须在Java源文件中通过package语句指定,单靠目录名时没办法指定的

    • package语句必须作为源文件的第一条非注释性语句,一个源文件只能指定一个包,即只能包含一条package语句,该源文件中可以定义多个类,则这些类将全部位于该包下。

    • 父包和子包之间确实表示了某种内在的逻辑关系,但父包和子包在用法上则不存在任何关系,如果父包中的类需要使用子包中的类,则必须使用子包的全名,而不能省略父包部分

  • Java的常用包

    • java.lang

包含了Java语言的核心类系统自动导入

  • java.util

包含了Java的大量工具类/接口集合框架类/接口

  • java.net

包含了一些Java**网络编程**相关的类/接口

  • java.io

包含了一些Java**输入/输出**编程相关的类/接口

  • java.text

包含了一些Java**格式化**相关的类

  • javal.sql

包含了Java进行JDBC数据库编程相关的类/接口

  • java.awt

包含了抽象窗口工具集的相关类/接口,这些类主要用于构建图形用户界面(GUI)程序

  • java.swing

包含了Swing图形用户界面编程的相关类/接口,这些类可用于构建平台无关的GUI程序

5.深入构造器

  • 使用构造器执行初始化

    • 一旦自定义了构造器,系统就不会再提供默认的构造器

    • 因为构造器主要用于被其他方法调用,用以返回该类的实例,因而通常把构造器设置成public访问权限,从而允许系统中任何位置的类来创建该类的对象

  • 构造器重载

    • 同一个类里具有多个构造器,多个构造器的形参列表不同,即被称为构造器重载

    • 使用this调用另一个重载的构造器只能在构造器中使用,而且必须作为构造器执行体的第一条语句

6. 类的继承

  • 继承的特点

    • Java类只能有一个直接父类,但可以有无限多个间接父类

    • java.lang.Object类是所有类的父类,要么是其直接父类,要么是其间接父类

    • 当父类中有私有的属性或方法时,子类同样可以获取得到,只是由于封装性的设计,使得子类不可以直接调用罢了。

  • 重写父类的方法

    • 子类包含与父类同名方法的现象被称为方法重写,也被称为方法覆盖

    • 两同两小一大

      • 两同,即方法名相同、形参列表相同

      • 两小,子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等

      • 一大,子类方法的访问权限应比父类方法的访问权限更大或相等

    • 覆盖方法和被覆盖方法要么都是类方法要么都是实例方法,不能一个是类方法,一个是实例方法。

    • 当子类覆盖了父类方法之后,子类的对象将无法访问父类中被覆盖的方法,但可以在子类方法中调用父类中被覆盖的方法

    • 如果父类方法具有private访问权限,则该方法对其子类是隐藏的,子类无法访问该方法,也就无法重写该方法

    • 如果子类中定义了一个与父类private方法具有相同的方法名、相同的形参列表、相同的返回值类型的方法,依然不是重写,只是在子类中重新定义了一个新方法

    • 父类方法和子类方法之间也可能发生重载,因为子类会获得父类方法,如果子类定义了一个与父类方法有相同的方法名,但参数列表不同的方法,就会形成父类方法和子类方法的重载

  • super限定

    • super用于限定该对象调用它从父类继承得到的实例变量或方法。

    • super和this都不能出现在static修饰的方法中。

    • static修饰的方法是属于类的,该方法的调用者可能是一个类,而不是对象,因而super限定也就失去了意义

  • 调用父类构造器

    • 子类不会获得父类的构造器,但子类构造器里可以调用父类构造器的初始化代码

    • 在子类构造器中调用父类构造器使用super调用来完成

    • 使用super调用父类构造器必须出现在子类构造器执行体的第一行,所以this调用和super调用不会同时出现。

    • 子类构造器执行体中既没有super调用,也没有this调用,系统将会在执行子类构造器之前,隐式调用父类无参数的构造器

    • 当父类中没有空参数的构造器时,子类的构造器必须通过this(参数列表)或者super(参数列表)语句指定调用本类或者父类中相应的构造器,且必须放在构造器的第一行

    • 建议,设计一个类时,尽量要提供一个空参的构造器

7. 多态

  • 概述

    • Java**引用变量有两个类型**:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。若编译时类型和运行时类型不一致,就出现多态

    • Java语言中,通常用方法的重载(编译时多态)和重写(运行时多态)实现类的多态性

    • 主要指子类对象的多态(伪装的例子)

  • 多态性体现

    • 方法的重载(overload)和重写(overwrite)

    • 对象的多态性

      • 可以直接应用在抽象类和接口上

      • 一个变量只能有一种确定的数据类型

      • 一个引用类型变量可能指向(引用)多种不同类型的对象

      • 子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型(upcasting)

  • 多态的前提

    • 类与类之间有关系(要么继承,要么实现),
      要有方法覆盖,要有父类引用指向子类对象
  • 父类引用指向子类对象

    • 又称为向上转型

    • 向上转型因为是从一个专有类向一个通用类转换,所以总是很安全的。因为子类应比基类含有更多的方法,但是至少包含基类中的方法,而在向上转型的过程中,类唯一可能发生的事情是丢失方法和属性。而不是获取原本不属于它的方法。所以编译器认为这种转型是安全的,因此允许这种转型的发生。

  • 在多态中,成员函数的特点

    • 在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。

    • 在运行时期:参阅对象所属的类中是否有调用的方法。

    • 简单总结就是:成员函数在多态调用时,编译看左边,运行看右边

  • 在多态中,成员变量的特点

    • 无论编译和运行,都参考左边(引用型变量所属的类)。

    • 因为类的属性无多态性

  • 在多态中,静态成员函数的特点

    • 无论编译和运行,都参考做左边

    • 因为类的属性无多态性

8. 继承与组合

  • 使用继承的注意点

    • 设计父类的规则

这里写图片描述

  • 细节

    • 如果父类构造器调用了被其子类重写的方法,则变成调用被子类重写后的方法
  • 何时派生子类

    • 子类需要额外增加属性,而不仅仅是属性值的改变

    • 子类需要增加自己独有的行为方式(包括增加新的方法或重写父类的方法)

  • 利用组合实现复用

    • 组合是把旧类对象作为新类的成员变量组合进来,用以实现新类的功能

    • 继承关系中从多个子类里抽象出共有父类的过程,类似于组合关系中从多个整体类里提取被组合类的过程;继承关系中从父类派生子类的过程,则类似于组合关系中把被组合类组合到整体类的过程

    • 总之,继承要表达的是一种“是(is-a)“的关系,而组合表达的是”有(has-a)“的关系

9. 初始化块

  • 使用初始化块

    • 一个类里可以有多个初始化块,相同类型的初始化块之间,前面定义的先执行

    • 初始化块的修饰符只是static,使用static修饰的初始化块被称为静态初始化块

    • 初始化块只在创建Java对象时隐式执行,而且在执行构造器之前执行

    • 显示初始化或代码块初始化(此处两个结构按照顺序执行

  • 初始化块和构造器

    • 先执行父类的初始化块和构造器,再执行该类的初始化块和构造器
  • 静态初始化块

    • 也被称为类初始化块(普通初始化块负责对对象执行初始化,类初始化块负责对类进行初始化)。

    • 类初始化阶段先执行最顶层父类的静态初始化块,然后依次向下,直到执行当前类的静态初始化块。

    • 对象初始化阶段,先执行最顶层父类的初始化块、最顶层父类的构造器,然后依次向下,直到执行当前类的初始化块、当前类的构造器

    • 静态初始化块和声明静态成员变量是所指定的初始值都是该类的初始化代码,它们的执行顺序与源程序中的排列顺序相同

  • 非静态代码块:没有static修饰的代码块

    • 可以有输出语句。

    • 可以对类的属性、类的声明进行初始化操作。

    • 可以调用静态的变量或方法。

    • 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。

    • 每次创建对象的时候,都会执行一次。且先于构造器执行

  • 静态代码块:用static 修饰的代码块

    • 可以有输出语句。

    • 可以对类的属性、类的声明进行初始化操作。

    • 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。

    • 若有多个静态的代码块,那么按照从上到下的顺序依次执行。

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

    • 静态代码块只执行一次

0 0
原创粉丝点击