Java封装与继承
封装思想
- 把对象的状态和行为看成一个统一的整体,将字段和方法放到一个类中
- 信息隐藏:把不需要让外界知道的信息隐藏起来
- 尽可能隐藏对象功能实现细节,向外暴露方法,保证外界安全访问功能
🐤封装的好处
- 保证数据的安全
- 提高组件的复用性
包
- 在开发中,我们存在几百上千个Java文件,如果所有的Java文件都在一个目录中,管理起来也很痛苦
- 此时,我们可以使用生活中的解决方案,此时在Java中,我们把这个特殊文件夹称之为
包(package)
- 关键字:package,专门用来给当前Java文件设置包名
🐤包的作用
- 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用
- 如同文件夹一样,包也采用了树形目录的存储方式
🐸注意点
- 同一个包中的类名不能相同,不同的包中的类的名字是可以相同的
- 当同时调用两个不同包中相同类名的类时,应该加上包名,用来区别。因此,包可以避免名字冲突
语法格式:package 包名.子包名.子子包
必须把该语句作为Java文件中第一行代码(所有代码之前)
包名定义
- 包名必须遵循标识符规范,
全部小写
- 定义格式:域名倒写.模块名.组件名(com.bntang666.login.authorization)
import 关键字
- 当A类和B类不在同一个包中,若A类需要使用到B类,此时就得在A类中去导入B类
- 系统提前帮我们做了很多功能,他们都放到了包里面,我们只需要把它们从指定的包里面导入,就可以使用了
- 使用系统提供的功能,需要从系统的包里面导入类
访问修饰符
- 访问权限修饰符来规定在一个类里面能看到什么,能暴露什么
访问修饰符分类
- private:表示私有的, 表示类访问权限,只能在本类中访问,离开本类之后,就不能直接访问
- protected:表示子类访问权限, 在同包中的可以访问, 不同包不能访问, 继承也可以访问
- public:表示全局的, 公共访问权限, 使用了public修饰, 则可以在当前项目中任何地方访问
- 默认:表示包访问权限,访问者的包必须和当前定义类的包相同级别才能访问
包的作用域
属性与 this 关键字
属性和字段类似,也是一个成员变量
- 但是必须得要有
getter/setter
方法 - 有getter/setter方法的字段才是属性,没有就是字段
- 一般属性都是私有的,公有的别人可以直接获取和设置值
this
- this 就是代表当前正在使用的对象的内存地址
🐤this的使用和注意点
- 解决成员变量和参数(局部变量)之间的二义性(区别开来)
- 同类中实例方法之间相互调(此时可以省略this, 但是不建议省略)
- 将this作为参数传递给另一个方法
- 将this作为方法的返回值(链式方法编程)
- 构造器重载的互调,this([参数])必须写在构造方法第一行
- static不能和this一起使用
- 当字节码被加载进JVM,static成员已经存在了
- 但是此时对象还没有创建,没有对象,就没有this
this 构造器
继承思想
🐤首先引出继承
代码存在问题
- 上面三个类,发现有共同的代码
- 如何来去解决代码的重复问题
- 我们就可以使用继承来去解决上面问题
什么是继承
- 从已有类中,派生出新的类,新的类中吸收已有类当中的状态和行为
- 把多个类中相同的属性和行为进行提取
- 派生出一个新的类
- Java继承是使用已有类作为基础,建立新的类
- 继承是一种, 从一般到特殊的关系,是一种
is a
的关系 - 即子类是对父类的派生,是一种特殊的父类
- 比如:狗是动物的一种特殊情况,狗也属于动物
- 卡车是车的一种特殊情况,卡车属于车
如何表示继承
- 语法格式:在定义子类的时候来表明自己需要拓展(继承)于哪一个父类
public class 子类类名 extends 父类类名
{
编写自己特有的状态和行为
}
继承的作用
- 解决代码重复的问题
- 表示出一个体系
继承编写规则
- 一般,我们在开发过程中先编写多个自定义类,写完之后
- 发现多个类之间存在共同的代码,此时可以抽出一个父类
🐸子类与父类的继承关系
- 子类继承父类之后, 可以拥有父类的某一些状态和行为
- 子类复用了父类的功能和状态
- 但并不是父类当中所有的内容,子类都可以直接使用
🐤子类可以使用父类当中的哪些成员
- 如果父类中的成员使用
public
修饰, 子类则可以完全继承 - 如果父类中的成员使用
protected
修饰, 子类也可以继承, 即使父类和子类不在同一个包中 - 如果父类和子类在同一个包中此时子类可以继承父类中默认修饰符修饰的成员,不同包不能继承默认修饰符修饰的成员
- 如果父类中的成员使用
private
修饰,子类打死都继承不到,因为private只能在本类中访问 - 父类的构造器,子类也不能继承,因为构造器必须和当前的类名相同
方法的覆盖 Override
- 子类继承了父类,可以获得父类的部分方法和成员变量
- 可是当父类的某个方法不适合于子类本身的特征(要求)时,可以进行覆盖
- 重新定义父类当中的方法
方法的覆盖原则
- 实例方法签名必须相同(方法名+方法参数)
- 子类方法的返回值类型是和父类方法的返回类型相同的,或者是其子类
- 子类方法声明抛出的异常类型和父类方法声明抛出的异常类型相同,或者是其子类
- 子类方法的访问权限比父类方法访问权限更大或相等
Bird.java
public class Bird {
Bird(){
System.out.println("执行了Bird构造器");
}
void fly(){
System.out.println("飞到天空了");
}
}
@Override
注解的作用:是用来判断标记的方法是否为覆盖的方法
- 若方法是覆写方法,在方法前或上方贴上该标签, 编译通过就是覆盖方法,否则,编译出错就不是一个覆盖方法
Penguin.java
public class Penguin extends Bird {
@Override
void fly() {
System.out.println("企鹅跳跳");
}
void test(){
System.out.println("test---------");
this.fly();
super.fly();
}
Penguin(){
super();
}
}
class Demo{
public static void main(String[] args) {
Penguin penguin = new Penguin();
penguin.fly();
}
}
- 如果一个类有父类,会在子类当中默认调用父类的构造器
- 先创建父类,在创建当前类
- 关于方法的查找,会先到当前类中找,看看有没有需要调用的方法,如果没有,在去父类当中查找
🐤什么时候进行方法的覆盖
- 当父类的某一个行为(方法)不符合子类具体的特征的时候,此时子类需要重新定义父类的方法,并重写方法体
方法重载和方法覆盖的区别
方法重载 Overload
- 解决了在同一个类中, 功能相同,方法名称相同的问题,而使用参数不同
- 既然是相同的功能,那么方法的名字就应该相同
- 同类中,方法名相同,方法参数列表不同
方法重写 / 覆盖 Override
- 解决子类继承父类之后,可能父类的某一个方法不满足子类的具体特征,此时需要重新在子类中定义该方法,并重写方法体
- 父类和子类的方法签名(名称)是相同的
super 关键字
- 当前对象的父类对象
- 在子类中的某一个方法中,去调用父类(中的方法)也就是可以被覆盖的方法
- 此时的解决方案,使用
super
关键字
🐤super 关键字的使用场景
- 可以使用 super 关键字解决子类隐藏了父类的字段情况,该情况我们一般不讨论,因为破坏封装
- 在子类方法中,调用父类(的方法)也就是可以被(重写)覆盖的方法
- 在子类构造器中,调用父类构造器,此时必须使用super,语句为:super([实参])
- static不能和super以及this共存
Animal.java
public class Animal {
private String name;
private int age;
Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
}
Dog.java
public class Dog extends Animal {
String color;
Dog(String color, String name, int age) {
super("BNTang", 23);
this.color = color;
}
public static void main(String[] args) {
Dog dog = new Dog("黑色", "BNTang", 23);
System.out.println(dog.getName());
System.out.println(dog.color);
}
}
- super()构造方法必须得要放到第一行
- 凡是子类的构造方法当中,都会有super()
- this(),一起使用
子类初始化过程
- 在创建子类对象之前, 会先创建父类对象
- 调用子类构造器之前, 在子类构造器中会先调用父类的构造器
- 默认调用的是父类无参数构造器
- 所有的类都会继承一个类就是object类,所以说任何类都会在构造器当中有一个super()
隐藏
- 满足继承的访问权限下,隐藏父类静态方法:若子类定义的静态方法的签名和超类中的静态方法签名相同,那么此时就是隐藏父类方法。注意:仅仅是静态方法, 子类存在和父类一模一样的静态方法
- 满足继承的访问权限下,隐藏父类字段:若子类中定义的字段和超类中的字段名相同(不管类型),此时就是隐藏父类字段,此时只能通过
super
访问被隐藏的字段 - 隐藏本类字段:若本类中某局部变量名和字段名相同,此时就是隐藏本类字段,此时只能通过this访问被隐藏的字段
SuperClass.java
public class SuperClass {
String name = "BNTang";
int age;
public static void test(){
System.out.println("Super test");
}
}
SubClass.java
public class SubClass extends SuperClass {
public static void test(){
System.out.println("Sub test");
}
String name = "JonathanTang";
void Show(String name){
System.out.println(this.name);
System.out.println(super.name);
}
public static void main(String[] args) {
SubClass subClass = new SubClass();
subClass.Show("Demo");
SubClass.test();
SuperClass.test();
}
}
UML
- 又称标准
建模语言
- 可以用来表示软件开发过程当中类与类之间的关系
主要模型
🐤功能模型
- 从用户的角度展示系统的功能,包括用例图
🐸对象模型
- 采用对象、属性、操作、关联等概念展示系统的结构和基础,包括类图、对象图、包图
🐬动态模型
- 展现系统的内部行为。 包括序列图、活动图、状态图
类图的画法
🐤权限表示
- public公用的:用
+
前缀表示,该属性对所有类可见 - protected受保护的:用
#
前缀表示,对该类的子孙可见 - private私有的:用
-
前缀表示,只对该类本身可见 - package包的:用
~
前缀表示,只对同一包声明的其他类可见 - 静态成员: 用
_
表示
🐸继承关系
UML画图ProcessOn
:https://www.processon.com/