什么是面向对象
面向对象编程(Object-Oriented Progaramming,OOP)
面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据
从认识论角度考虑是先有对象后有类.对象,具体的事物.类,是抽象的,是对对象抽象
从代码运行角度考虑是先有类后有对象.类是对象的模板.
类与对象的关系
类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物.
如动物,植物,手机,电脑
对象是抽象概念的具体实例
能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念.
创建和初始化对象
使用new关键字创建对象
使用new关键字的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造其的调用.
类中的构造器也成为构造方法,是在进行创建对象的时候必须要调用的.
并且构造器有以下两个特点:
- 必须和类的名字相同
- 必须没有返回类型,也不能写void
封装
该露的露,该藏的藏
我们程序设计要追求"高内聚,低耦合".
- 高内聚:就是类的内部数据操作细节自己完成,不允许外部干涉
- 低耦合:仅暴露少量的方法给外部使用
封装(数据隐藏:,通常应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问
封装的意义:
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 系统可维护增加了
继承
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模.
extend的意思是"扩展".子类是父类的扩展.
Java中类只有单继承,没有多继承.
继承是类和类之间的一种关系.除此之外,类和类之间的关系还有依赖,组合,聚合等.
继承关系的两个类,一个为子类(派生类),一个为父类(基类).子类继承父类,使用关键字extend来表示.
子类和父类之间,从意义上讲应该具有"is-a"的关系.
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为.
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
class 父类 {
}
class 子类 extends 父类 {
}
super关键字
子类的构造方法里面的一个隐式式的super存在,默认调用的是父类中的空参的构造方法
子类的构造方法为什么会有隐藏式的super存在
原因:子类会继承父类中的内容,所以子类在初始化的时候要先找到父类的初始化动作,才可以更方便的使用父类中的内容
子类的实例化过程
子类所有的构造方法都有去访问父类中的默认空参构造方法
如果要调用有参的构造方法就要用到一个显示的super
this和super不能同时出现,只能定义一个,必须要写在第一行,因为初始化动作要先执行
父类的构造方法里面是否有隐式的super?
是有的,只要是构造方法的第一行都是super
那父类调用的是谁的构造方法?
java体系在设计的时候,定义了一个所有对象的父类(Object)父类继承的是object
super注意点:
- super调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中
- super和this 不能同时调用构造方法
super和this的区别:
-
代表的对象不同:
this:调用者本身的这个对象
super:代表父类对象的应用 -
前提
this:没有继承也可以使用
super:只能在继承条件下才能使用 -
构造方法
this():本类的构造
super():父类的构造
重写
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
重写的注意事项:
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大但不能缩小 public>protected>default>private
- 抛出的异常:范围可以被缩小,但不能扩大:ClassNotFoundException -->Exception(大)
重写,子类的方法和父类必须一致,方法体不同
为什么需要重写:
父类的功能,子类不一定需要,或者不一定满足.
多态
多态是同一个行为具有多个不同表现形式或形态的能力
多态的优点:
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态存在的条件:
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
注意:多态是方法的多态,属性没有多态性
抽象类
在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口
abstract修饰符可以用来修饰方法也可以修饰类,
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样
子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明抽象类
抽象方法
如果修饰方法,那么该方法就是抽象方法
抽象方法,只有方法声明,没有方法的实现,它是用来让子类实现的
抽象方法的类一定要声明抽象类
抽象类
如果修饰类那么该类就是抽象类
抽象类,不能使用new关键字来创建对象,它是用来让子类继承的
抽象类中可以没有抽象方法
抽象类的特点:
- 抽象类里面的抽象方法都要用abstract来修饰,抽象方法一定要在抽象类当中
- 抽象类不可以创建对象,不能new对象
原因:抽象方法没具体的方法体,调用没有意义,所以不让创建对象 - 只有重写了抽象类中的抽象方法其子类才可以创建对象,不然子类也是一个抽象类
- 抽象类是一个父类吗?
是的,因为有子类要继承 - 抽象类有没有自己的构造方法?
有,虽然不能对自己实例化对象,但是可以给自己的子类实例化对象 - 抽象类和一般类的相同点:
- 它们都是用来描述事物的
- 他们之中可以定义属性和行为
抽象类和一般类的不同点:- 抽象类里面的抽象方法没有具体的方法体,一般类可以有具体的描述
- 抽象类可以多定义一个成员,这个成员是抽象方法
- 一般类可以创建对象,抽象类不可以创建对象
- 抽象类中是否可以不定义抽象方法了?
可以的,那这个抽象类有什么意义?仅仅是不让该类创建对象调用方法 - 抽象关键字不可以和哪些关键字共存?
- private:私有化之后子类没有访问权限
- final:被final修饰的类是一个最终类,既然是最终类子类就不能被继承
- static:没有意义,静态是可以通过对象来调用的
接口
接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法
类描述对象的属性和方法,接口则包含类要实现的方法
接口中的成员有几种固定的写法:
-
定义变量:但是变量有必须固定的修饰符:public static final,所以接口中的变量都称为常量
-
定义方法:方法也有固定的修饰符:public abstract
-
接口中的成员都是公共的
接口最重要的体现:
解决了多继承的弊端,将多继承这种机制在java中通过实现来完成
这就是接口的特别之处
- 怎样解决多继承的弊端?
弊端:多继承时,当继承多个父类,子类会产生不确定性
其根本的原因在于多继承父类中的功能都有方法体,从而导致了调用运行时产生了不确定性 - 为什么多实现就解决了?
是因为接口中没有方法的定义,没有方法的具体内容 - 子类要扩展功能,无法继承多父类,如何解决?
把要扩展的功能写在一个接口中,让这个子类去实现
接口与类相似点:
- 一个接口可以有多个方法。
- 接口文件保存在 .java 结尾的文件中,文件名使用接口名。
- 接口的字节码文件保存在 .class 结尾的文件中。
- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
接口与类的区别:
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法。
- 接口不能包含成员变量,除了 static 和 final 变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多继承。
接口特性:
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
接口和抽象类的区别:
- 抽象类可以提供成员方法的实现细节,而接口中只能存在抽象方法
- 类与类之间是继承方法,类与接口是实现关系
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口
- 抽象类中的成员变量可以是各种类型,而接口中的成员变量只能是 public static final类型
- 接口中不能含有静态代码块以及静态方法,而抽象类是可以有静态代码块和静态方法的
内部类
内部类的使用场景:
当描述事物时,事物的内部还有事物,这个内部事物还在访问外部事物的内容
这时就将这个事物通过内部类来描述
如果Outer类要调用Inner类里面的内容,那么Outer就要实例化Inner类里面的对象
这样就有一个弊端:麻烦
解决办法:把Inner类写到outer类,那么这个Inner类是位于Outer内部的
当Outer类的内容要被Inner类访问时,在Inner类中直接访问即可
当Outer类要访问Inner类里面的内容是,要进行对象的创建
调用方式:
外部类直接创建对象的
Outer o=new Outer();
o.print();
内部类调用要先创建外部类的对象,再创建内部类的对象
Outer.Inner i=new Outer().new Inner();
i.show();
内部类的共性:
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面会有一个$符号
- 内部类不能用普通的方式调用
- 内部类声明成静态的,就不能随便得访问外部类的成员变量了,此时内部类只能访问外部类的静态变量
- 外部类调用方式
Outer.Inner i=new Outer().new Inner();
i.show();
成员内部类:
当成员内部类拥有和外部类同名的成员变量时,会访问自己的
成员变量和成员方法不能含有静态的方法和变量
如果要访问外部类里面的成员:
外部类.this.成员变量
外部类.this.成员方法
局部内部类:
不能被成员修饰符修饰,局部内部类中访问局部变量在jdk1.8之前必须手动加上fianl,在1.8之后编译器自动添加,无需手动
静态内部类:
静态内部类不能使用外部类的非static成员变量,方法,要访问时要加上static
使用场景:静态内部类使用场景是当外部类需要使用内部类,而内部类无需外部资源
并且内部类可以单独的时候考虑采用静态的内部类
静态内部类特点:
1.静态内部类跟静态方法一样,只能访问静态的成员变量和方法,不能访问非静态的方法和属性
但是普通内部类可以访问任意外部类的成员变量和成员方法
2.静态内部类可以声明普通成员变量和方法,而普通内部类不能声明staitc成员变量和方法
3.静态内部类可以单独初始化
Inner i=new Inner();
i.shows();
匿名内部类:
当需要对Outer类的方法进行重写时就可以写一个匿名内部类
特点:内部类的方法尽可能少,一般只会写一个
弊端:如果想多次调用就的重复的写匿名内部类
格式:new Outer(){方法体}.方法名;
匿名内部类的使用原则:
1.匿名内部类不能定义任何静态成员,静态方法
2.一个匿名内部类一定是在new的后面
内部类的继承和实现:
可以通过内部类的方法对类进行继承重写,或者对接口进行实现,通过公共的方法对其内部类对象进行访问
因为通常内部类都是外部类封装其中(被private修饰);此时就可以通过父类或者接口的方式来访问到内部类对象