接着上一部分继续:上一部分学了类和对象的一些基本概念、以及对象的特性之一:封装性。
一、面向对象
this方法补充:
在前面已经学了this方法,关于怎么使用,已经很清楚了,但还是需要补充一些知识点:
应用举例:
理解项目的空间内存变化,对写代码有质的帮助。这点非常重要。比如:下面这个Account类、Customer类、Bank类。
面向对象的继承性:
对继承性的理解:
继承性有两种角度:
自上而下:类A、类B,类B功能和类A相似,这个时候,可以考虑类B继承类A。
自下而上:定义类B、C、D。发现B、C、D有共同的属性和方法。可以考虑将它们封装到类A中,并让BCD继承类A。
父类:superclass;子类:subclass。
介绍断点的作用:
断点可以帮助我们理解,栈和堆的空间变化。一般设置在 创建对象的时候。
这样点击运行,断点就会出现这个栈和堆的空间。类似下面:这里我们设置的断点是:Student s1=new Student();
区分重载和重写(再次):
super()关键字的补充:
使用场景:
super调用构造器:
其实super关键字,解决了一个,我们在测试类调用创建子类的对象时,它会把父类的属性一起创建在堆里面的问题。原因就是,默认使用了super()方法。例如下图解释:
碰到的问题:
在存在有参数的构造器时,使用继承的子类必须使用super带参数的关键词?
笔试题(一个挺棒的例子):
判断非继承方法里面this。和继承方法里面默认使用super()方法的例子。
在看看这个面向对象的例子:
这个例子面向不同的对象。分别有不同的属性。那么它的结果是什么,这个例子比较绕。
一点思考:虽然是旁听生,但这里的题目就不做了吗?不应该的,也是需要做的。这里的作业刚好可以给自己查缺补漏,不要觉得再做这里的作业会让自己的时间变得更短就不做了。我说的变化,就是争取一切能够帮助自己进步更快、更有用的方式去学习。所以,当然要争取变化。!
super关键字在与子类实例化的过程分析:
面向对象的多态性:
多态性指的是事物的一类状态。
使用前提:
1.要有类的继承关系
2.要有方法的重写
3.父类引用指向子类。
多态只适用于方法,不适用于属性。
例如:
多态性体现的口诀是:编译看左边,运行看右边。
适用场景:
例如:test.per(new Man())。 per(Person person)。 这种方式也叫做里氏替换原则。
多态的好处与弊端:
向下转型与多态性(重点):
多态就是把子类对象 赋值给父类变量。这个时候会出现类型转换的现象。我们把强类型转换的现象叫做向下转型;对基本使用,就是向上转型,也叫做多态性。
这里需要区分一下在继承的上一节知识点里,用到了super方法,这个方法是在子类调用父类的属性和方法。和多态是不一样的。多态一般都用在了测试类创建对象的时候。
多态的基本格式
就是:父类 变量名 = new 子类();(它存在一点弊端。)
不过,在我们写项目的时候,一般不会这么用,而是将父类 变量名,这一步作为方法的形参。然后在使用父类的对象去调用它这个方法时,传入new 子类()的实参。在上面叫做里氏替换原则。
但是这个会存在一些问题,就是父类创建的对象只能调用在子类里面重写的方法。对子类特有的方法不能调用。如果要调用子类特有的方法,这个时候,就需要用到向下转型。将父类创建的变量名转为子类的类型。这样就能使用子类特有的方法。
向下转型可以理解为,强类型转换。它的格式也是使用强类型符进行转换。
多态性可以理解为,向上转型。看下图理解,向下转型和强类型转换有点类似之处。
注意,多态的格式只能 父类 去 new子类。不能子类 new父类。如果反过来写,在逻辑上就会出现问题。因为我们是继承关系,不能子类new父类。只有通过向下转型(强类型转换才能调用子类特有的方法)例子:
它的格式是 子类 变量名 = (子类)父类变量名。
向下转型存在的问题:
向下转型和强类型转换是一样的,会存在精度丢失一样的问题。不过,在强类型转换,可能出现的异常是类型转换异常。解决方式: instanceOf
格式:a instanceOf A
使用多态的题目:
这个题目还可以更难一些。让属性添加private的权限修饰符。这个题型考查,多态只会调用方法,对属性无影响。
clone()和finalize()的介绍:
clone():它用于复制对象。注意复制的对象是一个新的内存空间。 p1.clone();
finalize():它用于GC机制,当GC要回收对象的时候调用它,我们可以通过重写此方法,可在释放对象前进行某些操作。比如:某些机制被退出后,仍然保存一些信息。
它有一个面试题:finalize()、final、finaly 的区别。
equals()、toString()方法:
equals和toString()方法都是Object类的方法。在讲解这两个方法的同时,会讲到Object类的使用。
equals()的使用场景:
当自定义的类在没有重写equals方法的时候,每次使用equals方法都是调用的是Object声明的equals方法。它的作用是比较两个对象的引用地址是否相等。
需要注意:对于像String、File、Date和包装类来说,它们本身都已经重写过了equals方法,它们重写了,都是比较两个对象的实体是否相等。
所以,我们使用自定义的类时,如果考虑使用equals方法去比较两个引用类型的内容是否相等,就需要重写equals方法。
重写equals方法:
有两种方式可以重写equals方法。第一种:使用eclipse自动生成。右键,选择Generat equals and hashCode(),然后一直点击next就可以重写equals方法。
第二种:手写(见下图)。这也是重写的格式,它返回的类型是boolean,需要用到向下转型。
这个例子可以实操一下,检验学习成果。
面试题:区分== 与equals()
== 是运算符,使用范围:基本数据类型、引用数据类型。在基本数据类型中,比较它们的值是否相等,在引用数据类型中,比较两个引用变量的地址值是否相等。
equals()方法,它只能使用在引用数据类型中,对于类来说,它有两种使用方式,重写与不重写。
toString()的使用场景:
toString()方法是Object类里的方法,我们平时在调用System.out.print()时打印对象引用变量,其实就调用了对象的toString()。
toString的定义:return getClass().getName+"@"+Integer.toHexString( hashcode() );
它的作用范围和toString()类似,在没有重写toString的前提下,默认返回的是当前对象的地址值。而像String、File、Date或包装类等Object的子类,它们都重写了Object类的toString(),在调用toString()时,返回当前对象的实体内容。
一般情况下,我们使用toString都是希望显示对象的实体内容,而非地址值。这个时候,就需要用到重写toString方法了。它的重写方式也有两种。之前学过了,就不再概述。