1、面向对象
面向对象(Object Oriented)是一种新兴的程序设计方法,或者是一种新的程序设计规范(paradigm),其基本思想是使用对象、类、继承、封装、多态等基本概念来进行程序设计。从现实世界中客观存在的事物(即对象)出发来构造软件系统,并且在系统构造中尽可能运用人类的自然思维方式。
2、对象
对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组服务组成。
类的实例化可生成对象,一个对象的生命周期包括三个阶段:生成、使用、消除。
当不存在对一个对象的引用时,该对象成为一个无用对象。Java的垃圾收集器自动扫描对象的动态内存区,把没有引用的对象作为垃圾收集起来并释放。当系统内存用尽或调用System.gc( )要求垃圾回收时,垃圾回收线程与系统同步运行。
3、类
类是具有相同属性和方法的一组对象的集合,它为属于该类的所有对象提供了统一的抽象描述,其内部包括属性和方法两个主要部分。在面向对象的编程语言中,类是一个独立的程序单位,它应该有一个类名并包括属性和方法两个主要部分。
Java中的类实现包括两个部分:类声明和类体。
类声明
[public][abstract|final] class className [extends superclassName] [implements interfaceNameList]{……}
其中,修饰符public,abstract,final 说明了类的属性,className为类名,superclassName为类的父类的名字,interfaceNameList为类所实现的接口列表。
类体
class className{
//成员变量
[public | protected | private ] [static] [final] [transient] [volatile] type variableName;
//成员方法
[public | protected | private ] [static] [final | abstract] [native] [synchronized] returnType methodName([paramList]) [throws exceptionList]{
statements
}
}
成员变量限定词的含义:
static: 静态变量(类变量)
final: 常量;
transient: 暂时性变量,用于对象存档,用于对象的串行化
volatile: 贡献变量,用于并发线程的共享
方法的实现也包括两部分内容:方法声明和方法体。
方法声明
方法声明中的限定词的含义:
static: 类方法,可通过类名直接调用
abstract: 抽象方法,没有方法体
final: 方法不能被重写
native: 集成其它语言的代码
synchronized: 控制多个并发线程的访问
方法声明包括方法名、返回类型和外部参数。其中参数的类型可以是简单数据类型,也可以是复合数据类型(又称引用数据类型)。
对于简单数据类型来说,java实现的是值传递,方法接收参数的值,但不能改变这些参数的值。如果要改变参数的值,则用引用数据类型,因为引用数据类型传递给方法的是数据在内存中的地址,方法中对数据的操作可以改变数据的值。
方法体
方法体是对方法的实现,它包括局部变量的声明以及所有合法的Java指令。方法体中声明的局部变量的作用域在该方法内部。若局部变量与类的成员变量同名,则类的成员变量被隐藏。
为了区别参数和类的成员变量,我们必须使用this。this用在一个方法中引用当前对象,它的值是调用该方法的对象。返回值须与返回类型一致,或者完全相同,或是其子类。当返回类型是接口时,返回值必须实现该接口。
构造方法
构造方法是一个特殊的方法。Java 中的每个类都有构造方法,用来初始化该类的一个对象。
构造方法具有和类名相同的名称,而且不返回任何数据类型。
重载经常用于构造方法。
构造方法只能由new运算符调用
4、面向对象的基本特性
封装
定义:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。
目的:增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,一特定的访问权限来使用类的成员。
基本要求: 把所有的属性私有化,对每个属性提供 getter 和 setter 方法,如果有一个带参的构造函数的话,那一定要写一个不带参的构造函数。在开发的时候经常要对已经编写的类进行测试,所以在有的时候还有重写 toString 方法,但这不是必须的。
封装的步骤:
i.修改属性的可见性 (设为 private ,防止错误的修改)
ii.创建公有的 getter / setter 方法 (用于属性的读写)
iii.在 getter / setter 方法中加入属性控制语句 (对属性的合法性进行判断)
类成员的访问修饰符:
作用域 / 修饰符 | Public | Protected | 无修饰符(default) | Private |
---|---|---|---|---|
同一个类 | √ | √ | √ | √ |
同一个包 | √ | √ | √ | × |
(不同包的)子类 | √ | √ | × | × |
不同包 | √ | × | × | × |
继承
目的: 实现代码复用(重用)。
介绍: 当两个类具有相同的特征(属性)和行为(方法)时,可以将相同的部分抽取出来放到一个类中作为父类,其它两个类继承这个父类。继承后子类自动拥有了父类的属性和方法。
注意: 父类的私有属性和构造方法并不能被继承。另外子类可以写自己特有的属性和方法,目的是实现功能的扩展,子类也可以复写父类的方法即方法的重写。子类不能继承父类中访问权限为 private 的成员变量和方法。子类可以重写父类的方法,及命名与父类同名的成员变量。有时候我们需要这样的需求:我们需要将某些事物尽可能地对这个世界隐藏,但是仍然允许子类的成员来访问它们。这个时候就需要使用到 protected 。
使用继承的方法:
.编写父类
.编写子类,继承父类( Java 中只支持单根继承,即一个类只能有一个直接父类)
方法重写
.方法的重写或方法的覆盖(overriding):
子类根据需求对从父类继承的方法进行重新编写(例如鸵鸟继承鸟类的飞翔方法,但鸟类的飞翔方式并不适用鸵鸟,所以鸵鸟需要重写鸟类的飞翔方法)
重写后,子类对象无法访问父类中被覆盖的方法,可以用 super.方法 (或者 父类名.方法 )的方式来调用父类中被覆盖的方法
构造方法不能被重写(子类中重写父类 private 方法并不是真正的重写,只是定义了一个新方法)
.方法重写的规则:
方法名相同
参数列表相同
返回值类型相同或者是其子类
访问权限不能严于父类
父类的静态方法不能被子类覆盖为非静态方法,父类的非静态方法不能被子类覆盖为静态方法
子类可以定义与父类同名的静态方法,以便在子类中隐藏父类的静态方法
父类的私有方法不能被子类覆盖
不能抛出比父类方法更多的异常
.方法重写 override 与方法重载 overload 区别:
重载主要发生在同一个类的多个同名方法之间;重写发生在子类和父类的同名方法之间
重载是在一个类中定义多个形参列表不同的同名方法(只能重载构造方法);重写是在子类中定义与父类形参列表相同的同名方法。两者只是都需要方法名相同,并无太大的相似之处
比较项 | 位置 | 方法名 | 参数表 | 返回值 | 访问修饰符 |
---|---|---|---|---|---|
方法重写 | 子类 | 相同 | 相同 | 相同或是其子类 | 不能比父类更严格 |
方法重载 | 同类 | 相同 | 不相同 | 无关 | 无关 |
多态
概念: 相同的事物,调用其相同的方法,参数也相同时,但表现的行为却不同。
实现多态的三个必要条件:
继承、重写、向上转型。只有满足这三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。
。继承:在多态中必须存在有继承关系的子类和父类。
。重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
。向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
多态的实现方式:
。基于继承实现的多态:
基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。
。基于接口实现的多态
继承是通过重写父类的同一方法的几个不同子类来体现的,那么就可就是通过实现接口并覆盖接口中同一方法的几不同的类体现的。
在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。
多态性的主要表现
方法重载:通常指在同一个类中,相同的方法名对应着不同的方法实现,但是方法的参数不同.
成员覆盖:通常指在不同类(父类和子类)中,允许有相同的变量名,但是数据类型不同;也允许有相同的方法名,但是对应的方法实现不同.
**多态的好处:**程序的可扩展性及可维护性增强。
5、面向对象其他重要知识点
1、Object 类
- Object类是所有类的父类
public class Pet extends Object {
……
}
- Object 类被子类经常重写的方法
方法 | 说明 |
---|---|
toString() | 返回当前对象本身的有关信息,按字符串对象返回 |
equals() | 比较两个对象是否是同一个对象,是则返回 true |
hashCode() | 返回该对象的哈希代码值 |
getClass() | 获取当前对象所属的类信息,返回 Class 对象 |
- Object 类的
equals()
方法与操作符==
equals()
比较两个对象是否是同一个对象,是则返回 true- 操作符
==
- 简单数据类型,直接比较值。如
1 == 2
- 引用类型,比较两者是否为同一对象
- 简单数据类型,直接比较值。如
Object 类的 equals() 方法与==没区别
当有特殊需求,如认为属性相同即为同一对象时,需要重写 equals()
Java.lang.String 重写了 equals() 方法, 把 equals() 方法的判断变为了判断其值
2、类型转换
向上转型
向上转型:父类的引用指向子类对象(
Pet pet = new Dog()
)。自动进行类型转换
//测试方法
Pet pet = new Dog();
pet.setHealth(20);
Master master = new Master();
master.cure(pet);
<父类型> <引用变量名> = new <子类型>();
- 此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法,不是父类的方法
- 此时通过父类引用变量无法调用子类特有的方法(需要向下转型)
向下转型
向下转型:将一个指向子类对象的父类引用赋给一个子类的引用,即:父类类型转换为子类类型。需强制类型转换。
Dog dog=(Dog)pet; //将 pet 转换为 Dog 类型
dog.catchingFlyDisc(); //执行 Dog 特有的方法
<子类型> <引用变量名> = (<子类型> )<父类型的引用变量>;
- 在向下转型的过程中,如果没有转换为真实子类类型,会出现类型转换异常
instanceof
- 如何减少在向下转型的过程中,没有转换为真实子类类型的类型转换异常? 这是需要用到 instanceof 运算符进行类型的判断。
- Java 中提供了 instanceof 运算符来进行类型的判断。instanceof 可以用于判断一个引用类型所引用的对象是否一个类的实例。
- 注意:使用 instanceof 时,对象的类型必须和 instanceof 后面的参数所指定的类在继承上有上下级关系。
3、抽象类和接口的区别
1.语法层面上的区别
1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。
2.设计层面上的区别
1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 “是不是”的关系,而 接口 实现则是 “有没有”的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。
2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。
4、接口 interface
接口(英文:Interface),在 Java 编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
接口的几个基本特性:
- 接口没有构造方法,不能被实例化(常作为类型使用)
- 实现类必须实现接口的所有方法
- 实现类可以实现多个接口( Java 中的多继承 )implements 多个接口,使用逗号隔开
- 接口中的所有方法都是抽象方法(public abstract)
- 接口中的变量都是静态常量(public static final)
5、抽象类
抽象类往往用来表征对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。
通常在编程语句中用 abstract 修饰的类是抽象类。含有抽象方法的类称为抽象类,它不能生成对象。
抽象类是不完整的,它只能用作基类(用于被继承)。在面向对象方法中,抽象类主要用来进行类型隐藏和充当全局变量的角色。
抽象类 & 普通类:
- 抽象类不能被实例化(不能生成对象)
- 但可以创建一个引用变量,其类型是一个抽象类,指向非抽象的子类实例(多态)
- 普通类可以被实例化抽象方法:以 abstract 修饰的方法,这种方法只声明返回的数据类型、方法名称和所需的参数,没有方法体,也就是说抽象方法只需要声明而不需要实现。当一个方法为抽象方法时,意味着这个方法应该被子类的方法所重写(重载主要发生在同一个类的多个同名方法之间;重写发生在子类和父类的同名方法之间)。
抽象方法的修饰符只能用 public 或者 protected 修饰或者不用修饰符,不能被 static , private 修饰。原因如下:抽象方法没有方法体,是用来被继承的,所以不能用 private 修饰; static 修饰的方法可以通过类名来访问该方法(即该方法的方法体),抽象方法用static修饰没有意义。抽象方法 & 普通方法 & 构造方法
- 抽象方法无方法体。实例:
public abstract void method1();
- 普通方法有方法体。实例:
public void method2(){ …… }
- 构造方法是一个与类同名且没有返回值类型(连 void 也不能有)的方法。用以初始化对象。构造方法分为两种:无参构造方法、有参构造方法。 Java 类隐式声明一个无参构造方法。
Person p = new Person()
中的Person()
和public Base(){System.out.println("父类的无参构造方法");}
抽象方法 & 抽象类:- 抽象类中可以没有抽象方法,但包含了抽象方法的类必须被定义为抽象类
- 如果子类没有实现父类的所有抽象方法,子类必须被定义为抽象类
- 没有抽象构造方法,也没有抽象静态方法
- 抽象类中可以有非抽象的构造方法,创建子类的实例时可能调用
- 抽象方法无方法体。实例:
文章评论