面向对象

来源:互联网 发布:小米聊天软件 编辑:程序博客网 时间:2024/06/13 00:58

 

面向对象

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

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

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

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

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

特点:1:是一种符合人们思考习惯的思想。

2:可以将复杂的事情简单化。

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

完成需求时:

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

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

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

 

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

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

过程和对象在我们的程序中是如何体现的呢?过程其实就是函数;对象是将函数等一些内容进行了封装。

 

其实定义类,就是在定义成员变量和成员函数。但是在定义前,必须先要对事物进行属性和行为的分析,才可以用代码来体现。在类中定义的成员变量和成员函数都称之为成员。成员有两种

1:成员变量:其实对应的就是事物的属性。

2:成员函数:其实对应的就是事物的行为。

 

成员变量和局部变量的区别:

成员变量:类变量

1.  成员变量定义在类中,在整个类中都可以被访问。成员变量在这个类中有效

2.  成员变量随着对象的建立而建立,存在于对象所在的堆内存中。

3.  成员变量有默认初始化值。Int默认值0    double默认值0.0   boolean 默认值 false   char  默认值 ‘\u0000’(空格) Streing默认值 null  

局部变量:实例变量

1.  局部变量只定义在局部范围内,如:函数内,语句内等

2.  局部变量存在于栈内存中。执行指令退出哪个局部,局部变量自动清除

3.  作用的范围结束,变量空间会自动释放。

4.  局部变量没有默认初始化值。(编译会出错)

 

成员变量 不初始化也能参与运算 因为他在堆内存中 都有默认值

局部变量 不初始化不可能参与运算编译出错,因为他在栈内存中必须要有初始化值以后才能参与运算

 

允许在本类中创建本类对象(单例模式)

 

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

匿名对象两种使用情况

l  当对对象方法仅进行一次调用的时

l  可以作为实际参数进行传递

封装是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

 好处

1.  将变化隔离。

2.  便于使用。

3.  提高重用性。

4.  提高安全性。

封装原则:

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

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

 

private int age;//私有的访问权限最低,只有在本类中的访问有效。

被私有化的成员只在本类中有效。Private

将成员变量私有化,对外提供对应的set ,get方法对其进行访问。提高对数据访问的安全性。一个私有化属性对应两个方法空类型set*(数据类型形参);还有数据类型get*();

注意:私有仅仅是封装的一中形式

 

私有的成员:其他类不能直接创建对象访问,所以只有通过本类对外提供具体的访问方式来完成对私有的访问,可以通过对外提供函数的形式对其进行访问。

好处:可以在函数中加入逻辑判断等操作,对数据进行判断等操作。

总结:开发时,记住,属性是用于存储数据的,直接被访问,容易出现安全隐患,所以,类中的属性通常被私有化,并对外提供公共的访问方法。

这个方法一般有两个,规范写法:对于属性 xxx,可以使用setXXX(),getXXX()对其进行操作。


构造函数用于给对象进行初始化,是给与之对应的对象进行初始化,它具有针对性,函数中的一种。

特点:

1该函数的名称和所在类的名称相同。

2不需要定义返回值类型。定义了返回值类型就不再是构造函数了

3不可以写return语句。

4:对象一建立就被会调用

作用:

给对象进行初始化。初始化属性变量

注意:

默认构造函数的特点。一个类在定义时,如果没有定义过构造函数,那么该类中会自动生成一个空参数的构造函数,为了方便该类创建对象,完成初始化。如果在类中自定义了构造函数,那么默认的空参数构造函数就没有了。

一个类中,可以有多个构造函数,多个构造函数是以重载的形式存在的。

构造函数允许私有化  允许重载

 

构造函数和一般函数有什么区别呢?

1两个函数定义格式不同。

2构造函数是在对象创建时,就被调用,用于初始化,而且初始化动作只执行一次。

    一般函数,是对象创建后,需要调用才执行,可以被调用多次。

  

什么时候使用构造函数呢?

分析事物时,发现具体事物一出现,就具备了一些特征,那就将这些特征定义到构造函数内。

 

构造代码块

    构造代码块中定义的是不同对象共性的初始化内容

作用:给对象进行初始化,对象一建立就运行,而且优于构造函数执行

   

构造代码块和构造函数有什么区别?

构造代码块:是给所有的对象进行初始化,也就是说,所有的对象都会调用一个代码块。只要对象一建立。就会调用这个代码块。

构造函数:是给与之对应的对象进行初始化。它具有针对性。

 

this关键字

特点:this代表其所在函数所属对象的引用。

换言之:this代本类对象的引用。

什么时候使用this关键字呢?

当在函数内需要用到调用该函数的对象时,就用this。

简单的说:哪个对象在调用this所在的函数,this就代表哪个对象

 

this的应用:当定义类中功能时,该函数内部要用到调用该函数对象时,这时用this来表示这个对象,但凡本类功能内部使用了本类对象,都用this表示

 

静态方法中不可以写this

this 还可以用于构造函数间的调用。

调用格式:this(实际参数);

this对象后面跟上 .  调用的是成员属性和成员方法(一般方法);

this对象后面跟上 () 调用的是本类中的对应参数的构造函数。

 

注意:用this调用构造函数,必须定义在构造函数的第一行。因为构造函数是用于初始化的,所以初始化动作一定要执行。否则编译失败。


构造函数建立几个对象就被调用几次 可以定义一个静态整型变量在构造函数函数中自加可用于记录建立对象的个数

 

Person p = new Person();

创建一个对象都在内存中做了什么事情?

1先将硬盘上指定位置的Person.class文件加载进内存。

2执行main方法时,在栈内存中开辟了main方法的空间(压栈-进栈),然后在main方法的栈区分配了一个变量p。

3在堆内存中开辟一个实体空间,分配了一个内存首地址值。

4在该实体空间中进行属性的空间分配,并进行了默认初始化。

5对空间中的属性进行显示初始化。

6进行实体的构造代码块初始化。

7调用该实体对应的构造函数,进行构造函数初始化。()

8将首地址赋值给p ,p变量就引用了该实体。(指向了该对象)

--------------------------------------------------------------------------------------------

 

(面向对象特征之一)是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

好处:将变化隔离;便于使用;提高重用性;安全性。

封装原则:将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共方法对其访问。

static关键字,是一个修饰符,用于修饰成员(成员变量和成员函数)。

特点:

1.  随着类的加载而加载

2.  优先于对象存在

3.  被所有对象所共享

4.  可以直接被类名调用

使用注意

1.  静态方法只能访问静态成员,

非静态方法中既可以访问静态成员,也可以访问非静态成员

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

3.  主函数是静态的   静态函数调用静态函数

 

静态有利有弊

利处:对对象共享的数据进行单独空间的存储,节省空间,没有必要每一个对象中都存储一份,可以直接被类名调用

弊端:

1,有些数据是对象特有的数据,是不可以被静态修饰的。因为那样的话,特有数据会变成对象的共享数据。这样对事物的描述就出了问题。所以,在定义静态时,必须要明确,这个数据是否是被对象所共享的。

2,静态方法只能访问静态成员,不可以访问非静态成员。

3,静态方法中不能使用thissuper关键字。

4,生命周期过长。

 

什么时候定义静态成员呢?或者说:定义成员时,到底需不需要被静态修饰呢?

成员分两种:

1,成员变量。数据共享时静态化

该成员变量的数据是否是所有对象都一样:

如果是,那么该变量需要被静态修饰,因为是共享的数据。

如果不是,那么就说这是对象的特有数据,要存储到对象中。

2,成员函数。方法中没有调用特有数据时就定义成静态

    如果判断成员函数是否需要被静态修饰呢?

    只要参考,该函数内是否访问了对象中的特有数据:

    如果有访问特有数据,那方法不能被静态修饰。

    如果没有访问过特有数据,那么这个方法需要被静态修饰。


成员变量(实例变量)和静态变量(类变量)的区别:

1,成员变量所属于对象。所以也称为实例变量。

静态变量所属于类。所以也称为类变量。

2,成员变量随着对象创建而存在。存在于堆内存中。随着对象被回收而消失。

静态变量随着类的加载而存在。存在于方法区中。随着类的消失而消失。

3,成员变量只能被对象所调用 。

静态变量可以被对象调用,也可以被类名调用。

成员变量可以称为对象的特有数据,静态变量称为对象的共享数据。

静态类变量

实例变量

如果其中一个对象改变了类变量的值,其他对象得到的就是改变后的结果

所有对象共用同一个静态类变量

如果某一个对象改变了实例变量的值,不影响其他对象

每个对象都有自己的实例变量

 

静态允许继承允许重载

 

 

静态代码块:就是一个有静态关键字标示的一个代码块区域。定义在类中。

作用:可以完成类的初始化。静态代码块随着类的加载而执行,而且只执行一次(new 多个对象就只执行一次)。如果和主函数在同一类中,优先于主函数执行。

 

构造函数    给对应对象初始化在对象建立的时候执行

构造代码块  给所有对象初始化 在对象建立的时候执行  建立几个对象执行几次

静态代码块  给类初始化  随着类的加载而执行  只执行一次

静态代码块、构造代码块、构造函数同时存在时的执行顺序:静态代码块à构造代码块à构造函数;

 

类中怎么没有定义主函数呢?publicstatic void main(String[] args)

注意:主函数的存在,仅为该类是否需要独立运行,如果不需要,主函数是不用定义的。

主函数的解释:保证所在类的独立运行,是程序的入口,被jvm调用。

Public:访问权限最大。

static:不需要对象,直接类名即可。

void:主函数没有返回值。

Main:主函数特定的名称。

(String[] args):主函数的参数,是一个字符串数组类型的参数,jvm调用main方法时,传递的实际参数是 new String[0]。

 

jvm默认传递的是长度为0的字符串数组,我们在运行该类时,也可以指定具体的参数进行传递。可以在控制台,运行该类时,在后面加入参数。参数之间通过空格隔开。jvm会自动将这些字符串参数作为args数组中的元素,进行存储。

 

生成Java帮助文档:命令格式:javadoc –d 文件夹名 –auther–version *.java

/**     //格式

*类描述

*@author 作者名

*@version 版本号

*/

/**

*方法描述

*@param  参数描述

*@return  返回值描述

*/

-----------------------------------------------------------------------------------------

设计模式:解决问题最行之有效的思想。是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

java中有23种设计模式:

单例设计模式

解决的问题:保证一个类在内存中的对象唯一性。

比如:多程序读取一个配置文件时,建议配置文件封装成对象。会方便操作其中数据,又要保证多个程序读到的是同一个配置文件对象,就需要该配置文件对象在内存中是唯一的。

Runtime()方法就是单例设计模式进行设计的。

如何保证对象唯一性呢?

思想:

1,不让其他程序创建该类对象。私有化构造函数

2,在本类中创建一个本类对象。在类中创建一个本类对象静态并私有化该对象

3,对外提供方法,让其他程序获取这个对象。static修饰该方法必须是静态方法

代码体现:

1,私有化构造函数,

2,创建私有并静态的本类对象;

3,定义公有并静态的方法,返回该对象

---------------------------------------------//饿汉式class Single{private Single(){} //私有化构造函数。private static Single s = new Single(); //创建私有并静态的本类对象。public static Single getInstance(){ //定义公有并静态的方法,返回该对象。return s;}}---------------------------------------------//懒汉式:延迟加载方式。class Single2{private Single2(){}private static Single2 s = null;public static Single2 getInstance(){if(s==null)s = new Single2();return s;}}

(面向对象特征之一)通过 extends关键字让类与类之间产生继承关系。子类可以直接访问父类中的非私有的属性和行为。

好处:

1:提高了代码的复用性。

2:让类与类之间产生了关系,提供了另一个特征多态的前提。

 

父类的由来:其实是由多个类不断向上抽取共性内容而来的。

java中对于继承,java只支持单继承。

单继承:一个类只能有一个父类。

多层继承:A继承B,B继承C。C继承D。

final修饰的类不许被 构造方法是不能被继承的

 

为什么不支持多继承呢?

因为当一个类同时继承两个父类时,两个父类中有相同的功能,那么子类对象调用该功能时,运行哪一个呢?因为父类中的方法中存在方法体。

多重继承的出现,就有了继承体系。体系中的顶层父类是通过不断向上抽取而来的。它里面定义的该体系最基本最共性内容的功能。

所以,一个体系要想被使用,直接查阅该系统中的父类的功能即可知道该体系的基本用法。那么想要使用一个体系时,需要建立对象。建议建立最子类对象,因为最子类不仅可以使用父类中的功能。还可以使用子类特有的一些功能。

 

简单说:对于一个继承体系的使用,查阅顶层父类中的内容,创建最底层子类的对象。

 

super

l  super和this的用法相像

l  this代表本类对象的引用

l  super代表父类的内存空间的标识。

l  当子父类出现同名成员时,可以用super进行区分

子类要调用父类构造函数时,可以使用super语句


子父类出现后,类中的成员都有了哪些特点:

1:成员变量。

     当子父类中出现一样的属性时,子类类型的对象,调用该属性,值是子类的属性值。

     如果想要调用父类中的属性值,需要使用一个关键字:super

     This代表是本类类型的对象引用。

     Super代表是子类所属的父类中的内存空间引用。

     注意:子父类中通常是不会出现同名成员变量的,因为父类中只要定义了,子类就不用在定义了,直接继承过来用就可以了。

2:成员函数。

当子父类中出现了一模一样的方法时,建立子类对象会运行子类中的方法。好像父类中的方法被覆盖掉一样。所以这种情况,是函数的另一个特性:覆盖(复写,重写) 子类继承父类 同名成员变量之间不存在覆盖 只有同名函数间满足条件时存在覆盖

什么时候使用覆盖呢?当一个类的功能内容需要修改时,可以通过覆盖来实现。

函数覆盖(Ovewride)

1.        子类中出现与父类一模一样方法时,会出现覆盖操作,也称为重写或者复写。但是父类的方法还在内存中

2.        父类中的私有方法不可以被重写   变量不存在重写那叫重新赋值  final修饰的方法不可以被重写子类中出现与父类一模一样方法时,会出现覆盖操作,也称为重写或者复写。但是父类的方法还在内存中

3.        在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取。

Ø  覆盖注意事项:                 继承之后才存在覆盖

覆盖时,子类方法权限一定要大于等于父类方法权限

静态只能覆盖静态。

覆盖的应用:

当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。

父类引用指向子类对象(多态):编译看左边,运行看右边

子类的实例化过程

l  子类中所有的构造函数默认都会访问父类中空参数的构造函数,因为每一个构造函数的第一行都有一条默认的语句super();

l  子类会具备父类中的数据,所以要先明确父类是如何对这些数据初始化的。

当父类中没有空参数的构造函数时,子类的构造函数必须通过super(参数)语句访问指定的构造函数   子类至少有一个构造函数会通过super语句访问父类构造函数 当父类的构造函数为空时 子类中的super();语句可以隐藏 但是有一定有super

 

为什么子类对象初始化时,都需要调用父类中的函数?(为什么要在子类构造函数的第一行加入这个super()?)

因为子类继承父类,会继承到父类中的数据,所以必须要看父类是如何对自己的数据进行初始化的。所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程

父类中也有隐藏super();父类的父类是object

This()和super()不可以共存


super()和this()为什么不可以同时出现的构造函数中。

两个语句只能有一个定义在第一行,所以只能出现其中一个。

super()或者this():为什么一定要定义在第一行?

因为super()或者this()都是调用构造函数,构造函数用于初始化,所以初始化的动作要先完成。

 

什么时候使用继承呢?

当类与类之间存在着所属关系时,才具备了继承的前提。a是b中的一种。a继承b。狼是犬科中的一种。

英文书中,所属关系:" is a "

注意:不要仅仅为了获取其他类中的已有成员进行继承。

 

继承的一个弊端:打破了封装性。对于一些类,或者类中功能,是需要被继承,或者复写的。

这时如何解决问题呢?  一个关键字,final:最终。

final关键字  可以理解为最终最终类最终方法 最终变量 最终即不可改变

final特点:

1:这个关键字是一个修饰符,可以修饰类,方法,变量。

2:被final修饰的类是一个最终类,不可以被继承。

3:被final修饰的方法是一个最终方法,不可以被覆盖。

4:被final修饰的变量是一个常量,只能赋值一次。

5: 内部类在局部位置上(函数内定义的内部类)时只能访问被final修饰的局部变量

 

抽象类:abstract

抽象:不具体,看不明白。抽象类表象体现。

在不断抽取过程中,将共性内容中的方法声明抽取,但是方法不一样,没有抽取,这时抽取到的方法,并不具体,需要被指定关键字abstract所标示,声明为抽象方法。

抽象类:

Java没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。 抽象方法不能有方法体但必须以分号结束static不能与abstract一起修饰一个方法   staticabstractic不可以共存

 

抽象方法所在类一定要标示为抽象类,也就是说该类需要被abstract关键字所修饰。

抽象方法的由来:

多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。

例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。

抽象类的特点:

1:抽象方法只能定义在抽象类中,抽象类和抽象方法必须由abstract关键字修饰(可以描述类和方法,不可以描述变量)。

2:抽象方法只定义方法声明,并不定义方法实现。

3:抽象类不可以被创建对象(实例化)

4:只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。

 

抽象类的细节:

1:抽象类中是否有构造函数?有,用于给子类对象进行初始化。

2:抽象类中是否可以定义非抽象方法?

    可以。其实,抽象类和一般类没有太大的区别,都是在描述事物,只不过抽象类在描述事物时,有些功能不具体。所以抽象类和一般类在定义上,都是需要定义属性和行为的。只不过,比一般类多了一个抽象函数。而且比一般类少了一个创建对象的部分。

3:抽象关键字abstract和哪些不可以共存?final , private, static

4:抽象类中可不可以不定义抽象方法?可以。抽象方法目的仅仅为了不让该类创建对象。

 

比较:静态与抽象

静态方法只能调用静态方法  静态方法内可以有非静态变量  非静态方法可以访问静态和非静态成员

有抽象方法的一定是抽象类    调用静态方法的可以是静态方法 也可以是非静态方法

 

-------------------------------------------------------------------------------

模板方法设计模式:

解决的问题:当功能内部一部分实现时确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。

abstract class GetTime{    public final void getTime(){ //此功能如果不需要复写,可加final限定        long start = System.currentTimeMillis();        code(); //不确定的功能部分,提取出来,通过抽象方法实现        long end = System.currentTimeMillis();        System.out.println("毫秒是:"+(end-start));    }    publicabstract voidcode(); //抽象不确定的功能,让子类复写实现}class SubDemo extends GetTime{    public void code(){ //子类复写功能方法        for(int y=0; y<1000; y++){            System.out.println("y");        }    }}

-----------------------------------------------------------------------------

 接口的出现将“多继承”通过另一种形式体现出来,即“多实现”。

1:是用关键字interface定义的。

2:接口中包含的成员,最常见的有全局常量、抽象方法。

注意:接口中的成员都有固定的修饰符。

    成员变量:public static final

    成员方法:public abstract

interface Inter{

    public static final int x = 3;

    public abstract void show();

}

3:接口中有抽象方法,说明接口不可以实例化接口的子类必须实现了接口中所有的抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。

4:类与类之间存在着继承关系,类与接口中间存在的是实现关系。

    继承用extends ;实现用implements

5:接口和类不一样的地方,就是,接口可以被多实现,这就是多继承改良后的结果。java将多继承机制通过多现实来体现。

6:一个类在继承另一个类的同时,还可以实现多个接口。所以接口的出现避免了单继承的局限性。还可以将类进行功能的扩展。

7:其实java中是有多继承的。接口与接口之间存在着继承关系,接口可以多继承接口

 

接口都用于设计上,设计上的特点:

1接口是对外暴露的规则

2接口是程序的功能扩展

3接口的出现降低耦合性

4接口可以用来多实现

 

类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。

接口与接口之间可以有继承关系。

 

抽象类与接口:

抽象类:一般用于描述一个体系单元,将一组共性内容进行抽取,特点:可以在类中定义抽象内容让子类实现,可以定义非抽象内容让子类直接使用。它里面定义的都是一些体系中的基本内容。

接口:一般用于定义对象的扩展功能,是在继承之外还需这个对象具备的一些功能。

 

抽象类和接口的共性:都是不断向上抽取的结果。


在开发之前,先定义规则,A和B分别开发,A负责实现这个规则,B负责使用这个规则。至于A是如何对规则具体实现的,B是不需要知道的。这样这个接口的出现就降低了A和B直接耦合性。

关于方法重载要注意三点:

1.  不要忽略参数次序不同,次序不同也构成方法重载

2.  仅方法返回值不同,不构成方法重载

3.  构造方法重载是方法重载的最常见的形式


方法重写和方法重载的区别:

方法重写:override,子类重写了从父类继承过来的方法

方法重载:overLoad,方法名字相同,参数的个数,类型,次序不同。返回值类型要相同

相同点:都是多态性的表现,方法重写属于一种动态的多态性,方法重载属于静态多态性

不同点:方法重写有继承,方法重载无继承


重写方法的规则:Overrdie

1、参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载。

2、返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载。

3、访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)

4、重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。例如:父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。

 

而重载的规则:Overwrite

1、必须具有不同的参数列表;

  如果参数个数不同,就不管它的参数类型了!
      如果参数个数相同,那么参数的类型或者参数的顺序必须不同。

2、可以有不同的返回类型,只要参数列表不同就可以了;

3、可以有不同的访问修饰符;

      可以大于原来的访问权限,也可以小于原来的权限。

4、可以抛出不同的异常;

==================================================================

(面向对象特征之一):就是同一种行为在不同子对象上有不同的表现形式。

体现:父类引用或者接口的引用指向了自己的子类对象。//Animal a = new Cat();

多态的好处:多态的存在提高了程序的扩展性和后期可维护性。

多态的弊端:当父类引用指向子类对象时,虽然提高了扩展性,但是只能访问父类中具备的方法,不可以访问子类中特有的方法。(前期不能使用后期产生的功能,即访问的局限性)

多态的前提:

    1:必须要有关系,比如继承、或者实现。

    2:通常会有覆盖操作。

    3:父类引用指向子类对象

 

多态的出现思想上也做着变化:以前是创建对象并指挥对象做事情。有了多态以后,我们可以找到对象的共性类型,直接操作共性类型做事情即可,这样可以指挥一批对象做事情,即通过操作父类或接口实现。


如果想用子类对象的特有方法,如何判断对象是哪个具体的子类类型呢?

可以可以通过一个关键字 instanceof;//判断对象是否实现了指定的接口或继承了指定的类

 

格式:<对象 instanceof类型> ,判断一个对象是否所属于指定的类型。

Student instanceof Person = true;//student继承了person类

 

多态在子父类中的成员上的体现的特点:(当调用成员变量或方法时需要检查)

1,成员变量:在多态中,子父类成员变量同名。

    在编译时期:参考的是引用型变量所属的类中是否有调用的成员。(编译时不产生对象,只检查语法错误

    运行时期:也是参考引用型变量所属的类中是否有调用的成员。

    简单一句话:无论编译和运行,成员变量参考的都是引用变量所属的类中的成员变量。

    再说的更容易记忆一些:成员变量---编译运行都看左边

2,成员函数。

    编译时期:要查看引用变量(左边)所属的类中是否有所调用的成员函数。

    运行事情:要查看对象(右边)所属的类中是否有所调用的成员函数

    为什么是这样的呢?因为在子父类中,对于一模一样的成员函数,有一个特性:覆盖。

    简单一句:成员函数,编译看引用型变量所属的类,运行看对象所属的类。

    更简单:成员函数---编译看左边,运行看右边

3,静态函数。

    编译时期:参考的是引用型变量所属的类中是否有调用的成员。

    运行时期:也是参考引用型变量所属的类中是否有调用的成员。

    为什么是这样的呢?因为静态方法,其实不所属于对象,而是所属于该方法所在的类。

    调用静态的方法引用是哪个类的引用调用的就是哪个类中的静态方法。

    简单说:静态函数---编译运行都看左边

多态的一般程序

1.        父类引用指向子类 (对象还是父类不是子类但是可以向下转型为子类

2.        以父类形参 接收 对象   函数调用

3.        接收后 向下转型 使用子类特有功能


内部类    成员内部类 局部内部类

将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。

内部类的访问特点

l  内部类可以直接访问外部类中的成员,包括私有成员。       之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式  外部类名.this

内部类Inner访问外部类的非静态同名成员   格式为 Outer.this.a 或者newOuter().a

而外部类要访问内部类中的成员必须要建立内部类的对象。才可以(外部类.内部类变量 = new外部类().内部类()

-----------------------------------------------------

当内部类定义在外部类中的成员位置上,可以使用一些成员修饰符修饰 private、static。

1:私有修饰符。

  通常内部类被封装,都会被私有化,因为封装性不让其他程序直接访问。

2:静态修饰符。

  如果内部类被静态修饰,相当于外部类,会出现访问局限性,只能访问外部类中的静态成员。

  注意;如果内部类中定义了静态成员,那么该内部类必须是静态的。

静态内部类只可以访问外部类的静态成员  非静态内部类可以直接访问外部类的任何成员

静态还是非静态访问外部类的同名成员需要通过建立对象来访问或者通过外部类名访问外部静态同名成员

 

内部类编译后的文件名为:“外部类名$内部类名.class”;

 

为什么内部类可以直接访问外部类中的成员呢?

那是因为内部中都持有一个外部类的引用。这个是引用是 外部类名.this

内部类可以定义在外部类中的成员位置上,也可以定义在外部类中的局部位置上。

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

访问格式

1,当内部类定义在外部类的成员位置上,而且非私有。 在外部其他类中可以直接建立内部类对象来访问

格式    外部类名.内部类名  变量名= 外部类对象.内部类对象;

         Outer.Inner in = new Outer().new Inner();

 2,当内部类在成员位置上,就可以被成员修饰符所修饰。

        比如private :将内部类在外部类中封装

            static:修饰的内部类就具备static的特性

    当内部类被static修饰后,只能访问外部类中的static成员,出现了访问局限;

在外部其他类中,如何直接访问static内部类的非静态成员呢??

newOuter.Inner().function();

在外部其他类中,如何直接访问static内部类的静态成员呢??

Outer.Inner.function();

注意:当内部类中定义了静态成员,该内部类必须是static的;

 当外部类中的静态方法访问内部类时,内部类也必须是static的

 

内部类定义在局部位置上 只在定义它的方法内部有效只能用默认的权限符修饰

内部类定义在局部时的特点:

1,不可以被成员修饰符修饰只能用默认的权限符修饰

2,可以直接访问外部类中的成员,因为还持有外部类中的引用。

但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。

 

 Static静态是用来修饰成员变量或函数的无法修饰局部变量

 

匿名内部类

前提:

内部类必须继承或实现一个外部类或者接口。不需要重复使用只用一次

格式为:

new 外部类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容。)}

简单理解:匿名内部类其实就是匿名外部类的子类对象可理解为带内容的子类对象

就是建立一个带内容的外部类或者接口的子类匿名对象。

匿名内部类可以用父类引用或者接口引用来建立一个对象但此对象没有子类的特有功能

                    注意区别于多态的父类引用指向子类对象

匿名内部类的特点:

1,匿名内部类其实就是内部类的简写格式

2,定义匿名内部类的前提:

内部类必须是继承一个类或者实现接口。

3,匿名内部类的格式:new 父类或者接口(){定义子类的内容}

4,其实匿名内部类就是一个匿名子类对象,而且这个对象有点胖,可以理解为带内容的对象;

5,匿名内部类中定义的方法最好不要超过3个

Test.function().method();

可以读出: Test.function()说明function()是一个静态方法

.method()说明function()返回的是一个对象,而且是一个Inner类型的对象,因为只有是Inner类型的对象才可以调用method()方法。

匿名内部类的使用场景:

当函数的参数是接口类型引用时,如果接口中的方法不超过3个。可以通过匿名内部类来完成参数的传递。

其实就是在创建匿名内部类时,该类中的封装的方法不要过多,最好两个或者两个以内。


由于内部类必须继承或实现一个外部类或者接口。那么匿名内部类对象可以理解为该内部类父类的子类对象,能够调用自定义的任意方法以及父类方法,而不是父类引用指向子类对象


面试题

//1可以理解为Object的子类对象只是没名字 子类继承Object然后定义了自己的方法,然后调用自己的方法new Object(){void show(){System.out.println("show run");}}.show();//2   可以理解为父类引用指向子类对象 调用方法时编译看左边Object obj = new Object(){void show(){System.out.println("show run");}};obj.show();1和2的写法正确吗?有区别吗?说出原因。写法是正确,1和2都是在通过匿名内部类建立一个Object类的子类对象。区别:第一个可是编译通过,并运行。第二个编译失败,因为匿名内部类是一个子类对象,当用Object的obj引用指向时,就被提升为了, Object类型,而编译时检查Object类中是否有show方法,所以编译失败。-------------------------------------------------------class InnerClassDemo6 {+(static)class Inner{void show(){}}public void method(){this.new Inner().show();//可以}public static void main(String[] args) {//static不允许thisThis.new Inner().show();//错误,Inner类需要定义成static}}------------------------------------------------------interface Inter{void show();}class Outer{//通过匿名内部类补足Outer类中的代码。public static Inter method(){return new Inter(){public void show(){}};}}class InnerClassDemo7 {public static void main(String[] args) {Outer.method().show();/*Outer.method():意思是:Outer中有一个名称为method的方法,而且这个方法是静态的。Outer.method().show():当Outer类调用静态的method方法运算结束后的结果又调用了show方法,意味着:method()方法运算完一个是对象,而且这个对象是Inter类型的。*/function (new Inter(){public void show(){}}); //匿名内部类作为方法的参数进行传递。}public static void function(Inter in){in.show();}}




0 0
原创粉丝点击