java-面向对象编程
面向过程 & 面向对象
- 面向过程思想
- 步骤清晰简单,第一步做什么,第二步做什么……
- 面对这一过程适合处理一些较为简单的问题
- 面向对象思想
- 以分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些问题进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
- 适合处理复杂问题,处理一个问题需要多人的协作情况。
对于描述复杂问题,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理
什么是面向对象
本质:以类的方式组织代码,以对象的组织(封装)数据。
1. 面向对象
- 面向对象是相对面向过程而言
- 面向对象和面向过程都是一种思想
- 面向过程强调的是功能、行为
- 面向对象:将功能封装进对象,强调具备了功能的对象
- 面向对象是基于面向过程的
举例
面向过程:
把大象放进冰箱里分为以下步骤:把冰箱门打开;把大象放进去;关上冰箱门(强调过程和过程中所涉及的行为(强调行为、动作、过程))。
面向对象:
无论是打开冰箱,放进大象,关闭冰箱,所有操作都是操作冰箱这个对象,所以只需要将所有功能都定义在冰箱这个对象上,冰箱上就有打开、存储、关闭得所有功能 。
三大基本特征: 封装、继承、 多态。面向对象的过程就是找对象、建立对象、使用对象、维护对象的关系的过程。
2.类和对象的基本关系
类:是对现实生活中事物的描述。
对象:就是这类事物,实实在在存在的个体。
如现实生活中的对象:张三、李四。想要描述对象张三和李四,就需要提取对象中的共性内容(就是类,相当于是一个模板)。在描述时,这些对象的共性有:姓名、性别、年龄、学习,而每个学员又有自己独有的姓名、性别、年龄、学习方式。
在java中,描述是用类的方式实现,而类是通过new操作符所产生的实体来实现,而这个实体在堆内存中再映射到java中去。简单的说,描述就是class定义的类,具体对象就是对应java在堆内存中用new建立的实体。类是对象的模板。
创建与初始化对象
使用new关键字创建对象,java会分配内存空间,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
public class Test {
public static void main(String[] args) {
//实例化两个对象
Student student1 = new Student();
Student student2 = new Student();
//两个对象拥有相同的一个studen类模板,但是属性内容不一样
student1.name = "小明";
student1.age = 20;
student2.name = "小李";
student2.age = 19;
//执行study
student1.study();
student2.study();
}
//定义一个学生类
public static class Student {
//名字属性
String name;
//年龄属性
int age;
//学习的方法
public void study() {
System.out.println(this.name + "在学习。今年" + this.age + "岁");
}
}
}
1. 构造器
类中的构造器也称之为构造方法,是进行创建对象的时候必须要调用的。一个类即使什么都不写,它也会存在一个方法(构造方法)。
构造器特点:
- 必须和类的名字相同
- 必须没有返回值类型,也不能写void
构造器作用:
- 实例化对象初始值
- 使用new关键字创建对象,本质是在调用构造器
1.1 无参构造(默认构造器)
无参构造器是没有形式参数的,也叫默认构造器,它创建的是”默认对象“。
public class Test {
//没有指定构造器,Java编译器会自动生成默认构造
public static void main(String[] args) {
new Test();
}
}
public class Test {
//显示的定义了一个无参构造器
public Test(){ }
public static void main(String[] args) {
new Test();
}
}
new Test()创建了一个新对象,并调用了默认构造——虽然我们并没有主动定义它。Java规定了,如果没有构造会生成默认构造,如果存在了一个及以上的构造便不会自动生成。
1.2 有参构造
注意:一但定义了有参构造,无参构造就要显示定义(有参构造其实就是重载无参构造器)
public class Test {
String name1;
//显示定义无参构造
public Test() {
}
//定义有参构造器
public Test(String name2) {
this.name1 = name2;
}
}
封装
概念:将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的访问和操作。
目的:直接通过操控类对象来达到目的,不需要对具体实现十分了解,使类属性和方法的具体实现对外不可见。不但方便还起到了保护作用。
封装的优点:
-
良好的封装能够减少耦合。
-
类内部的结构可以自由修改。
-
可以对成员变量进行更精确的控制。
-
隐藏信息,实现细节。
-
提高程序的安全性,保护数据。
-
统一接口,可形成一种规范,便于维护。
(我们程序设计要追求“高内聚,低耦合”。高内聚:类的内部数据操作细节自己完成,不允许外部干涉。低耦合:仅暴露少量的方法给外部使用)
实现封装的方式:使用访问控制符
java提供了三种访问权限,准确的说还有一种是默认的访问权限,加上它一共四种。
- private:在当前类中可访问
- default:在当前包内和访问
- protected:在当前类和它派生的类中可访问
- public:公众的访问权限,谁都能访问
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 | 别名 |
---|---|---|---|---|---|---|
public | Y | Y | Y | Y | Y | 公有的 |
private | Y | N | N | N | N | 私有的 |
protected | Y | Y | Y | Y/N | N | |
default | Y | Y | Y | N | N |
实现Java封装的步骤
修改属性的可见性来限制对属性的访问(一般限制为private),例如:
public class Person {
private String name;
private int age;
}
这段代码中,将 name 和 age 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。
尽然对属性进行了隐藏,那怎么让外部可以访问呢?java提供了一些可以操作这个属性的方法:get/set
- get:获得这个数据
- set:给这个数据设置值
public class Person{
private String name; //设置私有属性name
//获取name属性值
public String getName(){
return name;
}
//设置age属性值
public void setName(String name){
this.name = name;
}
}
IDEA快捷键使用:ALT + insert 。选择Getter and Setter,会自动生成该类属性get方法和set方法。
继承
什么是继承
继承是类与类之间的关系,是一个很直观的概念,与现实世界中的继承(例如儿子继承父亲财产)类似。
继承可以理解为一个类从另一个类获取方法和属性的过程。如果类B(儿子)继承于类A(父亲),那么B就拥有A的方法和属性。子类不可以直接访问父类中的私有的属性和行为。
一个为子类(派生类),一个为父类(基类),继承使用 extends 关键字。
class Student extends Person{} //Student是子类(派生类),Person是父类(基类)。
继承优点
- 提高代码的复用性。
- 让类与类之间产生了关系,是多态的前提。
java特点:
- JAVA中类只有单继承,没有多继承。(一个儿子只能有一个爸爸,一个爸爸可以有多个儿子)
//一个类只能有一个父类,不可以有多个父类。
class SubDemo extends Demo{} //正确
class SubDemo extends Demo1,Demo2...//错误
- Java支持多层(重)继承(继承体系)。(孙子可以共同继承爸爸和爷爷的属性)
class A{}
class B extends A{}
class C extends B{}
//A是爷爷,B是爸爸,C是孙子,爸爸继承了爷爷的家产,儿子继承了爸爸同时包括爷爷的家产。
使用继承时的注意事项:
- 如果类之间存在着:is a 的关系,就可以考虑使用继承。
- 不要为了继承部分功能,而去使用继承。
super和this有什么区别?
super是一个关键字,代表父类的存储空间标识。(可以理解为父亲的引用)
super和this的用法相似。
this代表对象的引用(谁调用就代表谁);
super代表当前子类对父类的引用。
使用场景
- 当子父类出现同名成员时,可以用super进行区分;
- 子类要调用父类构造函数时,可以使用super语句;
//Person父类
public class Person {
protected String name = "父亲"; //受保护的属性name
private int age; //私有属性age
public void print() {
System.out.println("我是父亲");
}
}
//Student子类
class Student extends Person {
private String name = "儿子";
public void print() {
System.out.println("我是儿子");
}
public void test() {
System.out.println(this.name); //调用自身的name属性
this.print(); //调用自身的方法
System.out.println(super.name); //调用父类的name属性
super.print(); //调用父类的方法
super.age; //错误,无法调用父类的私有(private)属性。
}
}
多态
什么是多态?
- 多态是同一个行为具有多个不同表现形式或形态的能力。
- 多态就是同一个接口,使用不同的实例而执行不同操作
多态性是对象多种表现形式的体现。
现实中,比如我们按下 F1 键这个动作:
- 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
- 如果当前在 Word 下弹出的就是 Word 帮助;
- 在 Windows 下弹出的就是 Windows 帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。
//人 父类
class Person {
public void run() {
}
}
//学生 子类
class Student extends Person {
public void run() {
System.out.println("学生在学习");
}
}
//老师 子类
class Teacher extends Person {
public void run() {
System.out.println("老师在上课");
}
}
学生和老师都继承了Person类,且都重写了Person父类的run方法,学生类和老师类的run方法具有不同的表现形态,这就是多态。
多态注意事项:
- 多态是方法的多态,属性没有多态。
- 父类和子类有联系(人和老师有联系)
- 存在条件:
- 继承关系
- 方法需要重写
- 父类引用指向子类对象。Father f1 = new Son();
抽象类
在Java中,不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类,抽象类用 abstract 关键字定义。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。
//抽象类
public abstract class Test {
//构造函数
public Test() {
}
//普通方法
public void A(){
}
//abstract定义的抽象方法:没有方法体,只有方法名。
public abstract void B();
}
//继承Test类
class A extends Test{
//重写抽象类Test的抽象方法B
public void B() {
System.out.println("B");
}
}
总结:
- 抽象类不能被实例化,必须要创建子类,继承抽象类,重写里面的抽象方法,然后创建子类对象来使用。
- 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
- 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
- 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
- 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。