JavaSE-深入面向对象

Posted on 2021-03-05 15:48  MissRong  阅读(79)  评论(0)    收藏  举报

JavaSE-深入面向对象

一、面向对象的三大特征

继承、封装、多态

二、封装

封装把过程和数据包围起来,对数据的访问只能通过已定义的接口。

使用方法将类的数据隐藏起来,控制用户对类的修改和访问数据的程度。

适当的封装可以让代码更容易理解和维护,也加强了代码的安全性。

包的名字必须是小写的

类的权限(2种):

public(可以被任何代码访问)、默认的(仅可被同包的其他代码访问)

类成员的访问权限(4种):

                   本类        同一个包下(子类和无关类)           不同包下的子类           不同包下的无关类
private          Y
default          Y                            Y
protected      Y                            Y                                            Y
public            Y                            Y                                            Y                                  Y

类方法的访问权限(3种):

public、protected、private

三、继承-extends

继承是单方向的,即派生类可以继承和访问基类中的成员,但基类则无法访问派生类中的成员。
在Java中只允许单一继承方式,即一个派生类只能继承于一个基类,而不能象C++中派生类继承于多个基类的多重继承方式。

子类拥有父类的的属性和方法(private成员由于权限关系因此不能访问)
子类可以拥有自己属性和方法,即子类可以对父类进行扩展
子类可以用自己的方式实现父类的方法

Java中的继承树根节点为Object
所有Java中的类都直接或间接继承自Object

构造方法是子类继承不了的,它只能够被调用,而不能被继承。

当构建子类对象时会优先隐式自动调用父类的无参构造方法,
而且是从父类开始向子类一级一级地完成构建(高-->低),
即:如果C继承自B,而B继承自A,那么构建C的对象时,会先调用A的构造方法,
        然后调用B的构造方法,最后调用C的构造方法,以此类推。

父类构造方法的显式调用--super

如果没有无参的父类构造方法,子类必须要显示的调用父类的构造方法
通过super关键字可以在子类构造方法中显式调用父类的构造方法,该调用必须位于子类构造方法的第一行

方法的覆盖/重写:

要想完成方法覆盖/重写,需要遵从以下几个规则(4个):
发生方法覆盖的两个方法的方法名、参数列表必须完全一致(子类重写父类的方法) ,
方法返回值如果是基本数据类型,则返回值应该保持一致;
如果返回值是类,则子类覆盖方法的返回值必须是父类方法返回值或其的子类,
子类抛出的异常不能超过父类相应方法抛出的异常(子类异常不能大于父类异常) ,
子类方法的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)。

this指向当前对象,super指向父类对象

子类对象可以赋值给父类对象、抽象类对象。

四、多态

Java中多态性指允许不同类的对象对同一消息做出响应。
即:同一消息可以根据发送对象的不同而采用多种不同的行为方式,
因此,多态的主要作用适用于消除类型之间的耦合关系。

对象向上造型:

EG:人 person = new 男人()
父类(编译期类型)的引用指向子类(运行期类型)的对象

对象向下造型:

进行向下造型的对象的运行期类型必须是子类 或 以子类为根的继承树中的其他类型:
EG(Husband是Person的子类):

//向上造型
Person person = new Husband();
//向下造型
Husband husband = (Husband) person;

静态绑定发生在编译时期,动态绑定发生在运行时。

静态绑定:

类的成员变量(属性)都是静态绑定的(编译时);
也就是说,类中声明的成员变量不能被子类中的同名属性覆盖,
EG:

public class StaticBind {
  public int i = 100;
  }

  class StaticBindSub extends StaticBind {
  public int i = 10;

  public static void main(String[] args) {
    //向上造型
    StaticBind staticBind = new StaticBindSub();
    StaticBindSub staticBindSub = new StaticBindSub();
    //类的成员变量和属性都是静态绑定的
    System.out.println(staticBind.i); //100
    System.out.println(staticBindSub.i); //10
  }
}

动态绑定:

除了final(后续详细介绍),static(后续详细介绍),private和构造方法是静态绑定外,
其他的方法全部为动态绑定。
这就意味着方法调用将动态使用运行期类型版本
EG:

public class StaticBind {
   public int i = 100;
   void foo () {
     System.out.println("父类的方法");
   }
}

class StaticBindSub extends StaticBind {
  public int i = 10;
  @Override
  void foo () {
    System.out.println("子类的方法");
  }
  public static void main(String[] args) {
    //向上造型
    StaticBind staticBind = new StaticBindSub();
    StaticBindSub staticBindSub = new StaticBindSub();
    //调用的是子类的foo()
    staticBind.foo();
  }
}

重载方法中具体调用哪个版本是通过静态绑定在编译期就决定了的;
重写覆盖的方法调用哪个版本是通过动态绑定在运行期决定的。

静态绑定一般针对的是成员变量,动态绑定针对的是方法。

instansof:

运算符instanceof用来判断对象是否属于某个类的实例
如果对象的类型是instanceof后面提供的类或其子类,则返回true,反之返回false
EG :

public class TestInstanceOf {
  public static void main(String[] args) {
    Human human = new Human();
    Man man = new Man();
    human.foo(man);
  }
}
class Human{
  void foo(Human human){
    if (human instanceof Man) {
      System.out.println("男");
    } else {
      System.out.println("女");
    }
  }
}
class Man extends Human {}
class Women extends Human {}

抽象-abstract:

abstract修饰的类就是抽象类。抽象类是抽象方法的容器。
抽象类不可以直接实例化,只可以用来继承作为其他类的父类存在
抽象方法必须位于抽象类中,抽象类中可以有非抽象方法,抽象类中可以没有抽象方法
抽象方法同样用abstract说明,抽象方法没有方法体,只有方法签名
构造方法和final、static方法不可以修饰为abstract

final:

如果将某个变量修饰为final,那么该变量就成为常量
[访问权限] final 数据类型 常量名 = 值;
常量在声明时必须初始化,声明之后不能对其进行二次赋值,
其后任何试图对常量进行赋值的语句都将报错。

如果将某个成员方法修饰为final,则意味着该方法不能被子类覆盖,
这就和抽象方法必须由子类实现的规定互相矛盾,因此,final和abstract不能同时修饰一个方法。

final方法的一般声明格式是:
[访问权限] final 返回值类型 方法名(参数列表) {
    ……
}

如果某个类被修饰为final,则该类无法被继承
Java中有一个最常用的final类:java.lang.String
final类的一般声明格式是:
[访问权限] final class 类名{
成员列表...
}

static:

static 在变量或方法之前,表明它们是属于类的,称为类方法(静态方法)或类变量(静态变量)。
若无static修饰,则是实例方法和实例变量。

和类的其他成员属性不同,static成员并不存放在对象对应的堆空间中,
通过对JVM的分析发现,其会将static成员存放在方法区中,
每个对象的相应static共享同一段内存

实例变量、静态变量、实例方法、静态方法之间的关系:
可以通过类名访问静态变量,也可以通过类对象访问静态变量,
但是注意:要避免后者,因为会增加编译器的成本。

静态方法、普通方法 均可以访问静态变量;
静态方法不可以访问普通变量(实例变量)。

类的实例化对象可以访问其静态方法;
直接通过类名也可以访问静态方法。

实例方法可以直接调用静态方法;
静态方法不可以直接调用实例方法,但是可以通过类对象调用。

接口-interface:

面向接口编程的意思是指:在面向对象的系统中所有的类 或者 模块之间的交互 是由接口完成的

[访问权限] interface 接口名 {
  公开静态常量列表;
  公开抽象方法列表;
}

在接口中的方法均是抽象的,下表中罗列了接口和抽象类的差异:
                         abstractclass                       interface
属性                     不用限制                   public静态常量(public static final)
构造方法              可有可无                            没有
普通方法              可以有具体方法        必须是public抽象方法
子类                     单一继承                  多重实现(接口继承接口时为多重继承)

成员变量方面,在接口中只存在公开静态常量
(即便没有使用static final修饰,Java也会默认确定其性质)
成员方法方面,在接口中只存在公开抽象方法
(即便没有abstract修饰,Java也会默认其抽象性质)

和抽象类一样,它不能用于实例化对象,只能作为继承树的高层结构被子类实现

在描述类与类的继承关系时extends后面只能跟一个名字,
在描述接口与接口之间的继承关系时,extends后面可以跟一个列表。
使用implements关键字来让类实现一个或多个接口。

JDK1.8之后,接口中还可以有默认的方法-default。
类型层次中任何符合override规则的方法,优先于默认方法。

如果一个类实现一个接口,那么他必须实现接口中的所有方法。

枚举-enum:

[访问权限] enum 枚举名{
    枚举值列表

博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3