面向对象的特性:
面向对象的三大特征:封装、继承、多态。有时候面试官也会说成是类的三大基本特性,其实是一回事。
1. 封装
封装是对象和类概念的主要特性。封装就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏,对外部不可见。封装的主要作用在于对外隐藏内部实现细节,增强程序的安全性。属性就是将属性私有化,提供共有的方法访问私有属性。对于属性和方法的封装都是通过加private修饰符实现的,封装之后的属性和方法对象是不能直接访问的,必须通过setter和getter方法设置和取得,setter方法用于赋值,getter方法用于取值。类中的全部属性都必须封装。这里注意,“如果子类继承了父类,对于父类中进行封装的方法,子类仍然可以直接调用”这句话是错误的。
public class Person {
private String name;
private int age;
public void tell() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0 && age < 200) {
this.age = age;
}
}
}
对封装对象的使用:
public class Use {
public static void main(String[] args) {
Person per=new Person();
//per.name = "张三"; 错误,无法访问封装数据
//per.age = -30;
per.setName("张三");
per.setAge(-30);
per.tell();
}
}
2. 继承
继承可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。在某些OOP语言中,一个子类可以继承多个基类。但是在java语言中,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承的实现方式
1. 实现继承、接口继承和可视继承。实现继承是指使用基类的属性和方法而无需额外编码的能力;
2. 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
3. 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。
在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Man属于人类,Woman也属于人类,因此这两个类都可以继承Human类。但是 Leg 类却不能继承Human类,因为腿并不是一个人。
抽象类仅定义将由子类创建的一般属性和方法,OO(面向对象)开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。
父类中属性或方法的修饰符对于子类访问的影响:
父类 | 子类 |
public | 可以 |
protected | 可以 |
缺省 | 同包可以,不同包不可以 |
private | 不可以 |
3.多态
3.1 多态的定义:
多态性(polymorphisn)允许将父对象设置成为和一个或更多的他的子对象相等,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单来说就是允许将子类类型的指针赋值给父类类型的指针。多态需满足三个条件:有继承;有重写;有父类引用指向子类对象。最终多态体现为父类引用可以指向子类对象:父类类型 变量名 = new 子类类型()。
3.2 多态的三种表现形式
1. 普通类多态定义的格式:父类类型 变量名 = new 子类类型()。
class Father {
int num = 4;
}
class Son extends Father {
int num = 5;
}
//普通类多态形式
Father father = new Son();
2. 抽象类多态定义的格式
abstract class Father {
abstract void method();
}
class Son extends Father {
public void method() {
System.out.println("abstract");
}
}
//抽象类多态表现形式
Father father = new Son();
3. 接口多态定义的格式
interface Father {
public void method();
}
class Son implements Father{
public void method() {
System.out.println("implements")
}
}
//接口多态的表现形式
Father father = new Son();
3.3 多态的编译和运行
(1)成员变量:编译和运行都看左边。
(2)成员方法:编译看左边,运行看右边。
关于多态的转型:
向上转型 | 向下转型 | |
作用 | 子类对象赋值给父类对象引用 | 父类对象引用强制转换为子类对象引用。 |
使用格式 | 父类类型 变量名 = new 子类类型() | 子类类型 变量名 = (子类类型)父类类型 |
优点 | 隐藏了子类类型,提高代码的扩展性。 | 可以使用子类特有功能。 |
缺点 | 只能使用父类共性的内容,无法使用子类特有功能。 | 容易发生类型转换异常(ClassCastException) |
实现多态,有覆盖和重载两种方式。覆盖指子类重新定义父类的虚函数的做法。重载指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。其实,重载的概念并不属于“面向对象编程”,重载的实现是:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。在java中的某个类中,如果有两个方法名相同但是参数列表(个数,类型)不同的方法,就视为重载。
3.4 多态的作用:
封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用,多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
3.5 多态的优点:
允许不同类对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用).主要有以下优点:
可替换性:多态对已存在代码具有可替换性.
可扩充性:增加新的子类不影响已经存在的类结构.
接口性:多态是超类通过方法签名,向子类提供一个公共接口,由子类来完善或者重写它来实现的.
灵活性:
简化性:
虚拟机实现多态的方法是动态绑定技术(dynamic binding),执行期间判断所引用对象的实际类型,根据实际类型调用对应的方法.如果你知道Hotspot中oop-klass模型的实现,对这个问题就了解比较深了。
面向对象的方法:
包括面向对象分析、设计和程序设计。
(1)对象:
指一组属性及这组属性上的专用操作的封装体。属性可以是一些数据,也可以是另一个对象。每个对象都由它自己的属性值,表示该对象的状态,用户只能看到对象封装界面上的信息,对象的内部实现对用户是隐蔽的。封装的目的是使对象的使用者和生产者分离,使对象的定义和实现分开,一个对象通常包括3部分,对象名、属性和操作(方法)。
(2)类:
一组具有相同属性和操作的对象的集合。一个类中的每个对象都是这个类的一个实例(instance)。通常把一个类和这个类的所有对象称为类及对象或对象类。一个类通常由3部分组成:类名、属性和方法。每一个类一般都有实例,没有实例的类称为抽象类。抽象类不能被实例化,抽象方法只需要声明,而不需要实现。抽象类的子类必须覆盖所有抽象方法后才能被实例化,否则这个子类还是抽象类。是否建立了丰富的类库是衡量一个面向对象程序设计语言成熟与否的重要标志之一。
(3)继承
在某个类的层次关联中不同的类共享属性和操作的一种机制。一个父类可以有多个子类。父类描述了这些子类的公共属性和操作,子类可以定义属于自己的属性和操作。一个子类只有唯一的父类,这种继承称为单一继承,一个子类如果有多个父类,则称为多重继承。对于两个类A和B,如果B类是A类的子类,则A类是B类的泛化。继承是面向对象方法区别于其他方法的一个核心思想。
(4)封装
面向对象系统中的封装单位是对象,对象之间只能通过接口进行信息交流,外部数据不能对对象中的数据随意访问,封装的优点:好的封装能减少耦合,类内部的实现可以自由改变,一个类有更清楚的接口。
(5)消息
消息是对象间通信的手段,一个对象通过向另一对象发送消息来请求其服务。一个消息通常包括接收对象名、调用的操作名和适当的参数,消息只需要告诉接收对象需要完成什么操作,单并不能指示接收者怎样完成操作,消息完全由接收者解释,接收者独立决定采用什么方法来完成所需操作。
(6)多态性
多态指同一个操作作用于不能的对象时,可以有不同的解释,并产生不同的结果,与多态性密切相关的一个概念就是动态绑定,传统的程序设计语言把过程调用与目标代码的连接放在程序运行前进行,称为静态绑定,动态绑定则把这种连接推迟到运行时才进行。在运行过程中,当一个对象发送消息请求服务时,要根据接收对象的具体情况将请求的操作与实现的方法连接,即动态绑定。
1. 封装
封装是对象和类概念的主要特性。封装就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏,对外部不可见。封装的主要作用在于对外隐藏内部实现细节,增强程序的安全性。属性就是将属性私有化,提供共有的方法访问私有属性。对于属性和方法的封装都是通过加private修饰符实现的,封装之后的属性和方法对象是不能直接访问的,必须通过setter和getter方法设置和取得,setter方法用于赋值,getter方法用于取值。类中的全部属性都必须封装。这里注意,“如果子类继承了父类,对于父类中进行封装的方法,子类仍然可以直接调用”这句话是错误的。
public class Person {
private String name;
private int age;
public void tell() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0 && age < 200) {
this.age = age;
}
}
}
对封装对象的使用:
public class Use {
public static void main(String[] args) {
Person per=new Person();
//per.name = "张三"; 错误,无法访问封装数据
//per.age = -30;
per.setName("张三");
per.setAge(-30);
per.tell();
}
}
2. 继承
继承可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。在某些OOP语言中,一个子类可以继承多个基类。但是在java语言中,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承的实现方式
1. 实现继承、接口继承和可视继承。实现继承是指使用基类的属性和方法而无需额外编码的能力;
2. 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
3. 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。
在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Man属于人类,Woman也属于人类,因此这两个类都可以继承Human类。但是 Leg 类却不能继承Human类,因为腿并不是一个人。
抽象类仅定义将由子类创建的一般属性和方法,OO(面向对象)开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。
父类中属性或方法的修饰符对于子类访问的影响:
父类 | 子类 |
public | 可以 |
protected | 可以 |
缺省 | 同包可以,不同包不可以 |
private | 不可以 |
3.多态
3.1 多态的定义:
多态性(polymorphisn)允许将父对象设置成为和一个或更多的他的子对象相等,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单来说就是允许将子类类型的指针赋值给父类类型的指针。多态需满足三个条件:有继承;有重写;有父类引用指向子类对象。最终多态体现为父类引用可以指向子类对象:父类类型 变量名 = new 子类类型()。
3.2 多态的三种表现形式
1. 普通类多态定义的格式:父类类型 变量名 = new 子类类型()。
class Father {
int num = 4;
}
class Son extends Father {
int num = 5;
}
//普通类多态形式
Father father = new Son();
2. 抽象类多态定义的格式
abstract class Father {
abstract void method();
}
class Son extends Father {
public void method() {
System.out.println("abstract");
}
}
//抽象类多态表现形式
Father father = new Son();
3. 接口多态定义的格式
interface Father {
public void method();
}
class Son implements Father{
public void method() {
System.out.println("implements")
}
}
//接口多态的表现形式
Father father = new Son();
3.3 多态的编译和运行
(1)成员变量:编译和运行都看左边。
(2)成员方法:编译看左边,运行看右边。
关于多态的转型:
向上转型 | 向下转型 | |
作用 | 子类对象赋值给父类对象引用 | 父类对象引用强制转换为子类对象引用。 |
使用格式 | 父类类型 变量名 = new 子类类型() | 子类类型 变量名 = (子类类型)父类类型 |
优点 | 隐藏了子类类型,提高代码的扩展性。 | 可以使用子类特有功能。 |
缺点 | 只能使用父类共性的内容,无法使用子类特有功能。 | 容易发生类型转换异常(ClassCastException) |
实现多态,有覆盖和重载两种方式。覆盖指子类重新定义父类的虚函数的做法。重载指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。其实,重载的概念并不属于“面向对象编程”,重载的实现是:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。在java中的某个类中,如果有两个方法名相同但是参数列表(个数,类型)不同的方法,就视为重载。
3.4 多态的作用:
封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用,多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。