面向对象

类和对象的概念

  1. 类在现实中是不存在的,是一个模板 概念
  2. 类代表了一类事物
  3. A和B有共同的特征,抽象总结出一个类
  4. 对象是实际存在的个体
  5. 类——> 对象 (实例化)
  6. 对象——> 类 (抽象化)

    类描述的是对象的共同特征

    状态信息 ——> 属性
    动作信息 ——> 方法

    类的定义

    修饰符列表 class 类名{ //属性 //方法 }
    java中所有的class类都是引用数据类型
    属性通常是以一个变量的形式来完成定义的

对象的创建与使用

对象 == 实例,实例变量 == 对象变量
通过一个类可以实例化多个对象
语法:
new 类名(); // new 创建对象
例如 Student s = new Student();
对象:在堆内存开辟的内存空间为对象
引用:引用是一个变量,在这个引用里保存了java对象地址
访问实例变量的语法格式

  • 读: 引用.变量名;
  • 改: 引用.变量名=值;

    声明周期

  1. 面向对象的分析 OOA
  2. 面向对象的设计 OOD
  3. 面向对象的编程 OOP

构造方法

介绍
  1. 构造方法又被称为构造器/构造函数/Construstor
  2. 语法:

【修饰符列表】 构造方法名(形参){构造方法体}
构造方法名必须和类名一致

  1. 构造器无返回值类型(也不能写void)

    作用
  2. 通过构造器方法的调用可以创建对象。

  3. 在创建对象的同时,初始化实例变量的内存空间。
    调用构造方法
  • new 构造方法名(实参);
    默认构造器
  1. 每一个类都有一个默认的构造器(缺省构造器/无参数构造方法)
  2. 当用户手动提供了构造器,那么系统将不再提供无参构造器
  3. 所以手动先写上无参构造
  4. 构造方法支持重载

面向对象

三大特征:封装、继承、多态

封装

什么是封装?

  1. 对外提供简单的操作入口(复杂性封装)例如:照相机
  2. 以后的程序可以重复的使用
  3. 封装后,对事物本省提高了安全性
  4. 封装后在会形成独立体

封装步骤

  1. 私有化
  • 使用private来进行修饰
  • private 表示私有的,所有的数据只能在本类中访问。
  • 需对外提供入口
  1. 提供入口
  • set(修改)
  • get(获取)
    get/set命名规范
    set
    public void set+属性名首字母大写(形参(只有一个)){ } 例如: public void setAge(int a){ age = a; }
    get
    public 返回值类型 get+属性名首字母大写() { } 例如: public int getAge(){ return age;}
    setter 和 getter中没有static关键字;

继承基础 extends

作用
  • 子类继承父类代码可以得到复用
  • 因为有了继承关系,才有了后期得方法覆盖和多态
    特性
  1. B类继承A类
  • 则A类为父类/超类/基类(superclass)
  • B类称为子类/派生类/拓展类(subclass)
  1. java中只支持单继承,不支持多继承也就是说不能这样写 class B extends A , C
  2. 虽然不支持多继承,但有时候会产生间接继承的效果
  3. java中规定,子类继承父类,除了构造方法不能被继承外,其余的都会继承但是父类私有的属性无法再子类中直接访问(需要用get,set方法)
  4. Java中没有继承任何东西的类,默认继承Object类(老祖宗类)
  5. 缺点: 耦合度高,父类修改,子类受牵连

class B extends A{ // java语句 }

什么时候使用继承?
  • 在实际方法中只要满足is a 条件就可以使用
  • 例如: Cat is an Animal; cat 是子类 ,animal是父类

    继承高级知识

    方法的覆盖 【override】

  • 什么时候考虑使用方法覆盖?

§ 当子类继承父类之后,继承过来的方法无法满足子类的需求时子类有权利对父类继承过来的方法进行重写
§ 例如:父类中的方法是 动物在移动,而子类的业务需求是 鸟儿在飞翔 ,

  • 含义
  • 方法覆盖就是将子类继承父类的方法进行重写/覆盖掉
  • 方法覆盖后调用子类的时候一定执行覆盖之后的方法

最好将要重写的方法复制过来; idea 可以alt+ins 生成
什么时候会构成方法覆盖

  1. 两个类必须要有继承关系
  2. 重写之后的方法和之前的方法对比

§ 方法名相同
§ 返回值类型相同
§ 形参相同

  1. 权限不能低,可以高
  2. 重写以后的方法不能比之前的方法抛出更过的异常,可以更少

注意

  1. 方法覆盖只针对方法,和属性无关
  2. 私有方法无法覆盖
  3. 构造方法不能被继承,所以不能被覆盖
  4. 只针对实例方法。覆盖静态方法毫无意义。

多态

多态基础一
两个概念

  • 向上转型 子—>父
  • 向下转型 父—>子

什么时候使用向下转型,如果想访问的方法是子类中特有的方法就必须 向下转型
向下转型语法
Animal a = new Cat(); if( a instanceof Cat){ Cat b = (Cat)a; b.doSome(); }
类型转换异常 : java.lang ClassCastException
注意:无论是向上转型还是向下转型都需要有继承关系
多态概念

多种形态
  • 编译的时候一种形态
  • 运行的时候一种形态
    多态指的是
  1. 父类型引用指向子类型对象
  2. 编译阶段:绑定父类的方法(静态绑定)
  3. 运行阶段:(动态绑定)子类型对象的方法

多态2

作用:
降低程序的耦合度,提高拓展力
如何避免类型转换异常的发生
instanceof 关键字
instanceof 可以在运行阶段动态判断引用指向的对象的类型
语法 (引用instanceof 类型)
运算结果只能是 true/false
只要是向下转型必须都要用instanceof 判断

空指针异常

例如: Student s = new Student();
s = null;
System.out.println(s.name);
如果引用为null , 那么访问这个引用里面的实例变量时会空指针异常

  • 但是静态变量可以访问
  • 空引用访问实例相关的数据一定会空指针异常
  • 实例方法
  • 实例变量

空指针异常:java.lang NullPointerException

Object源码

  • 源码中一个方法以;结尾,并且修饰符列表中有native关键字
  • 表示这个方法底层调用c++ 写的dll程序(动态连接库文件)

对比方法重载和方法重写

重载【override】
方法重载需要满足的条件

  1. 方法名相同
  2. 在同一类中
  3. 形参不同
  4. 形参不同
  5. 顺序不同
  6. 数据类型不同

重写【overwrite】
方法重写需要满足的条件

  1. 两个类必须要有继承关系
  2. 重写之后的方法和之前的方法对比
  3. 方法名相同
  4. 返回值类型相同
  5. 形参相同
  6. 权限不能低,可以高
  7. 重写以后的方法不能比之前的方法抛出更过的异常,可以更少

static

介绍

  1. 所有static关键字修饰的都是类相关的,类级别的
  2. 所有被static修饰的,都是用类名.的方式去访问

修饰

  • 成员变量
  • 实例变量 int i ;
  • 静态变量 static int a;

§ 静态变量在类加载的时候初始化完成,不需要new对象,空间就已经开出来了
§ 静态变量存储在方法区内存
§ 一般的静态变量都需要赋值
§ 同时在构造方法上也不需要写上静态变量的实参

  • 方法
  • 实例方法 public void doOther(){}
  • 静态方法 public static void doSome(){}

什么时候声明静态变量 什么时候声明实例变量呢

  • 当一个类中,都有统一的一个变量(属性)
  • 例如:中国人 类中,国籍都是中国,国籍可以声明为静态
  • 此做法可以节省内存空间 static String country = “中国”;
  • 一个对象一份实例变量
  • 只能使用 引用.的方式去访问
  • 所有对象一份是静态变量
  • 可以使用引用. 但是不建议。最好类名.

什么时候声明静态方法,什么时候声明实例方法呢?

  • 当这个方法中访问了实例变量,那么这方法一定是实例方法
  • 在以后的开发中,工具类的一般都用带static的

优点 方便,不用new对象
结论

  1. 空引用并不会对静态变量和静态方法造成影响
  2. 静态方法/变量可以用引用.的方式进行访问,但是不建议
  3. 实例方法要想访问,必须要先new对象,然后引用. 去访问
  4. 空引用会对实例造成影响

static静态代码块

语法:
static{ // 代码块代码 }

执行时间
  • 在类加载的时候执行,且只执行一次
  • (在main方法之前执行 执行顺序:自上而下)

    作用

    在类加载前做一些准备工作 (特殊的类加载时机)
    一个类中可以有多一个静态代码块

  • 静态代码块可以访问静态变量,因为他们都是在类加载时执行

  • 静态代码块不可以访问实例变量,因为实例变量在new对象之后才能访问
  • 如果静态变量在静态代码块的下面,则无法访问 遵循自上而下的顺序

实例语句块

{ // 实例代码块 }
实例语句块在构造方法执行之前执行(自动执行)
每new一次对象执行一次
作用

  1. 对象构造时机
  2. 当几个构造器里有相同的语句时,可以使用实例语句块

this

介绍

  1. 一个对象一个this
  2. this 是一个变量,是一个引用 this 保存了当前对象的内存地址,
  3. 严格上说this就是当前对象
  4. this 存储在堆内存当中,对象的内部
  5. this只能使用在没有static的方法中,(谁调用该方法,this就是谁)
  6. this. 可省略 (默认访问当前对象)
  7. this 不能出现在静态方法中(this表示当前对象,而静态方法不存在对象)

    this大部分可以省略,什么时侯不能省略呢

    例如:
    public void setAge (int age ){ this.age = age; }
    为了区分局部变量和实例变量,这种情况必须加this

    this新语法 调用本类中的构造方法

    语法:this(实参);
    通过当前的构造方法去调用另一个本类中的构造方法
    public Date (){ this(1970,1,1); } public Date(int year,int month,int day){ this.year = year; this.month = month; this.day = day; }
    注意事项:
  • this(实参) 调用的必须是本类中的构造方法
  • this() 只能出现在构造方法的第一行,且只能出现一次

super

语法

  • super(实参); 调用父类的构造方法
  • super.方法名(实参) 调用父类的方法
  • super.变量名 访问父类的变量

    super与this对比学习

    super

  • super 能出现在实例方法和构造方法中

  • super的语法是 super. super() super.方法名()
  • super不能用在静态方法中
  • super大部分可以省略
  • super()只能出现在构造方法第一行,
  • 通过当前类调用父类的构造方法(代码复用)

this

  • this 能出现在实例方法中和构造方法中
  • this的语法是 this. this();
  • this不能出现在静态方法中
  • this. 可省略 凡是为了区别变量时不可省略
  • this()只能出现在第一行,通过当前的构造方法调用其他的构造方法

super

  • 当一个构造方法第一行没有this() 没有super()时默认有一个super()
  • 表示通过当前子类的构造方法调用父类的无参构造
  • 所以必须保证父类中的无参构造必须有
  • this() 和 super()不能共存
  • Object类的构造方法一定会执行 100%
  • super关键字就是代表“当前对象”的父类型“特征”

    super() 的使用

  • 作用:初始化父类型的特征

  • 当在子类中想给父类的变量赋值的时候(封装后),
  • 可用到子类的构造方法调用父类的构造方法

public B(String name,int age){ super(name,age) } // 调用父类的有参构造

super.

  • super.name 访问的是父类的变量name
  • this.name 访问的是当前对象的name
  • super.什么时候不能省略
  • 父类中有name
  • 子类中也有name时不能省略

    super 方法名();

  • 调用父类的方法

  • super.sport(实参) 调用的是父类中的sport方法

final

final可修饰方法、变量、类等

:不可以被继承
方法
不能被覆盖(重写)
被final修饰的变量只能赋一次值
引用

  • 该引用只能指向一个对象,并且它永远指向该对象
  • 被final修饰的引用,该引用里面的数据是可以被修改的

实例变量 (少见)

  • 不会赋默认值 必须手动赋值不然编错
  • 这个手动赋值,在变量后面也可以,在构造方法里赋值也可以

常量

  • final修饰的实例变量一般都是加static的(节省内存)
  • static final 修饰变量,称为常量(全部大写 _ 连接)

例如
public static final String COUNTRY = “中国”;
存储在方法区
常量一般都是公开的

总结

类体中有

  • 实例变量、实例方法
  • 静态变量(static)静态方法(static)
  • 构造方法(有参无参)
  • 静态代码块
  • 实例语句块
  • 方法
  1. 所有实例相关的都是先创建对象 引用. 访问
  2. 所有静态相关的都是 类名. 访问
  3. 静态方法中要想访问实例变量先new对象
  4. 只要调用的方法a 和方法b 在同一类中
  5. this. 可省略(实例方法) 类名. 可省略(静态方法)

抽象类

介绍

  1. 抽象类无法实例化对象(不能new)
  2. 抽象类是类与类之间存在共同的特征,将这些特征抽象出来,来形成一个类
  3. 抽象类属于引用数据类型

语法:
【修饰符列表】abstract class 类名{ //类体 }

  1. 抽象类是用来被子类继承的
  • 子类可以是抽象类
  • 因为抽象类是要被继承的所以abstract和final不用共存(对立)
  1. 抽象类有构造方法,供子类创建对象使用

抽象方法

对抽象方法的理解
没有实现的方法,没有方法体的方法
特点

  1. 没有方法体,以分号结尾
  2. 修饰符中有 abstract 关键字
  3. 例:public abstract void doSome();
  4. 抽象方法只需声明,而不需实现某些功能

抽象类中不一定有抽象方法,有抽象方法的必须是抽象类(除接口)
抽象方法和非抽象方法可以同时存在
非抽象类继承抽象类,必须将抽象类里的方法全部实现(重写)
用abstract来修饰一个类时,这个类叫做抽象类;用abstract来修饰一个方法时,该方法叫做抽象方法。
Java面向对象 - 图1


接口

基础

【修饰符列表】 interface 接口名{ // 常量 抽象方法 } 接口中只能有 常量 和抽象方法

  1. 接口属于”引用数据类型”
  2. 接口是完全抽象的
  • 抽象类是半抽象的
  1. 接口编译后也是class 文件
  2. 接口与接口之间支持多继承

interface A extends B,C{ }

  1. 接口中 public abstract 可以省略

public interface A{ double PI = 3.14; // 常量 int sum(int i ,int j); // 抽象方法 } 在接口中 :public static final double PI = 3.14 等同于 double PI = 3.14;

  1. 接口中抽象方法的public abstract可以省略。
  2. 接口中常量的public static final可以省略。
  3. 接口中方法不能有方法体

接口二

  • 接口中所有的都是public 修饰的(公开的)
  • 类与接口直接叫做实现,用implements 实现

例如 class A implements A ,B{
}

  • 一个类支持实现多个接口
  • 当一个非抽象类实现一个接口,必须将接口中所有的方法实现
  • 继承和实现都存在时,代码写法

例如: class A extends B implements C{}
//A类继承B类 实现C接口

接口在实际开发中的作用

  1. 面向抽象 = 面向接口
  2. 有了接口就有了可插拔 ,拓展力变强
  3. 凡是能使用 has a 来描述的,同一以属性的形式存在 (实例变量)
  4. 接口可以解耦合

调用者: 面向接口调用
实现者: 面向接口实现
Java面向对象 - 图2

抽象类和接口的区别

Java面向对象 - 图3
Java面向对象 - 图4

访问权限/package

访问权限

  • private 私有的
  • protected 受保护的
  • public 公开的
  • 不写 默认

    对比

  1. private :只能在本类中访问
  2. public : 在哪里都能访问
  3. protected :表示只能在本类,同包名子类中访问
  4. 默认 : 表示再能在本类中,同报名下访问

    修饰符【访问控制】可修饰

  5. 属性 (4个都可以)

  6. 方法 (4 个都可以)
  7. 类 ( public 默认 )
  8. 接口 (public 默认)
修饰符 本类 同包 子类 任意位置
public
protected
×
默认 × ×
private × × ×

package

命名规范

  • 一般都是采用公司域名倒序
  • 公司域名倒序+项目名+模块名+功能名

    package用法

  • package语句只能出现在java源码中的第一行

  • 例如 package com.tongziyu.javase.test01

    Package

  • 为了方便程序的管理

  • 不同功能包类放在不同功能的包下

    import

    import什么时候使用

  • A类使用B类,A类B类在同一个包下,不用使用

  • A类使用B类,A类B类不在同一个包下,需要使用

    出现位置

  • import只能出现在package之下,类体之上

    类名

  • 带包名 (完整类名[全限定类名])

  • 不带包名 (简类名)