访问控制修饰符
信息隐藏是 OOP 最重要的功能之一,也是使用访问修饰符的原因。在编写程序时,有些核心数据往往不希望被用户调用,需要控制这些数据的访问。
对类成员访问的限制是面向对象程序设计的一个基础,这有利于防止对象的误用。只允许通过一系列定义完善的方法来访问私有数据,就可以(通过执行范围检查)防止数据赋予不正当的值。
作用:
- 防止对封装数据的未授权访问。
- 有助于保证数据完整性。
- 当类的私有实现细节必须改变时,可以限制发生在整个应用程序中的“连锁反应”。
访问范围 | private | default(默认) | protected | public |
---|---|---|---|---|
同一个类 | 可访问 | 可访问 | 可访问 | 可访问 |
同一包中的其他类 | 不可访问 | 可访问 | 可访问 | 可访问 |
不同包中的子类 | 不可访问 | 不可访问 | 可访问 | 可访问 |
不同包中的非子类 | 不可访问 | 不可访问 | 不可访问 | 可访问 |
public class Person {
private String name;
private int age;
public Person(){}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void display(){
System.out.println("姓名:"+this.name+",年龄:"+this.age);
}
public static void main(String[] args) {
Person p = new Person("wqc",20);
p.display();
}
}
一、封装
隐藏内部的实现细节,对外提供公共的访问方式。封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
作用:
- 良好的封装能够减少耦合。
- 类内部的结构可以自由修改。
- 可以对成员变量进行更精确的控制。
- 隐藏信息,实现细节。
1.封装实现
私有化属性后,对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问。
public class Person{
private String name;
private int age;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public void setName(String name){
this.name = name;
}
}
public class Test {
public static void main(String[] args) {
Person p = new Person();
p.setName("小王");
p.setAge(20);
System.out.println("姓名:"+p.getName());
System.out.println("年龄:"+p.getAge());
}
}
其中使用的
this
关键字是为了区别局部变量和成员变量
二、继承
继承实现了类层面的封装,提取了一个或多个类中的共性内容,定义在父类,子类哦通过继承父类去访问父类属性和方法。
所以,继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为
1.实现
class Person {
private String name;
private int age;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name=name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age=age;
}
}
class Student {
private String name;
private int age;
private String schoolName;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name=name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age=age;
}
public String getSchoolName()
{
return schoolName;
}
public void setSchoolName(String schoolName)
{
this.schoolName=schoolName;
}
}
以上代码可以看出,两个类中有很多重复的内容,不符合Java语言的开发规范,这段代码不仅从代码上重复,而且从概念上讲学生一定是人,只是学生类描述的范围小,具备更多的属性和方法,这个时候想要消除结构定义上的重复,就要用到继承。
class Person {
private String name;
private int age;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name=name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age=age;
}
}
class Student extends Person{
private String stuNo;
public void setStuNo(String stuNo){
this.stuNo = stuNo;
}
public String getStuNo(){
return stuNo;
}
}
public class Test2{
public static void main(String[] args)
{
Student student=new Student();
student.setName("花花");
student.setAge(18);
System.out.println("姓名:"+student.getName()+" 年龄:"+student.getAge());
}
}
通过以上代码可以发现,当发生了类继承关系之后,子类可以直接继承父类的操作,可以实现代码的重用,子类最低也维持和父类相同的功能。
格式:
class 父类 {
}
class 子类 extends 父类 {
}
2.作用
1.提高代码的复用性
2.子类一旦继承父类,就有权访问父类中的内容
3.子类可以进行扩展,可以定义子类中独有的内容
3.注意
继承为单继承机制,一个子类只能继承一个父类,但可以多实现
一个父类可以被多个子类继承
单继承的优点:结构和操作简单
单继承缺点:不便于后期维护
4.重写
方法体的重新实现
4.1 与重载的区别
重载:
1.同一个类中的多个方法
2.方法名相同
3.参数列表不同|方法签名不同
重写:
1.不同的类
2.继承|实现
3.方法签名相同
4.2 不能重写的条件
1.被private修饰的成员方法不能被重写
2.被final修饰的成员方法不能被重写
3.被static修饰的成员方法不能被重写
4.3 检测是否重写
1.在行号的位置显示O↑
2.@Override注解是否报编译错误
4.4重写的条件
1.==:子类重写方法与父类中的方法签名完全相同
2.<=:返回值类型相同,基本数据类型完全相同,引用类型子类范围<=父类范围
3.>=:子类访问权限修饰符>=父类访问权限修饰符
三、多态
一种事物的多种表现形式
1.前提:
通过继承或者实现的方式
2.多态调用:
会调用子类中的重写方法,对子类新增不可见
3.调用成员方法:
编译看父类,运行找子类
4.调用成员变量:
编译运行看父类
多态引用调用时,对子类新增成员不可见
5.转型:
5.1向下转型
多态前提下,想要调用子类的新增内容需要向下转型
基本数据类型
小范围类型 变量 = (小范围类型)大范围类型
引用数据类型
子类类型 子类类对象 = (子类类型)父类类对象
5.2向上转型
父类引用指向子类对象
父类类型 引用变量 = new 子类类型();
6.注意
“java.lang.ClassCastException”类型转换异常
解决:instanceof:判断前面的引用指向的对象是否为后面类型的对象,或钱买你的引用是否指向后面类型的子类对象。
编译原则:只检查钱买你的引用与后面的类型是否在同一继承体系上,在则通过,不在则不通过