面向对象

OOP(object-oriented Programming):以类的方式组织代码,以对象的组织(封装)数据

三大特性:封装,继承,多态

 

类与对象

对象是类的一个实例,比如某个人(对象),是人(类)的一个实例

创建和初始化对象

Student student = new Student();

1、分配内存空间

2、进行默认的初始化

3、类中构造器的调用

 

构造器

调出out目录(输出目标,含.class文件):program structure->Modules->Add Content Root->out

在.class文件中可看到,所有的类都有一个隐藏的public ClassName(){}方法,即构造方法/构造器

1、构造方法必须和类同名,且无返回值;

2、每new一个实例时,都会立即执行构造方法;即:new的本质,就是在调用构造器

3、构造器一般用来初始化值

4、定义有参构造之后,想使用无参构造,需定义一个无参构造(即定义有参构造之后,无参构造会消失)

alt+insert,插入构造器

 

 

封装

程序要求高内聚,低耦合

高内聚:类的内部数据操作细节自己完成,不允许外部干涉;

低耦合:仅暴露少量的方法给外部使用

属性私有,get/set方法:alt+insert快捷键生成;

1、提高程序的安全性,保存数据

2、隐藏代码的实现细节

3、统一接口

4、系统可维护性增加了

 

继承extends

Java中只有单继承,没有多继承;

1、继承是类和类之间的关系,除此之外还有依赖、组合、聚合

2、子类(派生类),父类(基类)

3、private无法继承(public,protected,default,private)

4、所有类都直接间接继承Object类

super

1、在子类的构造器中,隐藏了一句调用父类构造器的代码:super(),且必须放在最前面

2、super必须只能出现在子类的方法或构造方法中

3、super和this不能同时调用构造方法(因为两者都必须在第一行)

this:本身调用者这个对象;没有继承也可用;this()指本类的构造;

super:代表父类对象的应用;必须有继承;super()指父类的构造;

方法的重写(非重载)

父类中的方法无法满足满足子类的业务需求,子类需要将继承过来的方法重写,即覆盖

重写的条件:1、重写发生在具有继承关系的父子类之间

                      2、返回值类型相同,方法名相同,形参列表相同(重写建议复制粘贴)

                      3、子类不能比父类更私有(原因:保证父类的方法可以被调用,详见)

                      4、子类抛出的异常不能比父类更广泛

注意:1、私有方法和构造方法不能被继承,所以不能被覆盖

           2、静态方法不存在覆盖(原因涉及多态)

           3、重写只能是方法,不存在属性

 

转型(多态预备知识)

向上转型(upcasting):子类型->父类型,自动类型转换

向下转型(downcasting):父类型->子类型,强制类型转换

转型必须要有继承,否则编译不通过

举例1:向上转型

Cat继承Animal

Animal a = new Cat();
a.move(); //move()父子类中都有,此时成功通过
a.caseMouse(); //catchMouse()为Cat类特有,此时出错

编译期是Animal中的move(),运行时是Cat中的move()(因为new时已在堆中分配内存)

详解

1、Java程序分为编译阶段和运行阶段

2、先分析编译阶段,再分析运行阶段

3、编译阶段编译器检查a的引用类型为Animal,由于Animal.class字节码文件中有move(),所以编译通过;这个过程称为静态绑定,或编译阶段绑定

4、在程序运行阶段,JVM堆内存中国真实创建的对象是Cat对象,因此运行阶段调用Cat对象的move(),此时发生动态绑定,即运行阶段绑定

5、无论Cat类是否重写,一定是调用Cat类中的Move();

6、父类型指向子类型对象,导致编译和运行阶段绑定不同状态,这种机制可以成为一种多态语法机制

问题

a.catchMouse()不通过是因为编译阶段绑定Animal,而Animal中无catchMouse,所以在编译阶段出错;

解决方案

a要调用catchMouse(),可以进行强制类型转换,即向下转型

downcasting使用时机:当调用的方法是子类型中特有的,在父类型中不存在

Cat a2 = (Cat)a;

举例2 向下转型

Animal a = new Bird();
Cat a2 = (Cat)a;

编译通过,但运行时出错,出现著名异常:java.lang.ClassCastException,这种异常通常在向下转型时发生;

向上转型时,只要编译通过,运行也能通过;而向下转型存在隐患;

解决方案

Java规范中要求,强制类型转换之前,建议采用instanceof进行判断,避免ClassCastException异常发生

假设:(a instance Animal)

true:a这个引用指向的对象是一个Animal类型

flase:a这个引用指向的对象不是一个Animal类型

if(a instanceof Cat){
    Cat a2 = (Cat)a;
    a.catchMouse;
}

问题

如果定义的是静态方法,指向的则是左边的对象,为啥?

 

instanceof

已知:Studen类和Teacher类是Person类的之类

Object object = new Student()

1、object instanceof Student  ->  true

2、object instanceof Person  ->  true

3、object instanceof Object  ->  true

4、object instanceof Teacher  ->  false

Person person = new Student()

1、person instance Object  ->  true

Student student = new Student()

1、student instanceof Person  ->  true

Person person = new Person()

1、person instanceof Student  ->  false

instanceof测试时,当被测试者是类的子孙类时,显示true

 

多态

多态:同一方法可以根据接收对象的不同而采用多种不同的行为方式(原理:向上转型upcasting)

提高程序的扩展里->降低程序的耦合

举例:主人(Master类)喂养宠物,猫(Cat类),狗(Dog类)

           喂猫需要在Master类添加一个方法,喂狗又需要一个方法……类与类之间关系紧密,这就是高耦合

多态使用举例

//新建类Pet,内涵eat()喂养方法,Cat类和Dog等都继承Pet类
public class Master {
    public void feed(Pet pet){
        pet.eat();
    }
}

此时加入传来一个Cat的实例,如上一小节中所说编译阶段是Pet类,运行是Cat类,最终调用的是Cat中的eat()方法;

关键在于,将相似的行为抽象成一个方法,写在一个类中,并使有关类继承于它(父类型的引用,指向子类型的对象)

1、Master主人类面向的是一个抽象的Pet,不再面向具体的宠物,面对抽象类的好处在于低耦合,高扩展

2、能使用多态,尽量使用多态

核心:面对抽象编程,而不面对具体编程;

多态的存在条件:有继承关系、子类重写父类、父类引用指向子类对象