Java面向对象编程(知识归纳)

一、Java 中的类和对象

  • OOP (Object Oriented Programming),全称:面向对象程序;
  • 原先的程序是面向过程,后来演变为面向对象(底层是面向过程);

  • 类相当于蓝图,然后对象是在这个蓝图上构建出来的,且构建后的对象,在堆上分配了内存空间;
  • 一个类中包含三个内容:字段、方法、构造方法;
  • 字段相当于变量,且不同位置其变量命名又可以不一样,依次为成员变量、局部变量、全局变量;

1.对象比较:

  • hashCode:按照约定,相等的对象必须具有相等的哈希码, Objects.hashCode 用来返回对象的哈希码
  • equals(Object obj):用于比较 2 个对象的内存地址是否相等(注:如果比较的是值内容的话,就要重写方法)

2.对象拷贝:

  • protected native Object clone() throws CloneNotSupportedException:naitive 方法,返回此对象的一个副本。默认实现只做浅拷贝,且类必须实现 Cloneable 接口。
  • Object 本身没有实现 Cloneable 接口,所以在不重写 clone 方法的情况下直接直接调用该方法会发生 CloneNotSupportedException 异常

3.对象转字符串

  • public String toString():返回对象的字符串表示。默认实现返回类名@哈希码的十六进制表示,但通常会被重写以返回更有意义的信息

4.多线程调度:每个对象都可以调用 Object 的 wait/notify 方法来实现等待/通知机制。

5.反射:public final native Class<?> getClass():用于获取对象的类信息,如类名

6.垃圾回收:protected void finalize() throws Throwable:当垃圾回收器决定回收对象占用的内存时调用此方法。用于清理资源,但 Java 不推荐使用,因为它不可预测且容易导致问题,Java 9 开始已被弃用

二、Java中的包

  • Java 定义了一种名字空间,称之为包:package。一个类总是属于某个包,类名(比如Person)只是一个简写,真正的完整类名是包名.类名;
  • 在 Java 虚拟机执行的时候,JVM 只看完整类名,因此,只要包名不同,类就不同;
  • 包可以是多层结构,用.隔开。例如:java.util;(注:包没有父子关系。java.util和java.util.zip是不同的包,两者没有任何继承关系)
  • Java 内建的package机制是为了避免class命名冲突;
  • JDK 的核心类使用java.lang包,编译器会自动导入;

三、Java 中的变量

  • 局部变量:

    • 定义:在方法体内声明的变量被称为局部变量,该变量只能在该方法内使用,类中的其他方法并不知道该变量
    • 注意事项:
      • 局部变量声明在方法、构造方法或者语句块中。
      • 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,将会被销毁
      • 访问修饰符不能用于局部变量
      • 局部变量只在声明它的方法、构造方法或者语句块中可见。
      • 局部变量是在栈上分配的。
      • 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用
  • 成员变量:

    • 定义:在类内部但在方法体外声明的变量称为成员变量,或者实例变量,或者字段。之所以称为实例变量,是因为该变量只能通过类的实例(对象)来访问
    • 注意事项:
      • 成员变量声明在一个类中,但在方法、构造方法和语句块之外
      • 当一个对象被实例化之后,每个成员变量的值就跟着确定。
      • 成员变量在对象创建的时候创建,在对象被销毁的时候销毁。
      • 成员变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息。
      • 成员变量可以声明在使用前或者使用后。
      • 访问修饰符可以修饰成员变量。
      • 成员变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把成员变量设为私有。通过使用访问修饰符可以使成员变量对子类可见;成员变量具有默认值。数值型变量的默认值是 0,布尔型变量的默认值是 false,引用类型变量的默认值是 null。变量的值可以在声明时指定,也可以在构造方法中指定
  • 静态变量:

    • 定义:通过 static 关键字声明的变量被称为静态变量(类变量),它可以直接被类访问
    • 注意事项:
      • 静态变量在类中以 static 关键字声明,但必须在方法构造方法和语句块之外。
      • 无论一个类创建了多少个对象,类只拥有静态变量的一份拷贝。
      • 静态变量除了被声明为常量外很少使用。
      • 静态变量储存在静态存储区。
      • 静态变量在程序开始时创建,在程序结束时销毁。
      • 与成员变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为 public 类型。
      • 静态变量的默认值和实例变量相似。
      • 静态变量还可以在静态语句块中初始化。
  • 常量:

    • 定义:在 Java 中,有些数据的值是不会发生改变的,这些数据被叫做常量——使用 static关键字和final 关键字修饰的成员变量。常量的值一旦给定就无法改变!
    • 常有的组合:static final 、enum、(待补充)
    • 作用:
      • 代表常数,便于修改;
      • 增强程序的可读性(默写固定值等例如Up、down等代表上下);
      • Java要求常量名必须大写;

四、Java中的方法

  • 方法名规范:
    • 方法名最好反应出方法的功能;
    • 方法名最好是一个动词,并且以小写字母开头;
    • 如果方法名包含两个以上单词,那么第一个单词最好是动词,然后是形容词或者名词,并且要以驼峰式的命名方式命名;
  • 方法签名:每一个方法都有一个签名,包括方法名和参数;
  • 方法体:方法体放在一对花括号内,把一些代码放在一起,用来执行特定的任务;

  • 抽象方法:没有方法体的方法被称为抽象方法,它总是在抽象类中声明。
  • 这意味着如果类有抽象方法的话,这个类就必须是抽象的。可以使用 abstract 关键字创建抽象方法和抽象类。
    abstract class AbstractDemo {      //当一个类继承了抽象类后,就必须重写抽象方法
      abstract void display();
    }
    

五、Java的可变参数

  • 可变参数是Java 5 的时候引入的,允许方法使用任意多个、类型方法的值作为参数
  • 实际开发过程尽量不要使用可变参数,如果要使用的话,需要放在参数列表中的最后一位
  • 实现原理:
    • 当使用可变参数的时候,实际上是先创建了一个数组,该数组的大小就是可变参数的个数,然后将参数放入数组当中,再将数组传递给被调用的方法;
    • 重载带有可变参数的方法时,就必须在调用方法的时候给出明确的指示,不要让编译器去猜;

六、Java native方法

  • 背景:
    • 一般情况下,我们完全可以使用 Java 语言编写程序,但某些情况下,Java 可能满足不了需求,或者不能更好的满足需求,比如:
      • ①、标准的 Java 类库不支持。
      • ②、我们已经用另一种语言,比如说 C/C++ 编写了一个类库,如何用 Java 代码调用呢?
      • ③、某些运行次数特别多的方法,为了加快性能,需要用更接近硬件的语言(比如汇编)编写。
    • 从Java 1.1开始,Java Native Interface (JNI)标准就成为 Java 平台的一部分,它允许 Java 代码和其他语言编写的代码进行交互。
  • 缺点:
    • ①、程序不再跨平台。要想跨平台,必须在不同的系统环境下重新编译本地语言部分。
    • ②、程序不再是绝对安全的,本地代码的不当使用可能导致整个程序崩溃。一个通用规则是,你应该让本地方法集中在少数几个类当中。这样就降低了 Java 和 C/C++ 之间的耦合性。

  • native:native 用来修饰方法,用 native 声明的方法表示该方法的实现在外部定义,可以用任何语言去实现它,比如说 C/C++。 简单地讲,一个 native Method 就是一个 Java 调用非 Java 代码的接口。
  • native语法:
    • ①、修饰方法的位置必须在返回类型之前,和其余的方法控制符前后关系不受限制。
    • ②、不能用 abstract 修饰,也没有方法体,也没有左右大括号。
    • ③、返回值可以是任意类型

七、Java初始化

  • 代码初始化:
    • 类实例化的时候执行代码初始化块;
    • 实际上,代码初始化块是放在构造方法中执行的,只不过比较靠前;
    • 代码初始化块里的执行顺序是从前到后的。
    • 在默认情况下,子类的构造方法在执行的时候会主动去调用父类的构造方法。也就是说,其实是构造方法先执行的,再执行的代码初始化块
    • 静态初始化块在类加载时执行,只会执行一次,并且优先于实例初始化块和构造方法的执行;
    • 实例初始化块在每次创建对象时执行,在构造方法之前执行

八、Java抽象类

  • 定义抽象类的时候需要用到关键字 abstract,放在 class 关键字前
  • 特点:
    • 1、抽象类不能被实例化。
    • 2、抽象类应该至少有一个抽象方法,否则它没有任何意义。
    • 3、抽象类中的抽象方法没有方法体。
    • 4、抽象类的子类必须给出父类中的抽象方法的具体实现,除非该子类也是抽象类。
    • 5、可以选择性实现方法,方便子类只覆盖需要的部分

九、Java 接口

  • 定义:接口通过 interface 关键字来定义,它可以包含一些常量和方法
  • 特点:
    • 接口中允许定义变量(接口中定义的变量会在编译的时候自动加上 public static final 修饰符)
    • 接口中允许定义抽象方法(没有使用 private、default 或者 static 关键字修饰的方法是隐式抽象的,在编译的时候会自动加上 public abstract 修饰符)
    • 接口中允许定义静态方法(Java 8 之后)(静态方法无法由(实现了该接口的)类的对象调用,它只能通过接口名来调用)
    • 接口中允许定义默认方法(Java 8 之后)

  • 使用规则:
    • 接口不允许直接实例化,否则编译器会报错(必须先定义一个类去实现接口,然后再实例化类)
    • 接口可以是空的,既可以不定义变量,也可以不定义方法(最典型的例子就是 Serializable 接口,该接口用来为序列化的具体实现提供一个标记)
    • 接口的抽象方法不能是 private、protected 或者 final,否则编译器都会报错
    • 接口的变量是隐式 public static final(常量),所以其值无法改变
    • 要求实现接口所有方法

  • 作用:
    • 使某些实现类具有我们想要的功能;(即只有类实现了部分接口,才能使用对应接口的功能);
    • Java 原则上只支持单一继承,但通过接口可以实现多重继承的目的;(即让一个类实现多个接口,实现多个接口中的功能);
    • 实现多态(就是同一个事件发生在不同的对象上会产生不同的结果,即在实例化的时候,定义对象的类型一样,但实例的就是实习接口的不同类);
    • 接口的三种模式:
      • 策略模式:针对一组算法,将每一种算法封装到具有共同接口的实现类中,接口的设计者可以在不影响调用者的情况下对算法做出改变;
      • 适配器模式:针对调用者的需求对原有的接口进行转接()(即通过使用抽象类做中间体适配器,任何实现接口中的方法,后续就是适配器继承抽象类,实现自己需要的部分方法)
      • 工厂模式:工厂模式将对象的实例化推迟到子类中实现

  • 抽象类和接口的区别
    • 只能说抽象类是普通类与接口之间的一种中庸之道;
    • 接口(英文:Interface),在 Java 中是一个抽象类型,是抽象方法的集合;
    • 抽象类可以有方法体的方法,但接口没有;
    • 接口中的成员变量隐式为 static final,但抽象类不是的;
    • 一个类可以实现多个接口,但只能继承一个抽象类;
    • 接口是对类的局部(行为)进行抽象,是“有没有”的关系;
    • 抽象类是对整个类整体进行抽象,包括熟悉、行为,是“是不是”的关系;

十、Java内部类

  • 成员内部类:访问外部类的所有成员,增强逻辑关系。
  • 局部内部类:在方法内部定义,仅在方法内有效,减少可见性。
  • 匿名内部类:临时创建类的实例,方便快速实现接口或继承。
  • 静态内部类:与外部类的实例无关,仅访问静态成员,节省内存。

十一、Java继承封装多态

地位:Java的三大特征

封装:

  • 1、良好的封装能够减少耦合。
  • 2、类内部的结构可以自由修改。
  • 3、可以对成员进行更精确的控制。(即get和set进行数据转换等)
  • 4、隐藏信息,实现细节。

继承:

  • 定义:在 Java 语言中继承就是子类继承父类的属性和方法,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的方法。

  • 分类:继承分为单继承和多继承,Java 语言只支持类的单继承,但可以通过实现接口的方式达到多继承的目的

  • 实现多继承效果的方式:

    • 内部类:可以继承一个与外部类无关的类,保证了内部类的独立性,正是基于这一点,可以达到多继承的效果
    • 多层继承:子类继承父类,父类如果还继承其他的类,那么这就叫多层继承
    • 实现接口:一个类可以实现多个接口满足自己在丰富性和复杂环境的使用需求(但必须实现我这个接口中的所有方法)
  • 实现:

    • 在 Java 中,类的继承是单一继承,也就是说一个子类只能拥有一个父类,所以extends只能继承一个类。其使用语法为:
         class 子类名 extends 父类名{}
    
    • 使用 implements 关键字可以变相使 Java 拥有多继承的特性,使用范围为类实现接口的情况,一个类可以实现多个接口(接口与接口之间用逗号分开)
  • 特点:

    • 子类中不能继承父类的构造方法,但子类会调用父类的构造方法;
    • Java 虚拟机构造子类对象前会先构造父类对象,父类对象构造完成之后再来构造子类特有的属性,这被称为内存叠加。而 Java 虚拟机构造父类对象会执行父类的构造方法,所以子类构造方法必须调用 super()即父类的构造方法;如果子类的构造方法中没有显示地调用父类构造方法,则系统默认调用父类无参数的构造方法;
    • 方法重写也就是子类中出现和父类中一模一样的方法(包括返回值类型,方法名,参数列表),它建立在继承的基础上。你可以理解为方法的外壳不变,但是核心内容重写;
    • Java 子类重写继承的方法时,不可以降低方法的访问权限,子类继承父类的访问修饰符作用域不能比父类小,也就是更加开放
    • 重载可以通常理解为完成同一个事情的方法名相同,但是参数列表不同其他条件也可能不同。
    • 继承当中子类抛出的异常必须是父类抛出的异常或父类抛出异常的子异常;(子类方法的异常不可大于父类对应方法抛出异常的范围)
    • 子父初始化顺序:
      • 1.父类中静态成员变量和静态代码块
      • 2.子类中静态成员变量和静态代码块
      • 3.父类中普通成员变量和代码块,父类的构造方法
      • 4.子类中普通成员变量和代码块,子类的构造方法

多态

  • 多态的前提条件有三个:

    • 子类继承父类
    • 子类重写父类的方法
    • 父类引用指向子类的对象(避免向下转型错误)
  • 多态构造方法:先执行的是父类的构造方法,然后再执行子类的构造方法,期间如果父类的方法被子类重写就执行子类的方法

十二、java this和super关键字

this关键字

  • 指向当前对象;
  • 调用当前类的方法;(如果在当前的类中,一个方法里面调用另一个方法,那么在编译后编译器会自动在调用方法前面假设this.xxx)
  • this() 可以调用当前类的构造方法;
  • this 可以作为参数在方法中传递;(传递的就是当前的这个对象)
  • this 可以作为参数在构造方法中传递;
  • this 可以作为方法的返回值,返回当前类的对象。

super关键字

  • 指向父类对象;
  • 调用父类的方法;
  • super() 可以调用父类的构造方法。

十三、Java static关键字

  • 静态变量:静态变量只在类加载的时候获取一次内存空间,这使得静态变量很节省内存空间;

    • 由于静态变量属于一个类,所以不要通过对象引用来访问,而应该直接通过类名来访问,否则编译器会发出警告
  • 静态方法:

    • 静态方法属于这个类而不是这个类的对象;
    • 调用静态方法的时候不需要创建这个类的对象;
    • 静态方法可以访问静态变量,不能访问非静态变量和调用非静态方法
  • 静态代码块:通常用来初始化一些静态变量,它会优先于 main() 方法执行。

  • 静态内部类:

    • 第一,静态内部类不能访问外部类的所有成员变量;
    • 第二,静态内部类可以访问外部类的所有静态变量,包括私有静态变量;
    • 第三,外部类不能声明为 static

十四、Java final关键字

  • final变量

    • 修饰后的基本数据类型必须有一个默认值,且不可以被重新更改赋值;
    • final修饰的对象不可以重新new,但内部中的参数变量可以进行修改;
  • final方法

    • 修饰的方法不能被重写
    • 类是final的不能被继承,即方法不能被重写
    • 类不是final的,但所有的方法都是final的,可以被继承,然后追加一些非final的方法
  • final类

    • 为了实现字符串常量池
    • 为了线程安全
    • 为了 HashCode 的不可变性

十五、Java instanceof关键字

  • 写法:
      (object) instanceof (type)
    
  • 用法:
    • instanceof 操作符正是基于类与类之间的继承关系,以及类与接口之间的实现关系的(即 子类 instanceof 父类 返回的结果是true)
    • 如果对象是由该类创建的,那么返回的也是true;
    • 当值位null时,编译器不会报错,但是呢返回的结果都是false;
    • 该关键字经常用于类型判断,然后再进行强制转换为我们期望的类型;

十六、Java不可变对象

  • 什么是不可变类?

    • 一个类的对象在通过构造方法创建后如果状态不会再被改变,那么它就是一个不可变(immutable)类。它的所有成员变量的赋值仅在构造方法中完成,不会提供任何 setter 方法供外部类去修改。
  • 常见的不可变类:

    • String类
      • 常量池的需要;
      • hashCode需要;(因为字符串是不可变的,所以在它创建的时候,其 hashCode 就被缓存了,因此非常适合作为哈希值(比如说作为 HashMap 的键),多次调用只返回同一个值,来提高效率)
      • 线程安全;(可以在多个线程之间共享,不需要同步处理)
    • 包装器类Integer、Long等
  • 构造不可变类

    • 1)确保类是 final 的,不允许被其他类继承*。
    • 2)确保所有的成员变量(字段)是 final 的,这样的话,它们就只能在构造方法中初始化值,并且不会在随后被修改。
    • 3)不要提供任何 setter 方法。
    • 4)如果要修改类的状态,必须返回一个新的对象。(即放回对象的副本)
  • 优点:

    • 线程安全;
    • 简化调试;
    • 避免副作用;
    • 可以作为哈希表的键;
    • 提高性能,某些情况可以共享实例,减少内存的使用
  • 缺点:

    • 每次修改都需要创建新的实例,内存开销增加
    • 需要通过创建新的对象来实现状态的改变,可能使代码显得冗长

十七、方法重写和方法重载

  • 重载overload:如果一个类有多个名字相同但参数个数不同的方法,我们通常称这些方法为方法重载;
  • 重写override:如果子类具有和父类一样的方法(参数相同、返回类型相同、方法名相同,但方法体可能不同),我们称之为方法重写

十八、Java 注解(待补充用法)

十九、Java enum枚举

  • 枚举(enum),是 Java 1.5 时引入的关键字,它表示一种特殊类型的类,继承自 java.lang.Enum。
  • 枚举特性:
    • 枚举常量只能赋给枚举类型的变量,避免了类型错误;
    • 枚举是一种特殊的类,那它其实是可以定义在一个类的内部的,这样它的作用域就可以限定于这个外部类中使用;
    • 枚举还可用于 switch 语句,和基本数据类型的用法一致;

  • EnumSet 是 Java 中一个高效、有序、类型安全的枚举集合,专门用于存储枚举类型的元素

  • 特性:

    • 高效性:内部使用位向量存储枚举元素,对大型枚举集合具有高效性;
    • 有序性:集合中的元素安装枚举常量声明的顺序进行排序;
    • 类型安全:只能存储同一个枚举类型的元素,保证类型安全
  • 方法:

Enum Example

  • EnumMap 是 Java 中一个特殊的 Map 集合,专门用于存储键为枚举类型,值为任意类型的键值对.
  • 特性:
    • 高效性:EnumMap 内部使用数组存储;
    • 简化代码: EnumMap 提供了一些方便的方法,可以简化枚举键值对的操作;
    • 类型安全:只能存储同一个枚举类型的元素,保证类型安全
  • 方法:
Enum Example
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值