java学习笔记10

1、接口的应用

接口类型的引用指向都是实现这个接口的具体子类的对象。

笔记本生产前肯定要先设计好USB接口的规则(形状),这是定义规则;把USB接口装到笔记本上,这是使用规则;之后U盘,鼠标照着USB的规则来生产USB接口型的产品,这是实现规则,而笔记本电脑插上U盘,鼠标后就扩展了功能。



2、多态性,多种形态

函数的多态性和对象的多态性,一个对象可以具有多个形态。多态的体现:父类引用执行子类对象。



多态提高了程序的扩展性。



用父类作为引用就可以接受很多子类对象的引用,这就是多态的核心。多态就是多种形态,要想一种形态(类)和另一个形态(类)有关系,就要继承或者实现接口。




多态里的所谓类型自动提升,如果是子类提升为父类类型(也称为:向上转型)如将猫转为动物类型,此时子类特有的函数就不能在使用了,之所以提升,就是为了限制子类的特有功能。同样还有向下转型:将父类转为子类,如将动物转为猫类型,是为了使用子类特有功能。转型时要注意自始至终是例如:猫先转为动物,再转为猫;不允许直接把new出的动物转为猫;也不能把狗先转为动物,再把这个动物转为猫。


下面用毕老师和毕姥爷的例子说明:



3、如何判断一个对象是否是某种类型:可使用关键字 instanceof 来判断

下图中函数的参数是Animal,但是里面有猫所特有的函数,如果传进来的是狗,那么就体现了函数的优越性了,函数可以通过借助 if 判断传进来的对象的类型,来决定是否执行下面指令。


4、覆盖或者重写只发生在成员函数,和成员变量没关系。

父类对象指向子类引用后,如果父类和子类中都有成员变量num,那么f.num取得是父类的num。如果父类中没有num,那你提升为父类找不num,就会报错。猫有9条命,但是动物没有9条命这个成员变量,所以没法调用。


但是当父类引用调用的是成员函数时,就会有所不同,编译看左边夫类有没有那个函数,运行时实际却运行的是右边子类的对应函数(如果自雷有同名的就编译通过,如果父类没有直接报错,没有的话继续调用左边的)


5、多态性是指对象的多态性,而静态函数不依赖于对象,所以可以理解为静态函数没有多态性,不会动态绑定到子类对象,Fu f = new Zi(); f.method()调用的就是父类自己的method(method为静态方法),如果是 zi.method( )那么调用的就是子类的静态方法method,静态的方法不需要对象,通过类名就能调用。而一般的函数都必须通过对象才能调用,所以调的是哪个的函数,要看子类的对象的具体类型。

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



6、内部类编译之后的名字为:外部类$内部类.class,其中$表示类的所属关系。


内部类的好处就是访问所属类方便。

比如孙悟空钻到铁扇公主,孙悟空可以访问铁扇公主的心肝脾,但是铁扇公主不能直接访问孙悟空内部,必须先new一个孙悟空对象才可以访问孙悟空内部成员。


内部类的地位和类的成员相似,可以用权限修饰符来修饰;如何在一个类中直接访问另一个类中的内部类:写法格式固定如下,图中的内部类是默认权限的,若是private则不能访问。


如果内部类是静态的,那么相当于一个外部类,可以直接new对象。Outer.Inter(这种写法表示内部类的所属关系)就是类名。如果内部类不是静态的,那么内部类的内部也不能有静态,也即内部类内部定义了静态成员,内部类也必须是静态的。



当内部类成员是静态时,随着外部类的加载就加载了,可以不new对象就调用,但是内部类还不是静态的,又必须在外部类的方法中new出内部类的对象才能调用内部类的成员,所以干脆把内部类也定义为静态,这样就可以直接:外部类.内部类.(静态)方法。

7、匿名内部类:就是内部类的简写格式。

之前是写好内部类,在其外部类的方法中创建内部类(继承它爹)对象,并调用内部类对象的方法,但是这几步骤比较麻烦,所以就又有了匿名内部类,前提是这个要创建的内部类必须继承了一个外部类,或者实现了一个接口。


之前的创建内部类对象的过程如下(绿色划线代码): 



之后改成匿名内部类的写法:

直接new一个外部类(其实可以理解为要创建的内部类他爹),但是把外部类的方法覆盖重写,覆盖后这样就相当于有了个子类对象(内部类对象),之后就可以直接调用内部类的成员了。

匿名内部类的使用地方:



还要注意的一些小细节:主函数为静态的,而匿名内部类相当于所在外部类的成员,而静态主函数中不允许有非静态的,所以要在内部类前面加上static修饰符。

内部类中有中有多个函数时,直接new 父类名(){ 。。。} .show() 调用着不方便,还是找个同类型的对象来接收,相当于起个名字,用着方便一点。


还有如下的小细节:

当父类引用指向子类对象的时候,不能通过生成的这个父类对象来调用子类所特有的函数,如果父类没有子类的函数,编译要失败,如果有,编译通过,但是运行的时候还是运行的子类的(同名)方法。具体参见多态时,成员变量,函数的编译运行三条准则。


下图中的 new Inter( )已经相当于一个匿名内部类了,Inter就是这个匿名内部类的父类或者说实现的接口,也就是说Inter in = new Inter() 就是父类引用 in 指向子类对象的例子。



同样道理还有例子如下:

object类中没有(子类所特有的)show()方法,所以不能用父类引用 obj去调用show( )方法


8、很详细的对象初始化过程

构造代码块什么时候运行呢?

构造代码块在子类构造函数super()后面的的显示初始化的后面紧接着。


其实在父类的内部也是隐藏了红色的那两句。具体如下图所示:


此时如果在main函数中执行一句: Zi z = new Zi();   

执行顺序为:先在方法区加载Zi的父类和Zi类,之后Zi的构造函数进栈;调用super(),进入父类的构造方法,开始父类的super(),接着显示初始化,堆中子类对象中的父类num成员为由最初默认的0变成9,之后构造代码块初始化,显示:“Fu”;接着调用show()方法,由于是对子类对象初始化,所以调用的是子类的show()方法,也就是覆盖,显示:“zi show 0”(显示的是子类自己的num,由于还未显示初始化,所以还是0);之后super()执行完毕,又回到子类的构造函数中,开始子类的显示初始化,子类的num由默认的0变为8,;接着构造函数代码块运行,打印:“zi”;之后子类的show()运行,显示:“zi show 8”




运行结果如下:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值