java的面向对象的封装机制_java面向对象(封装-继承-多态)

框架图

521b1276d12558ad3a609ae88653d260.png

理解面向对象

面向对象是相对面向过程而言

面向对象和面向过程都是一种思想

面向过程强调的是功能行为

面向对象将功能封装进对象,强调具备了功能的对象。

面向对象是基于面向过程的。

面向对象的特点

是一种符合人们思考习惯的思想

可以将复杂的事情简单化

将程序员从执行者转换成了指挥者

完成需求时:

先要去找具有所需的功能的对象来用。

如果该对象不存在,那么创建一个具有所需功能的对象。

这样简化开发并提高复用。

面向对象开发,设计,特征

开发的过程:其实就是不断的创建对象,使用对象,指挥对象做事情。

设计的过程:其实就是在管理和维护对象之间的关系。

面向对象的特征:

封装

继承

多态

类与对象的关系

计算机语言是虚拟的,但描述的是现实中的事物,java中描述事物通过类的形式体现,类是具体事物的抽象,概念上的定义。对象即是该类事物实实在在存在的个体。

类与对象的关系好比汽车的设计图纸,参照这个设计图制造的汽车,具有颜色、轮胎等特征。图纸就是类,汽车就是堆内存中的实体对象。我们可以对某个汽车所改观,比如换颜色换轮胎,和其他汽车没有关系。

生活中描述事物无非就是描述事物的属性和行为。Java中用类class来描述事物也是如此:

属性:对应类中的成员变量。

行为:对应类中的成员函数。

定义类其实就是在定义类中的成员(成员变量和成员函数)。

匿名对象

匿名对象是对象的简化形式

对比如下:

1 Car c = newCar();2 c.color="red"

3 c.run();4

5

6 new Car().run();

匿名对象两种使用情况

当对对象方法仅进行一次调用的时,如果对一个对象进行多个成员调用,必须给这个对象起名。

匿名对象可以作为实际参数进行传递,函数调用完成后自动释放,没了引用指向,匿名对象在堆内存中成为垃圾被自动回收。

成员变量和局部变量

a.无论成员变量还是局部变量使用前都需要声明;

b. 局部变量使用前必须初始化;成员变量可以不用初始化,其每个类型的的成员变量都有一个初始值:byte、short、int、long类型初始值为 0;float、double类型初始值为0.0;char类型的初始'\u0000';boolean类型的初始值为false;

c.局 部变量没有访问权限修饰符,不能用public,private,protected来修饰。局部变量不能用static修饰,没有”静态局部变量“。局 部变量的作用域仅限于定义它的方法,在该方法的外部无法访问它;成员变量定义在类中,在整个类中都可以被访问。如果权限允许,还可以在类的外部使用成员变 量;

d.局部变量的生存周期与方法的执行期相同。当方法执行到定义局部变量的语句时,局部变量被创建,执行到它所在的作用域的最后一条语句时,局部变量被销毁;类的成员变量,如果是实例成员变量,它和对象的生存期相同。而静态成员变量的生存期是整个程序运行期;

e.在同一个方法中,不允许有同名的局部变量。在不同的方法中,可以有同名的局部变量,它们互不干涉。 局部变量可以和成员变量同名,且在使用时,局部变量具有更高的优先级。

局部变量代码示例

1 public classlocalVariable2 {3 public voidmethod_1()4 {5 int va = 0; //正确

6 public int pva; //错误,不能有访问权限

7 static int sa; //错误,不能是静态的

8 final int CONST = 10; //正确,可以是常量

9 double va =0.0; //错误,与前面的va同名

10 vb = 100.0; //错误,vb还未定义

11 doublevb;12 vb = 100.0; //正确,现在可以使用了

13 }14 public voidmethod_2()15 {16 va = 0; //错误,method_1()中的变量va在此不可用

17 int CONST = 100; //正确,它与method_1()中的CONST不同

18 }19 }

局部变量与成员变量同名示例

1 public classlocalVSmember2 {3 private int iVar = 100;4 public voidmethod_1()5 {6 int iVar; //正确可以与成员变量同名

7 iVar = 200; //这里访问的是局部变量

8 this.iVar = 300; //这里访问的是成员变量

9 }10 public voidmethod_2(){11 iVar = 400; //这里访问的是成员变量

12 }13 }14 //因为局部变量优先级高于成员变量,同一函数内调用,同名的局部变量会屏蔽掉成员变量。为了访问被屏蔽的成员变量,需要使用"this"关键字,它表示的是"本类对象"(所在函数所属对象)成员变量其实还是对象在调用

构造函数

对象一建立就会调用与之对应的构造函数,用于给对象进行初始化。当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数。当在类中自定义了构造函数后,默认的构造函数就没有了。

构造函数和一般函数在写法上不同,在运行上也有不同:

构造函数是在对象一建立就运行。给对象初始化;而一般方法是对象调用才执行,给是对象添加对象具备的功能。

一个对象建立,构造函数只运行一次;而一般方法可以被该对象调用多次。

什么时候定义构造函数呢?

当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容定义在构造函数中。

构造函数的特点:

函数名与类名相同

不用定义返回值类型(区别void)

不可以写return语句

多个构造函数是以重载的形式存在的

构造代码块

构造代码块和构造函数一样,也是为对象进行初始化用的。

共同点是在对象一建立的时候他们都在运行,区别在于构造代码块要优先于构造函数执行,同时,构造代码块是给所有对象进行统一的初始化,而构造函数则是给对应的对象进行初始化。

this关键字

this代本类对象的引用,也就是它所在函数所属对象的引用,简单说:哪个对象在调用this所在的函数,this就代表哪个对象。

this关键字的使用:

1.当成员变量和局部变量重名时,在方法中使用this时,表示的是该方法所在类中的成员变量。例如上面局部变量和成员变量同名的示例。

2.用于构造函数之间进行调用。注意:只能定义在构造函数的第一行,构造函数之间不允许相互调用,会形成死循环。

static关键字

static关键字用于修饰成员(成员变量和成员函数)。

被修饰后的成员具备以下特点:

随着类的加载而加载,消失而消失。

优先于对象存在

被所有对象所共享

可以直接被类名调用,格式为:类名.静态成员

使用注意

静态方法只能访问静态成员,非静态方法既可以访问静态也可以访问非静态。

因为静态优先于对象存在,所以静态方法中不可以写this,super关键字。

主函数是静态的

静态有利有弊

利处:对对象的共享数据进行单独空间的存储,节省空间。没有必要每一个对象中都存储一份。

可以直接被类名调用。

弊端:生命周期过长。

访问出现局限性。(静态虽好,只能访问静态)

什么使用静态?要从两方面下手:因为静态修饰的内容有成员变量和函数。

什么时候定义静态变量(类变量)呢?

当对象中出现共享数据时,该数据被静态所修饰。对象中的特有数据要定义成非静态存在于堆内存中。

什么时候定义静态函数呢?

当功能内部没有访问到非静态数据(没有操作对象的特有数据),那么该功能可以定义成静态的。

静态代码块

示例1

1 classStaticCode2 {3 static

4 {5 System.out.println("a");6 }7 }8 classStaticCodeDemo9 {10 static

11 {12 System.out.println("b");13 }14 public static voidmain(String[] args)15 {16

17 newStaticCode();18 new StaticCode();//随类加载只执行一次且优先于主函数执行

19 System.out.println("over");20 }21 static

22 {23 System.out.println("c");24 }25 }26 //运行结果27 //b c a over

示例2

1 classStaticCode2 {3 int num = 9;4 StaticCode()//无参数类型的构造函数

5 {6 System.out.println("b");7 }8 static//静态代码块------给类初始化

9 {10 System.out.println("a");11 }12

13 {14 System.out.println("c"+this.num);//构造代码块-------给对象初始化

15 }16

17 StaticCode(int x)//有参数类型的构造函数---------给对应对象初始化

18 {19 System.out.println("d");20 }21 public static voidshow()22 {23 System.out.println("show run");24 }25 }26

27 classStaticCodeDemo28 {29 static

30 {31 System.out.println("f");32 }33 public static voidmain(String[] args)34 {35 new StaticCode(4);36 }37

38 }39

40 //运行结果:f a c9 d

特点:随着类的加载而执行,只执行一次,优先于主函数执行。类似构造代码块。用于给类进行初始化。表示:一个类进入内存,不需要对象的情况下,需要先做什么事情,较少使用。

注意:可能不止一个。位置不固定,可能在末尾。新建对象和调用类方法都可以加载类,但是创建一个没有实体指向的空变量不会加载类,例如,StaticCode s = null;,因为没有指向、没有意义。只有用到了类中的内容,例如,构造函数等,类才会被加载。

执行顺序:加载类—》静态变量—》静态代码块—》主函数—》加载对象—》加载属性—》构造代码块—》构造函数

静态代码块内部只能放静态成员,构造代码块内部能放各种成员变量。

对象的初始化Person p = new Person(“zhangsan”,20);

该句话的执行步骤如下:

1.因为new用到了Person类,所以会先找到Person.class文件并加载到内存中,静态变量加载到方法区。同时,栈内存中分配空间给变量p。

2. 会执行该类中的静态代码块,如果有的话,同时给Person.class类进行初始化。

3. 在堆内存中开辟空间,分配内存地址。

4. 在堆内存中建立对象的特有属性(实例变量),并进行默认初始化。

5. 对属性进行显示初始化。

6. 对对象进行构造代码块初始化。

7. 对对象进行对应的构造函数初始化。

8. 将内存地址赋给栈内存中的p变量,p指向对象。

面向对象的特征

封装

封装:就是隐藏对象的属性和实现的细节,控制在程序中属性的读和写的访问级别,仅对外提供公共的访问方式。

好处:

•将变化隔离。

•便于使用。

•提高重用性。

•提高安全性。

封装原则:

•将不需要对外提供的内容都隐藏起来。

•把属性都隐藏,提供公共方法对其访问。

private(私有)关键字是一个权限修饰符。用于修饰成员(成员变量和成员函数),被私有化的成员只在本类中有效。private可以将成员变量私有化,对外提供对应的

set方法(返回值为void且有参数)和get方法(没有参数)对其进行访问,提高对数据访问的安全性。私有仅仅是封装的一种表现形式。

继承

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承单独的那个类即可。多个类可以称为子类,单独这个类称为父类或者超类。

通过extends 关键字让类与类之间产生继承关系。

写法:class SubDemo extends Demo{}

继承的出现提高了代码的复用性。

继承的出现让类与类之间产生了关系,提供了多态的前提。

子类可以直接访问父类中的非私有的属性和行为。定义继承要注意不能仅为了获取其他类的功能,简化代码而继承,必须是类与类之间有所属关系才可以继承(is a)。

使用继承体系中的功能:先查阅体系中父类的描述,因为父类中定义的是该体系中共性功能,通过了解共性功能就可以知道该体系的基本功能。具体调用时,要创建最子类的对象。因为有可能父类不能创建对象,如抽象类;而且创建子类对象可以使用更多的功能,包括基本功能和特有功能。总的说就是查阅父类功能,创建子类对

象使用功能。

Java语言中:java只支持单继承,不支持多继承。

因为多继承容易带来安全隐患:当多个父类中定义了相同功能,当功能内容不同时,子类对象不确定要运行哪一个。但是java保留这种机制。并用另一种体现形式来完成表示。多实现。

java支持多层继承。也就是一个继承体系。

继承出现后,子父类成员的特点:

类中成员:

1,变量。

如果子父类中出现非私有的同名成员变量时,子类要访问本类的变量用this,一般可以省略。子类要访问父类中的同名变量用super,不可以省略。父类private成员变量可以被继承但无法被访问。

2,函数。

当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容。如同父类的函数被覆盖一样。这种情况是函数的另一个特性:重写(覆盖)

当子类继承父类,沿袭了父类的功能,到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,这时,没有必要定义新功能,而是使用覆盖特殊,保留父类的功能定义,并重写功能内容。

子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。

静态只能覆盖静态。

注意区分:

重载:同一个类中,只看同名函数的参数列表。

重写:子父类方法要一模一样。(包括返回值类型)

3,构造函数。

子类不能覆盖父类构造函数,因为类名不一样。在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认第一行有一条隐式的语句super();

super()会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super();(只能写在第一行)

为什么子类一定要访问父类中的构造函数?

因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。所以子类在对象初始化时,必须要先访问一下父类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。

如果要访问父类中指定的构造函数,可以通过手动定义super显示语句的方式来指定。当然子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。

final关键字

1,可以修饰类,函数,变量。

2,被final修饰的类不可以被继承。为了避免被继承,被子类复写功能。

3,被final修饰的方法不可以被复写。

4,

被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,也可以修饰局部变量。当在描述事物时,一些数据的出现值是固定的,那么这时为了增强

阅读性,都给这些值起个名字。方便于阅读。而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成,

单词间通过_连接。

5,内部类定义在类中的局部位置上是,只能访问该局部被final修饰的局部变量。

抽象类

当多个类中出现相同功能,但是功能主体不同,这时可以进行向上抽取。这时,只抽取功能定义,而不抽取功能主体。例如void work() ,工人和程序员都需要工作,但是工作的内容不会相同。不抽取主体只抽取方法再通过方法的覆盖来实现多态的属性。是一种运行时绑定。

抽象类的特点:

1,抽象方法一定在抽象类中。抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。

2,抽象方法和抽象类都必须被abstract关键字修饰。

3,抽象类不可以用new创建对象。因为调用抽象方法没意义。

4,抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。

接口

接口是对外暴露的规则,是程序的功能扩展。

格式:

interface {}

接口中的成员修饰符是固定的:

成员常量:public static final----全局常量

成员函数:public abstract

接口可以理解为一个特殊的抽象类,当类中的方法都是抽象的,该类可以通过接口的形式来表示。接口中的方法都是没有方法体的,便于以后的覆盖。

类与接口之间是“实现”关系,implements。父类中有非抽象内容可以直接拿来用,子类只有将接口中的内容全部实现后才能实例化,否则是抽象类。接口

是不可以创建对象的,因为有抽象方法。覆盖接口中的方法必须用public,因为接口中的方法都是共有的,抽象类的权限不确定。

接口可以被类多实现。一个类可以同时现实多个接口。也是对多继承的不支持的转换形式。依然需要覆盖每个接口的方法。即使多个接口有相同名称的方法也没有问题,因为没有方法体,不会产生矛盾,子类可以全部覆盖。子类在继承父类的同时,还可以实现多个接口。

类之间是继承关系;类和接口之间是实现关系;接口之间是继承关系,接口之间可以多继承,但是不能有重载函数。

接口的使用思路:

子类继承父类的全部功能;但是,有的子类需要某些功能,有的子类不需要某些功能,可以将这些功能作为接口,需要的用,不需要的不用,防止不需要的子类也带上这些功能,而且其他的子类也可以使用这些接口;如果所有的子类都需要这些功能,但是具体的内容不同,可以使用抽象类,子类自己进行覆盖,或者使用一般类,

少部分的子类通过覆盖获得自己所需要的功能。

基本功能定义在类中,扩展功能定义在接口中。例如培训班的学员基本功能都要学习,扩展功能有部分学员需要抽烟。

抽象类和接口异同

相同:

1,都可以在内部定义抽象方法。

2,通常都在顶层。

3,都不可以实例化,都需要子类来实现。

不同:

1,抽象类中可以定义抽象方法和非抽象方法,而接口中只能定义抽象方法。

2,抽象类只能单继承。接口的出现可以多实现,也就是说接口的出现避免了单继承的局限性。

3,继承和实现的关系不一致。继承:is a,实现:like a

多态

多态可以理解为事物存在的多种体现形态。 比如动物的体现形态:猫、狗等。

猫这个对象对应的类型是猫类型

•猫 x = new 猫();

同时猫也是动物中的一种,也可以把猫称为动物。

•动物 y = new 猫();

动物是猫和狗具体事物中抽取出来的父类型。

父类型引用指向了子类对象,这就是多态的体现。

多态的前提必须是类与类之间有关系。要么继承,要么实现。通常还有一个前提:方法存在覆盖。

好处:大大提高了程序的扩展性,便于后期维护。

弊端:但是只能使用父类的引用访问父类的成员。

1 Animal a = new Cat();//类型提升。 向上转型。

2 a.eat();3

4 //如果想要调用猫的特有方法时,如何操作?强制将父类的引用转成子类类型。向下转型。

5 Cat c =(Cat)a;6 c.catchMouse();7 //千万不要出现这样的操作,就是将父类对象转成子类类型。8 //Animal a = new Animal();9 //Cat c = (Cat)a;错误的。10

11 //多态自始至终都是子类对象在做着变化。

12

13

自己写了个小代码加深下多态的理解

1 classPolymorphic2 {3 public static voidmain(String[] args)4 {5 Boss boss=newBoss();6 boss.command(newMDWorker());7 boss.command(newMTWorker());8 }9 }10 //父类员工类

11 abstract classWorker12 { String name;13 intage;14

15 abstract void salaried();//领薪水的方法

16 abstract void doProject();//做项目的方法

17

18 }19

20 //市场部员工子类

21 class MDWorker extendsWorker22 {23

24 public voidsalaried(){25 System.out.println("领3K薪水!");26 }27 public voiddoProject(){28 System.out.println("做市场调差项目!");29 }30 public voidreport(){31 System.out.println("特有功能写报告!");32 }33

34

35 }36 //技术部员工子类

37 class MTWorker extendsWorker38 { public voidsalaried(){39 System.out.println("领4K薪水!");40 }41 public voiddoProject(){42 System.out.println("做技术测试项目!");43 }44 public voidcoding(){45 System.out.println("特有功能写代码!");46 }47 }48 //老板类

49 classBoss50 {51

52 public void command(Worker w)//接收父类的引用

53 {54

55 w.doProject();56 w.salaried();57 //w.report();编译不通过。想调用子类特有功能必须向下转型。

58 if(w instanceofMDWorker)59 {60 MDWorker md = (MDWorker)w;//父类引用强转为市场部子类对象,调用写报告的特有方法。

61 md.report();62 }63 else if(w instanceofMTWorker)64 {65 MTWorker mt =(MTWorker)w;66 mt.coding();67 }68

69 }70 }

在多态中成员函数的特点:

在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有编译通过,如果没有编译失败。

在运行时期:参阅对象所属的类中是否有调用的方法。

简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。

在多态中,成员变量的特点:

无论编译和运行,都参考左边(引用型变量所属的类)。

在多态中,静态成员函数和静态成员函数的特点:

无论编译和运行,都参考左边(引用型变量所属的类)。

接口实现多态

1 实现 被使用2 类——--——>接口——--——>主程序3 将相似的类中的方法抽象出来放在接口。

4 主程序只需要使用接口的方法建立接口的引用,类只需实现了接口,有新类出现只要将接口的引用指向新类,无需改动主程序和接口,就降低了程序的耦合性。

Object类

Object类:是所有对象的直接或者间接父类,唯一没有父类的类,传说中的上帝。该类中定义的是所有对象都具备的功能。

注意:实际应用中一般都有复写object父类中的方法。

equals()方法

1 Object类中的equals()方法如下:2

3 public booleanequals(Object obj)4 {5 return (this ==obj);6 }

Object类中的equals()方法等价于==。只有当继承Object的类覆写了equals()方法之后,子类实现了用equals()方法比较两个对象是否相等,才可以说equals()方法与==的不同。

toString()

1 Object类中的toString()方法定义如下:2

3 publicString toString()4 {5 return getClass().getName() + "@" +Integer.toHexString(hashCode());6 }

覆写equals和toString例子

1 classCarDemo2 {3 public static voidmain(String[] args)4 {5 Car c1 = new Car("2013", "宝马");6 Car c2 = new Car("2013", "宝马");7 System.out.println(c1.equals(c2));8 System.out.println(c1);9 }10 }11 classCar {12 privateString year;13 privateString type;14 Car(String year, String type){15 this.year=year;16 this.type =type;17 }18 //复写equals()方法

19 public boolean equals(Object obj){ //如果比较双方指向同一个对象,则直接返回true。

20 if( this ==obj)21 return true;22 if(obj != null && getClass() == obj.getClass())//使用getClass方法来判断运行时对象是否是同类对象,还要防止对null的对象执行getClass操作。

23 {24 Car c = (Car)obj;//强转转换向下转型,才能访问子类中year和type。

25 if((this.year== c.year) && (this.type ==c.type))26 return true;27 }28 return false;29 }30 //复写toString()方法

31 publicString toString(){32 return ("这是"+year+"年生产的"+type+"汽车。");33 }34 }

运行结果

66a02b90b8c87a5fa893170ef26c1853.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值