JavaSE
面向对象三大特征
一.封装
1.概念:
将数据和基于数据的操作封装在一起。
2.好处:
重点:将数据保存在内部;
目的:将类使用者和类设计者分开。
3.应用在代码中。
- 在定义变量和成员方法是要秉持授予最小访问权限的原则。
- 若成员变量被“pirvate”定义,要考虑提供对应得public get,public set方法。
好处:可以修改private成员变量;完成对成员变量访问的读写分离;可以在修改值时进行检查,拒绝错误修改
4.访问权限修饰符
在Java中,一切事物都有访问权限,在语言层面是由访问权限修饰符实现。
在声明的类体中 / 同包的其他类的类体中 / 不同包(在import情况下)
public
protected
默认(包权限)
private(最小访问权限)
成员变量,成员方法(类中成员)
针对对于其他类的可见性(类能不能使用)。
public:
在类体中:可以直接访问,可以创造对象进行访问。
在同包其他类中:可以通过创造对象进行访问。
不同包的类中:同上。
三种情况都能访问。
protected:
在类体中:可以直接访问,可以创造对象进行访问。
在同包其他类中:可以通过创造对象进行访问。
不同包的类中:
分两种情况:
在非同包的子类中,其方法可以直接访问父类的protected修饰的成员。
在非同包的子类中,创建该子类对象及子类对象的引用也能访问父类中的protected修饰的成员。
其他情况不能访问。(特别注意在跨包子类中创建父类对象,并不能访问protected类变量)
默认(缺省):
在类体中:可以直接访问,可以创造对象进行访问。
在同包其他类中:可以通过创造对象进行访问。
不同包中不能访问。
private:
在类体中:可以直接访问,可以创造对象进行访问。
其他都不能访问。
类
针对对于外部的使用者的可见性(能不能用这个类)
public:
同一包中可以访问到。
不同包中可以访问到。
默认:
在同一包中可以创建类对象。
不同包中不能创建类对象和继承。
控制修饰符的好处
从代码的使用者来讲:可以快速忽略不该碰触的“private”方法。
从coder的角度来讲:可以防止自己的代码被别人广泛使用,从而免费帮别人维护。同时可以安全得实现细节。
二.继承
1.概念:
java的一种复用机制,防止代码产生冗余。
表示一种从属关系。is-a的关系:
从数据类型看可以把子类类型当做父类类型。因为子类拥有父类的所有数据和基于这些数据的操作。
语法:class A extends B {}
被继承的类叫做父类(基类,超类)
继承其他类的类叫子类(派生类,导出类)
子类通过继承机制,可以拥有父类的“所有成员”。
2.优缺点:
优点:
- 代码复用;
- 便于维护;减少代码冗余;
- 弱化了Java语言的类型约束(父类类型引用指向子类对象)
缺点:
- 父类修改后,会反应在所有的子类中,我们无法选择父类中的修改应该反应在哪些子类中。
3.单重继承:
extend后面只能跟一个类名。
但这不意味着一个类只能继承另外一个类的类成员。而是可以继承该类和该类的所有祖先类。
4.注意事项:
- 子类只能访问父类的所有非私有成员。
- 子类不能继承父类的构造方法。
5.子类对象的初始化:
子类对象中,有两部分数据构成,一部分是父类中声明的变量,一部分是子类中自己定义的成员变量的值。初始化过程中,需要先初始化父类中的变量,再初始化子类中的变量,因为避免一些子类中的变量初始化需要用到父类变量的情况。
实现条件:保证父类的构造方法执行在子类之前。
隐式初始化
由JVM完成。
条件:
- 父类中存在默认的构造方法。
- 子类中没有显示地调用父类的其他构造方法。
- 则在子类构造方法执行前,会自动调用父类的默认构造方法。
显式初始化
由我们自己编写。
- 在子类构造方法中通过super()的方式调用父类构造方法。
- super语句必须在子类构造方法的第一句位置。
- 若父类没有默认构造方法,则在子类构造方法的第一句位置通过super(实参列表)调用某个构造方法。
- super和this在构造方法中不共存,因为都需要放在第一句的位置。
super关键字
super代表父类的引用。可以类比this。
父类域的隐藏
子类对象调用子类的方法,通过方法访问同名成员变量,同名变量是指子类中定义的变量。
子类对象调用父类的方法,通过方法访问同名成员变量,同名变量是指父类定义的同名成员变量。
在子类的方法体中访问成员变量:
查找规则:在子类对象上查找子类自身是否存在这个成员变量,如果有则访问,如果没有就在父类的对象上查找目标变量,并访问。
当然,在子类对象中,用 对象名.变量访问的是子类的成员变量。搜索方案跟上个规则一致。
所以,什么是父类成员变量的隐藏:在子类类体中,通过同名成员变量的变量名访问到的是子类中定义的同名成员变量,使得父类成员变量在子类中看起来被隐藏了。
利用super关键字,则可以在子类中访问到父类的同名成员变量。
方法的覆盖或重写
在子类对象上调用子类的“一摸一样”方法,运行的是子类的“一摸一样”方法。
在子类对象上调用父类的“一摸一样”方法,运行的还是子类的“一摸一样“方法
看起来像是被子类的方法覆盖掉了。
在子类中通过super关键字调用父类的同名方法。
在子类中调用方法:
查找策略:优先在调用方法的类中找到目标方法,如果有了,则执行目标方法;如果没有,则接着在父类中查找目标方法,直到找到为止。注:方法寻找的每一步都要从调用方法的对象自身先找起。
方法覆盖的使用场景:
不希望受到父类的修改而受到影响时。
在子类中修改父类方法的实现(方法覆盖)并不是在物理上修改了父类的同名方法实现,而是运用了目标方法的查找策略。
方法覆盖的条件: ----> @Override 该方法可判断覆盖是否成功
- 子类中的方法权限要大于或者等于( >= )父类中的同名方法。
- 返回值:基本类型返回值和引用类型返回值。基本类型返回值相同;引用类型返回值,子类的返回值应该与父类方法的返回值相同或者是父类方法返回值的子类。
- 方法签名必须一致。
注意事项:
- 父类的私有方法不能被重写。(语法不会产生错误,但是覆盖无效)
- 静态方法不能被重写。(同上)静态方法属于类,理论上可以重写,但不具备多态性。多态性只与实例和非静态方法有关。
- 父类中被final修饰的方法不能重写。
- 父类的构造方法不能重写。
final
可以修饰类,成员方法,变量。
修饰类:类不能被继承。
修饰方法:方法不能被重写。
修饰变量:变量 ----> 常量 且只能被赋值一次(常量可分为:字面值常量,自定义常量)
final 修饰局部变量,只要保证在使用之前赋值就可。
final 修饰成员变量,需要保证在创建对象之前能赋值。(通过 变量初始化值,构造方法,构造代码块 都可,不考虑JVM的默认值)。
static final 修饰的变量命名规则,全部大写,单词之间用’_'分割。
三.多态
实现多态的三个前提条件:
- 继承
- 方法覆盖
- 父类引用指向子类实例(子类对象)
成员访问特点:
父类引用变量 = 子类实例
- 成员变量:编译看左边,运行看左边
- 成员方法:编译看左边,运行看右边
编译看左边是指:引用变量的类型决定了可以访问到的成员的范围。
运行看左边是指:访问多态成员变量的时候。(外貌上是一个父类)
运行看右边是指:多态成员方法的访问。
多态的好处:
- 提高了程序的维护性(由继承保证)。
- 提高了程序的拓展性(由多态保证)。
多态的弊端:
不能访问子类特有的功能。
方案:多态中进行转型。
–》
类型转换:
-
向上转型:子类类型引用变量 可直接赋值给 父类类型引用引用变量 (天然允许)
父类类型的引用变量 = 子类类型的引用变量 -
向下转型:父类类型的引用变量 可直接赋值给 子类类型的引用变量(默认禁止)
子类类型的引用变量 = 父类类型的引用变量
向下转型需要通过强制转换。
语法: 目的类型 引用变量 = (目标类类名)待转化的引用变量
条件:需要满足父类引用实际指向的就是强制转换的这个子类对象,才能转化成功。否则会产生ClassCastException错误。
如何判断?
通过 instanceof
语法: 引用变量 instanceof 实际类型
判断引用变量是否为实际类型的对象。
父类引用 instanceof 目标子类类型 ----> 返回boolean类型的值
注: 任何引用变量都可以被赋值为null,但是若引用变量为null则一定返回false
public static Test(Person p){
if( p instanceof Student )
{
Student stu = (Student) p;
}
}