一、封装(模块化)
1.问题的引入:
当我们创建一个类的对象后,可以通过对象.属性的方式,对对象进行赋值。
这里,赋值操作受到属性的数据类型和存储范围的制约,除次之外,没有其他制约条件。
但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件,这个条件又不能在属性声明时体现
,我们只能通过一个public 方法对属性进行限制条件的添加(get(),set())
同时,我们需要避免用户再使用“对象.属性”进行赋值,则需要将属性声明为私有化。
--》此时,针对属性就体现了封装。
2.封装的思想
(1)类的内部数据操作细节自己完成,不允许外部干涉。仅对外暴露少量的方法用于使用
(2)隐藏对象内部的复杂性。只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。
(3)封装性的设计思想:把该隐藏的隐藏起来,该暴露的暴露出来
例如:
public class Animal{
int age;//年龄可能被赋为负数,不符合实际
int legs;//腿有可能被赋为负数或奇数个,不符合实际
}
所以可以给属性设置一个get()和set()方法,来添加限制条件,并获取和设置相应的属性值,如下:
public class Animal{
private int age;
private int legs;
//对属性的设置
publci void setAge(int age){
if(age>=0){
this.age=age;
}
//对属性的获取
public int getAge() {
return age;
}
//对属性的设置
public void setLegs(int leg){
if(leg>=0&&leg%2==0){
legs=leg;
}else{
legs=0;
}
}
//对属性的获取
public int getLegs(){
return legs;
}
}
但仅这样还不够,因为用户还是可以通过“对象.属性”的方式更改属性值,所以,为了避免者中情况发生,要将相应的属性私有化,只对外留下public方法来供用户对属性进行使用。
2.封装的体现:
(1)将类的属性私有化,同时提供public方法来获取和设置此属性的值
(2)不对外暴露的私有的方法
(3)单例模式(构造器私有化)
3.封装性的体现,需要权限修饰符(private)的配合
(1)Java的四种权限:
private 缺省 protected public
(2)4种权限可以用来修饰类及类的内部结构(属性、方法、构造器、内部类)
(3)具体的:4种都可以修饰类的内部结构
修饰类:缺省,public
二、类的继承性(代码复用)
1.继承的作用
(1)减少了代码的冗余,提高了代码的复用性
(2)便于功能的扩展
(3)为之后多态性的使用,提供了前提
2.关于继承的描述
一旦子类继承了父类。子类就获取了父类的所有属性和方法,包括私有private方法或属性
证明:
私有属性:通过get()\set(int i)来进行设置和获取
私有方法:将私有方法放在public方法中还是可以被调用的
3.方法的重写:
(1)子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
(2)子类重写的权限不小于父类(特殊:子类不能重写private方法)
(3)子类重写方法抛出的异常类型不大于父类
(4)返回值类型:
a.父类被重写的方法类型是void,子类重写也是void
b.父类被重写的方法类型是A,子类重写方法可以是A或A的子类
c.父类被重写的方法类型是基本数据类型,子类重写方法也是相同的基本数据类型
(5)不能重写static方法
4.为什么要重写:
(1)父类的情况不适用于子类
例如:(圆柱体类继承圆类)圆求面积,但圆柱体求表面积
(2)操作的多样化
5.方法的重载和重写
(1)从定义看:
重载(同一个类中,继承类):方法名相同,形参列表不同,返回值可以不同,权限符可以任意不同
重写(继承类):方法名,形参列表相同,返回值,权限符与父类的有关
(2)从编译和运行的角度
重载(不表现为多态性):允许存在多个同名的方法,编译器根据方法的不同的参数列表进行区分,对编译器而言,这些同名方法就成了不同的方法,因此它们的调用地址在编译期间就确定了
重载:早绑定,静态绑定
重写:可以理解为多态,动态绑定,晚绑定,只有在运行时,才知道调用的对象是父类还是子类的
(3)static:重载可以,重写不行
static 随着类的加载加载,不能被覆盖
(4)构造器可以重载不能重写
6.super关键字
(1)调用属性,方法
a.一般省略
b.子类、父类有同名属性时,要用super.属性来指明是调用父类的属性
c.子类重写父类方法后,在子类方法中调用父类被重写的方法时,要用super.方法
(2)调用构造器
super(参数1,参数2,...)
三、类的多态性(运行时行为,只有在运行后才能确定对象)
1.理解:
一个事物的多种形态
2.何为多态性(多态的使用):动态绑定
(1)对象的多态性:(向上转型)编译看左(父类),运行看右(子类),调用虚拟方法
①父类引用指向子类对象,当调用子父类同名参数的方法时,实际执行的是子类重写父类的方法---虚拟方法调用
虚拟方法:在多态的情况下,父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,
动态调用属于子类的该方法,这样的方法在编译时是不确定的
②如果子类没有重写该方法,则执行父类的方法.
③该子类对象不能调用自身的特有方法(编译会看左边的父类)
class Animal{
public void walk(){
System.out.println("动物跑");
}
}
class Cat extends Animal {
@Override
public void walk() {
System.out.println("喵喵走路");
}
public class AnimalTest {
public static void main(String[] args) {
Animal cat=new Cat();//父类引用指向子类对象
cat.walk();//调用walk()方法,执行的是子类重写的walk方法
}
}
(2)对象的多态性只适用于方法不适用于属性,属性都看左边的父类
3.多态的使用前提:
(1)类的继承关系
(2)要有方法的重写
4.为什么有多态性:
可以通过传入不同的对象来控制不同的特征结果
5.为什么有了对象的多态性后,子类特有的方法和属性不能调用
内存中实际上是加载了子类特有的属性和方法,但是由于变量声明为父类类型,
导致编译时,只能调用父类中声明的属性和方法,子类特有的属性和方法不能调用
如何调用子类特有的属性和方法:
强制类型转换,(向下转型)将父类引用指向的对象转为为子类类型,可能会出现ClassCastException异常,
解决方法:instanceof
(1)a instanceof A:判断对象a是否是A的实例,如果true就向下转型
Animal cat=new Cat();
if(cat instanceof Cat){
Cat cat1=(Cat)cat;
cat1.eat();
}
(2)如果 a instanceof A:为true,a instanceof B也为true,则B是A的父类
来源:51CTO
作者:小西几
链接:https://blog.51cto.com/14234228/2467014