一、什么是面向对象
面向对象和面向过程的区别
面向对象:是一种以“对象”为中心得编程思想,万事万物皆对象。面向对象是把构成问题的事物分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。类就相当于一件事物的模型,对象就是一个模型的产物。
面向过程:是一种以“事件”为中心的编程思想。就是分析出解决问题所需要的步骤,然后用函数把这些步骤实现,并且顺序调用。
面向对象的一些概念
从软件工程的角度来说,面向对象分为三种:面向对象编程(OOP)、面向对象分析(OOA)、面向对象设计(OOD)。
对象:名词,Object,一切皆对象,只要是客观存在的(空气、时间、物品)
类:一类事物
引用:用于指代某个对象
多态:多种形态
面向对象的优点是:可重用性、可扩展性、可管理性
面向对象的四大特性(也有说三大特性,各有说法)
抽象:
抽象就是忽略一个主题中与当前目标无关的那些方面,以便于我们能够更加充分的注意与当前目标有关的方面。抽象并不打算了解全部问题,而是选择其中的一部分。暂时不用考虑部分细节。抽象分为两个方面:一是过程抽象,二是数据抽象。过程抽象是指任何一个明确定义功能的操作都可以被使用者当做单个实体看待,尽管这个操作实际上可能由一系列更低级的操作来完成。数据抽象定义了数据类型和施加于该类型对象上的操作,并限定了对象的值只能通过使用这些操作修改和观察。
例如:我们要设计一个学生成绩管理系统,考察学生对象的时候,我们只需要关心他的班级、学号、成绩等问题,不用关心他的身高、体重等问题。
继承:
继承是一种联结类的层次模型,并且允许和鼓励类的重用,他提供了一种明确表示共性的方法。对象的一个新类可以从原有类当中派生,这个过程称之为继承。新类继承了原始类的特征,新类成为原始类的派生类或者子类,而原始类称为其派生类的父类或者基类。派生类可以从他的父类或者说基类中继承实例变量和方法,并且类可以修改或增加新的方法使它更适合特殊的需要。
例如:所有的Windows应用程序都有一个窗口,他们可以看做是由一个窗口类当中派生出来的。但是有的应用程序用于文字处理,有的应用程序用于绘图,这是由于派生除了不同的子类,各个子类添加了不同的特性。
封装:
封装就是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个概念,即现实世界可以被描绘成一系列的完全自治的、封装的对象。这些对象通过一个受保护的接口访问其他对象。封装保证了模块具有较好的独立性,使得程序维护修改较为容易,对应用程序的修改仅限于类的内部,因而可以将应用程序修改带来的影响减少到最低限度。
多态:
多态是指允许不用类的对象对同一消息做出响应。多态性包括参数化多态和包含多态。多态性语言具有灵活、抽象、行为共享、代码共享的特点,很好的解决了应用程序函数同名问题。
二、相关基础知识
1)访问权限修饰符
本类 | 同一包的类 | 不同包子类 | 不同包非子类 | |
---|---|---|---|---|
public | 可以访问 | 可以访问 | 可以访问 | 可以访问 |
protect | 可以访问 | 可以访问 | 可以访问 | 不可以访问 |
default | 可以访问 | 可以访问 | 不可以访问 | 不可以访问 |
private | 可以访问 | 不可以访问 | 不可以访问 | 不可以访问 |
public:表示权限是公有的,任何对象都可以访问。
private:表示权限私有,除了在本类内部,不能被任何对象访问。
protect:和private类似,但是可以在同一包下访问,也可以被其子类对象访问。
default:当我们缺省访问权限修饰符的时候就会使用,它表示在同一包下任何对象或者元素都可以访问。
2)涉及的常用关键字
this关键字:
- 记录的是堆区对象的额地址,主要在类的内部使用,可以通过this访问对象的属性和方法
- this可以调用构造方法,例如this()可以调用无参构造器,this(参数列表)可以调用有参构造器
- 注意:this调用构造方法必须放在代码第一行
super关键字:
和this关键字作用一样,但是他是调用父类的构造器,而且在子类的构造器当中如果没有显示声明super语句,JVM会在子类构造器默认调用父类的无参构造器,而且super和this不能共存,因为他们都需要放在代码第一行。
static关键字:
引用《JAVA编程思想》中的一句话:static修饰的方法就是没有this的方法。在static修饰的方法内部不能够调用非静态方法,反过来是可以的。而且在没有创建任何对象的情况下,我们可以通过类来调用被static修饰的方法。
static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态代码块,但是java中没有全局变量的概念。而且被static修饰的代码都存储在代码区的静态域当中
a)修饰类:静态内部类
b)修饰属性:类级别的属性,被该类型的所有对象共享,访问方式:类名.属性名
c)修饰方法:类级别的方法,被该类型的所有对象共享,访问方式:类名.方法名
d)静态块:
static{
//代码
}
执行顺序:类加载器加载之后,构造器调用之前,执行静态块
静态块只会执行一次
注意:普通方法可以调用静态方法和属性,但是静态方法不能调用普通方法和属性。
静态方法中只能访问静态属性和方法,如果要访问普通的方法和属性需要创建对象调用。
final关键字:
- 修饰类,该类不能被继承。
- 修饰属性,属性必须初始化,属性只读,不可以修改。可以通过构造器初始化值。
- 修饰方法,方法不能重写
- 修饰形参,形参只读
- 修饰局部变量,可以在局部内部类访问外部变量。
常见笔试题:
final、finally、finalize的区别:
final用于声明属性、方法和类。修饰属性,表示属性不可变,值只读,且必须初始化。修饰方法,方法不可以被重写。修饰类表示类不可以被继承。finally是异常处理语句try{}catch{}语句块的一部分,表示总是被执行,通常用于资源的回收。finalize方法是Object类的方法,在垃圾回收器的轮询开始的时候,会调用回收对象的该方法,可以重写该方法用于垃圾回收时的其他资源的回收。(如果轮询没开始程序就结束了会造成内存泄漏,可以使用System.gc()手动执行轮询)
3)对象在内存中的存储形式
我们知道对象的引用是存放在栈区的,栈的对象的引用指向堆区的对象,但是堆区中的对象内部其实又有方法栈和属性栈。其中方法栈中的方法的引用指向代码区中的方法区,也就是代码区中对应方法的地址。我的理解如下图:
4)重写Overriding和重载Overload
重写:
- 重写是父类与子类之间多态性的一种体现,对父类的函数进行重新定义。如果在子类中定义某种方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。在Java中,子类可以继承父类当中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动的继承父类的方法,而是想做一定的修改,这就需要采用方法的重写。方法的重写又称为方法覆盖
- 若子类中的方法与父类中的某一方法具有相同的方法名、返回值类型和参数列表,则新方法将覆盖原有的方法。如需父类中原有的方法,可以使用super关键字,该关键字引用了当前类的父类。
- 子类函数的访问权限修饰符必须大于或者等于父类。而且父类的访问权限修饰符不能使用private封装起来。
例如:Base和Overriding类的add方法构成重写
class Base{
public void add(){
int i = 0;
System.out.println("base:"+i);
}
}
class Overriding extends Base{
public void add(){
int i = 0;
i++;
System.out.println("base:"+i);
}
}
重载:
- 方法的重载就是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。重载就是一个类当中的多态性的一种表现。
- Java的方法重载就是在勒种可以创建多个方法,他们具有相同的名字,但是具有不同的参数列表和不同的定义。调用方法时通过传递给他们的不同参数个数和参数类型来决定具体使用哪个方法,这就是多态性。
- 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。无法以返回值类型作为重载函数的区分标准。
例如:
public class Demo {
//构成重载的几种方式
public void add(){
System.out.println(1);
}
public void add(int a){
System.out.println(a);
}
public void add(String a){
System.out.println(a);
}
public void add(int a,String b){
System.out.println(a+"*"+b);
}
public void add(String a,int b){
System.out.println(a+"*"+b);
}
public int add(int a,int b){
return a+b;
}
}
常见笔试题:
Overriding重写和Overload重载的区别,Overload的方法是否可以改变返回值的类型。
方法的重写Overriding和重载Overload是多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overload是一个类当中多态性的表现。如果在子类中有与父类同名的方法,而且参数列表相同,返回值类型相同,父类方法权限访问修饰符不是private,而且子类中该方法的访问权限修饰符的权限大于等于父类中访问权限修饰符,那么我们说这个方法被重写Overriding了,子类对象调用这个方法的时候将会使用子类方法的定义。如果在一个类当中定义了很多同名的方法,但是他又不同的参数个数或者参数类型(参数列表),那么我们成为该方法被重载了,在子类中继承了父类当中的同名方法符合规则同样构成重载(Overload)。Overload的方法可以改变返回值的类型,但是不能通过不同的返回值类型来构成重载。
构造器Constructor是否可以被Overriding重写?
构造器不能被继承,所以无法构成重写,但是构造器可以被重载。
5)多态性的进一步解释
多态的分类
引用多态
- 使用父类作为形参,调用是子类对象都可以传递
- 使用父类作为属性,可以指向子类的对象的实例
- 使用父类作为返回值,返回值类型可以是任何子类对象
三、抽象类和接口
抽象类概念
抽象类的特征
- 抽象类不能够实例化
- 抽象类包含构造方法
- 抽象类可以不包含抽象方法,但是包含抽象方法的类必须被声明是抽象类
- 如果子类继承了抽象类,那么要么子类实现抽象类当中的所有抽象方法,要么声明子类也是抽象类
- 引用多态,可以父类对象的引用指向子类的实例对象
接口的概念
接口是一组规范或者一组协议,用来约束其实现类,并且补充了java单继承的不足,使Java支持多实现。
接口的特征
- 接口不能实例化
- 接口没有构造方法
- 接口中的属性自动被static final修饰为常量,接口中的所有方法都是抽象方法
- 子类实现接口,要么实现接口中的所有方法,要么声明子类是抽象类
- 子类可以实现多个接口
- 接口的引用可以指向子类对象的实例
- 接口可以继承多个接口
抽象类和接口相关笔试题
抽象类和接口有什么区别:
将抽象类和接口的特征说明一遍
接口是否可以继承接口?抽象类是否可以实现接口?抽象类是否可以继承实体类?
抽象类可以继承接口,接口也可以继承接口,抽象类也可以继承实体类,但是实体类必须要有明确的构造方法。
四、内部类
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类成为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类、静态内部类。现在来了解下四种内部类的用法。
1)成员内部类
- 成员内部类是最普通的一种内部类,相当于外部类的一个成员,成员内部类的普通方法可以无条件的访问外部类的所有成员属性和成员方法(包括被private修饰的)
- 当成员内部类和外部类有同名的成员变量或者方法时,默认调用内部类的变量和方法,如果需要使用外部类的,需要使用 外部类.this.成员变量 或者 外部类.this.成员方法 来调用
- 外部类想要调用成员内部类的方法和变量,需要创建对象,然后通过对象来调用
- 成员内部类依赖于外部类的存在而存在,如果需要创建内部类对象必须先存在外部类对象
- 成员内部类相当于外部类的一个成员,它可以拥有多种访问权限
外部类调用内部类的成员和内部类调用外部类的成员:
class Circle {
private double radius = 0;
public Circle(double radius) {
this.radius = radius;
getDrawInstance().drawSahpe(); //必须先创建成员内部类的对象,再进行访问
}
private Draw getDrawInstance() {
return new Draw();
}
class Draw { //内部类
public void drawSahpe() {
System.out.println(radius); //外部类的private成员
}
}
}
创建内部类对象的方式:
public class Test {
public static void main(String[] args) {
//第一种方式:
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner(); //必须通过Outter对象来创建
//第二种方式:
Outter.Inner inner1 = outter.getInnerInstance();
}
}
class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
class Inner {
public Inner() {
}
}
}
2)局部内部类
局部内部类和成员内部类相似,他是定义在一个方法或者作用域里面,他的访问权限仅限于方法或者作用域内
如果局部内部类要访问方法或者作用域内的局部变量,该变量必须被final修饰,当访问外部类的属性和方法时,外部类对应的属性和方法也必须被final修饰
class People{
public People() {
}
}
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{ //局部内部类
int age =0;
}
return new Woman();
}
}
注意:局部内部类类似于方法的一个局部变量一样,不能有访问权限修饰符以及static关键字修饰
3)匿名内部类
匿名内部类是我们平时写的最多的,在写事件监听的代码时使用匿名内部类方便而且便于维护。它没有名字,只是一段代码。
特征:
- 匿名内部类没有类名
- 匿名内部类可以存在于任何地方(方法内部、成员)
- 访问方法中的局部变量,该变量必须用final修饰
- 匿名内部类可以定义属性和方法
例如:
scan_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
history_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
4)静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法。因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
例如:创建静态内部类的对象
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
----------------------------------------------------------------------------------------------------------------------------------
如有错误,敬请各位大神多多批评指正!
下一节:JAVA基础复习(3)JavaBean规范和String、StringBuffer、StringBuilder
参考习题: