Java面向对象

503 阅读10分钟

类的定义

/**
 * class 类名 {
 *     0 ~ N 个成员变量(Field)
 *     0 ~ N 构造器
 *     0 ~ N 个方法
 * }
 */

对象的操作

对象的创建和使用

        Person p1 = new Person();
        p1.name = "西门吹雪";
        p1.age = 18;
        p1.dancing();

对象的实例化过程

对象的生命周期

  • 从使用new关键字在堆种开辟内存空间开始,到垃圾回收器回收期间
  • 垃圾:内存中某一块内存空间没有被某一个变量引用。

构造器

  • 构造器:主要用于创建对象和初始化对象数据。
  • 构造器的特点
    1. 构造器的名称必须和当前类名相同
    2. 没有返回值类型。
    3. 构造器种不要使用return返回当前对象
    4. 编译器提供了一个默认无参数构造器
  • 默认无参数构造器
    1. 无参数
    2. 默认构造器的访问修饰符和当前类的修饰符相同
    3. 一旦在类中自定义任意构造器,则默认构无参数造器就没有了。
  • 构造器重载
    1. 同一个类型多个构造器参数列表不同。
    2. 一旦重载任意构造器则默认无参数构造器不再提供。
public class Person { // 人类
    // 描述状态
    String name;    // 名字
    int age;        // 年龄

    // 不再默认提供无参数构造器
    public Person() {
        this(null, 0);
    }

    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
}

static修饰符

  • 概述:当我们需要描述一类事物共有的行为和状态,可以使用static修饰符。比如整个人类的总数。
  • static可以修饰成员变量,也可以修饰方法,内部类。
  • 一旦使用static修饰符修饰的成员变量、方法属于类而不属于任意一个对象。
  • static修饰符成员的特点:
    1. 随着类被加载进JVM而同时也作初始化和在内存中分配空间。
    2. 优先于对象存在。
    3. 被该类的所有对象所贡献。
    4. 直接使用类名调用即可。
  • 类成员如何使用
    1. 一般工具类的工具方法都使用static修饰。
    2. 一般的静态方法需要访问成员变量时候,此时把成员变量用static修饰。

成员变量 & 局部变量

  1. 直接定义在类的大括号内的变量成为成员变量(Field)
  2. 局部变量:
    1. 定义在方法种的变量
    2. 方式形式参数的变量
    3. 代码块种的变量。
  3. 成员变量都是有初始值的,而局部变量没有自动初始化值。
  4. Java种只有final修饰符可以修饰局部变量。
  5. 变量作用域和生命周期
    1. 成员变量在整个类种有效。
    2. 局部变量

访问权限修饰符

  1. private(类访问权限):使用private修饰的成员变量、方法、构造器、内部类只能在本类种访问。
  2. 默认修饰符(包访问权限):只有在同一个包中可以访问到。
  3. protected(子类 访问权限):即使子类和父类不在同一个包中,也可以访问。
  4. public(公共访问权限): 在任何地方都可以访问到。

继承

继承格式

  1. 概述:在原有类的基础上,加以拓展,产生新的子类的过程。
  2. 格式:
class 子类名称 extends 父类名 {
}

什么时候不用继承

  1. 子类不能继承父类的构造方法。
  2. 不要为了部分功能而去使用继承。
  3. 继承体现了is-a的关系,比如 香蕉是水果的一种。A是B的一种考虑使用继承。

继承中的成员变量的关系

  1. 子类和父类有各种的存储空间。
  2. 如果子类调用父类的方法,则方法访问的成员变量在父类存储空间中。
  3. 相同的成员变量名,调用父类的方法得到的也是父存储空间中的值。
  4. this&super: this表示当前类的引用,super表示父类存储空间标识。
    • this.Field super.Field
    • this.Method super.Method
    • this() super()调用父类构造器

继承中构造方法关系

  1. 子类中所有的构造方法,默认都会去调用父类的无参构造方法。
  2. 如果父类没有了无参构造方法(父类定义了其他有参构造方法),子类需要使用super显示调用父类其他有参构造方法。

静态代码块 & 构造代码块 & 构造方法

  1. 静态代码块 >构造代码块 > 构造方法
  2. 静态代码块随着类的加载而执行
  3. 子类加载前会先加载父类,子类初始化前会先对父类初始化
  4. 虽然子类构造方法第一行必须要是super(..),但并不会按照顺序向下直接执行,该super仅仅表示要先初始化父类,然后再初始化子类, 实际上构造方法第一行super(..)会直接跳转到父类构造方法执行,执行构造方法前会先对成员变量初始化,然后执行构造代码块语句,其本质是将成员变量,构造代码块语句合并到构造方法最前面。所以super执行完还是继续向下执行的。
  5. 一个类再初始化完毕父类后,会先把成员变量初始化,再执行初始化代码块,其本质是将成员变量初始化语句和初始化代码块语句 按顺序合并到 构造方法 最前面。 成员变量 > 构造代码块

继承中的成员方法

  1. 子类调用方法,首先在子类中找,找不到再去父类中去找。
  2. 父类私有方法不能被重写,或不算重写
  3. 子类重写父类方法时,访问权限不能比父类更低
  4. 父类静态方法,子类算不上重写,实际上是2个方法。

final关键字

  1. 常见的是final可以修饰 类、方法、变量。
  2. final修饰的类是最终类,该类不能被继承。
  3. final修饰的方法不能被重写。
  4. final修饰变量,该变量不能被修改,变成了常量。
  5. final问题:
    • final修饰局部变量,值也不可以再改变
    • final修饰引用类型,表示地址值不能变。
  6. final修饰变量要在什么时候进行初始化
    • final修饰的变量(静态变量、成员变量、临时变量)可以先定义,再赋值,不赋值前不能使用,且只能赋值一次。
    • final修饰的临时变量,必须在使用前赋值,不赋值不能使用,语法报错。
    • final修饰的成员变量,必须在构造方法执行完毕前赋值,不赋值不能使用,语法报错。
    • final修饰的静态变量,必须在静态代码块执行完毕前赋值,不赋值不能使用,语法报错。

多态

  1. 概述:同一个对象,在不同时刻体现出来的不同状态。如:猫是猫,猫也可以是动物。水可以是液体,也可以是冰(固体)。
  2. 多态的前提:
    • 要有继承关系
    • 要有方法重写
    • 父类引用指向子类对象。
  3. 多态中的成员访问特点:
    • 成员变量:编译看左边,运行也看左边。
      • 访问成员变量,实际上上在编期来确定将来访问对象内存地址的偏移量,如果符号引用的是父类的符号,则根据成员变量在父类中的偏移量,如果引用的是子类对象,则根据成员变量在子类中的偏移量。
    • 构造方法:创建子类对象时,先初始化父类,再初始化子类。
    • 成员方法:编译看左边,运行看右边。
      • 每一个对象都维护一个虚方法表,包括继承而来的方法,如果一个对象没有重写父类方法,那么子类虚方法表中的方法入口地址就和父类虚方法表中的地址是一样的。
      • 多态采用invokevirtual 动态分派,找到栈顶第一个元素this,根据方法的简单符号,去自己的虚方法表中寻找常量中的描述符合简单名都一致的方法,以此类推。
    • 静态方法:
    • Class文件中所有的方法调用都是一个符号引用,在类的解析阶段会将一部分符号引用转化为直接引用,即编译期可知,运行期不变的方法调用,这种类型的方法主要有静态方法、私有方法。
    • blog.csdn.net/u010512964/…

抽象类

  1. 抽象类和抽象方法必须使用abstract修饰
  2. 格式: abstract class 类名 {} public abstract void 方法名();
  3. 抽象类可以有构造方法,但不能实例化
  4. 抽象类的子类,必须重写抽象方法。

抽象类成员特点

  1. 成员变量:既可以有变量,也可以有常量。
  2. 构造方法:有构造方法。
  3. 成员方法:既可以是抽象的,也可以是非抽象的,抽象方法具体子类必须重写。

接口

  1. 抽象更注重,所有的子类都有这些功能,而接口更著重于 部分子类 拥有额外的功能。
    • 比如一些动物经过训练可以掌握 钻火圈等技能
  2. 为了体现 事物的 拓展性,Java提供了接口。
  3. 接口的特点:
    • 使用关键子interface定义
    • 格式:interface 接口名 {}, class 类名 implements 接口名 {}
  4. 接口成员特点:
    • 成员变量:接口中定义的成员变量只能是(默认也是隐式)静态常量public static final
    • 构造方法:接口不能定义没有构造方法。因为接口主要是功能拓展,没有具体存在的,它只有实现类。
    • 成员方法:接口种定义的方法默认都是公共抽象方法。public abstract

抽象类和接口区别:

  1. 成员区别:
    • 抽象类:
      • 成员变量:可以有变量,也可以有常量。
      • 构造方法:有。
      • 成员方法:可以是抽象的,也可以是非抽象的。
    • 接口:
      • 成员变量:只有静态常量。
      • 构造方法:无。
      • 成员方法:默认全是公共抽象的。
  2. 设计理念的不同:
    • 抽象类,被继承体现is a的关系,猫是动物,老师是人的概念,抽象类定义的是继承体系的共性功能。
    • 接口,被实现体现的是like a, 猫拥有跳高的额外功能拓展,像是一个运动员。接口定义的是继承体系的拓展功能,表明本来不具备某功能。
/**
 * 练习:乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。
 *    为了出国比赛,乒乓球相关人员要学英语,设计类和接口。
 */

  1. 设计的时候,先考虑类继承,再把额外功能设计成接口。
  2. 如果需要实现接口的类是相同种类的类,则在父类种实现接口,如果需要额外功能的类不是相同种类的类,则分开实现。

内部类

  1. 概述:把类定义在其他类的内部,成为内部类。
  2. 分类:
    1. 成员内部类(不使用static修饰的),属于外部类的一个成员,外界向访问,需要使用外部类对象进行访问(outer.new Inner();) Outer.Inner inner = new Outer().new Inner()
    2. 静态成员内部类(static修饰的内部类),属于外部类的静态成员,使用外部类类名.内部类类名访问.
    3. 成员内部类里可以访问其所属外部类成员变量或方法.本质相当于(Outer.this.Filed)
    4. 局部内部类,也可以访问外部类成员,原理同上. 内部类加static相当于静态成员,不加相当于 对象成员.
    5. 局部内部类访问局部变量,局部变量必须用final修饰,final修时候,编译期直接替换为真实的值.

匿名内部类

  1. 格式: new 类名/接口名 { 重写方法 }