Java轻松掌握面向对象的三大特性封装与继承和多态
作者:小学生!! 发布时间:2021-07-27 02:39:11
1.封装
1.介绍
封装是指把抽象出的属性和方法封装在一起,数据被保护在内部,程序的其他部分只能通过被授权的方法,才能对数据操作。
2.封装的理解和好处
隐藏实现的细节
可以对数据验证,保证安全合理
3.封装的实现步骤
将属性私有化(private)
提供一个公共的set方法,用于对属性判断并赋值
提供一个公共的get方法,用于获取属性的值
public class Student {
private Double score;
public void setScore(Double score) {
//还可以在这里进行属性的判断
this.score = score;
}
public Double getScore() {
return score;
}
2.继承
1.介绍
继承可以解决代码的复用,当多个类具有相同的属性和方法时,我们可以从中抽象出父类,然后再父类中定义这些相同的属性和方法,这样所有的子类就不需要再定义这些相同的属性和方法,只需要使用extends关键字来继承父类即可。
2.继承的基本语法
public class Graduate extends Student{
}
子类会自动拥有父类定义的属性和方法
父类又叫基类,超类
子类又称派生类
3.继承的使用细节
子类继承了父类所有的属性和方法,但是私有属性和方法不能在子类直接访问,要通过公共的方法去访问。
package com.wang.extend;
public class Student {//父类
public int age;
public String name;
private Double score;
String hobby;
public Double getScore() {
return score;
}
package com.wang.extend;
public class Graduate extends Student {//子类
public void test() {
//子类不能直接访问private属性,要调用公共方法得到
System.out.println("大学生" + name + age + hobby + getScore());
}
}
子类必须调用父类构造器,完成父类的初始化,当创建子类对象时,不管使用子类的哪一个构造器,默认会先去调用父类的无参构造器,若父类没有无参构造器,则必须在子类构造器中使用super()指定使用父类的哪个构造器完成父类初始化,否则编译失败。
package com.wang.extend;
public class Student {//父类
public int age;
public String name;
//public Student() {
//}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
package com.wang.extend;
public class Graduate extends Student {
public Graduate() {
// super();//默认会有一个调用父类无参构造的方法super()
//若父类没有无参构造器,必须用super()指定使用哪个构造器
super(20,"小明");
}
}
super()在使用时,需要放在第一行。
super()和this()都只能放在构造器第一行,因此这两个方法不能同时存在于同一个构造器。
Java所有的类都是Object的子类。查看类的层级Ctrl+H。
父类构造器的调用不限于直接父类!将一直向上追溯到Object类(顶级父类)。
子类最多继承一个父类,java的单继承机制。
不能滥用继承,子类和父类要符合包含关系。比如,大学生包含在学生当中,这是学生就可以是父类,大学生为子类。
3.super关键字
1.基本介绍
super代表的是父类的引用,用于访问父类的属性,方法,构造器
2.基本语法
1.访问父类的属性/方法,但不能访问父类的private属性/方法
super.属性名; super.方法名(形参列表);
2.访问父类的构造器
super(形参列表);//只能放在构造器的第一句
3.细节与好处
1.父类属性由父类初始化,子类的属性子类初始化,分工明确。
2.当子类与父类的成员重名时,若要访问父类的成员,必须通过super。
3.super的访问不限于直接父类,当多个基类都有同名的成员,使用super访问时遵循就近原则。
4.super与this的比较
区别点 | this | super |
---|---|---|
访问属性 | 先访问本类的属性,若本类没有再去父类 | 只访问父类的属性 |
调用方法 | 先访问本类的方法,若本类没有再去父类 | 直接访问父类的方法 |
调用构造器 | 调用本类的构造器,必须放第一句 | 调用父类的构造器,必须放第一句 |
特殊 | 表示当前对象 | 表示子类访问父类对象 |
4.方法重写
1.基本介绍
子类的一个方法与父类的名称,返回类型,形参列表都一样,称子类是父类方法的重写。
2.注意事项与使用细节
1.子类方法的返回类型与父类方法的返回类型相同或者父类返回类型的子类。
//正确示例
public Object a() //父类返回类型为Object
public String a() //子类返回类型为String或者Object
//Object是String的父类
2.子类方法不能缩小父类方法的访问权限。
//接下来是错误示例
void display() //这是子类 子类访问权限为 默认的
public void display() //这是父类 父类访问权限为public
//public->默认的 访问权限变小所以报错
3.重载与重写的比较
名称 | 发生范围 | 方法名 | 形参列表 | 返回类型 | 修饰符 |
---|---|---|---|---|---|
重载 | 本类 | 必须相同 | 参数类型,个数或者顺序中至少有一个不同 | 无要求 | 无要求 |
重写 | 父子类 | 必须相同 | 必须相同 | 子类的返回类型相同或者是父类的返回类型的子类 | 不能缩小父类的访问范围 |
3.多态
1.基本介绍
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。
2.具体体现
1.方法的多态
重写和重载体现多态。
//重载
public int sum(int a,int b);
public int sum(int a,int b,int c);
//重写
class A{
public void say(){ System.out.printf("A是父类~");}
}
class B extends A{
public void say() { System.out.printf("B是子类~");}
}
2.对象的多态(重点)
一个对象的编译类型和运行类型可以不一致。
编译类型在定义对象时,就确定了,不能改变,运行类型可以变化。
定义时 = 的左边是编译类型,右边是运行类型。
Animal animal = new Dog();//Animal是编译类型,Dog是运行类型
animal = new cat();//编译类型不能改变,运行类型可变
3.多态注意事项和细节讨论
1.多态的前提
两个对象(类)存在继承关系。
2.属性
没有重写,属性的值是看编译类型。
public class Tes {
public static void main(String[] args) {
A a = new B();
System.out.println(a.n);
//这里输出的是10,因为属性的值要看编译类型,a的编译类型为A,所以输出的是A的属性
}
}
class A {
public int n = 10;
}
class B extends A {
public int n = 20;
}
3.instance of
比较操作符,是用来判断对象的运行类型是否为某类型或者某类型的子类型。
4.多态的向上转型
本质:父类的引用指向了子类的对象。
语法:父类类型 引用名 = new 子类类型();
特点:可以调用父类中的所有成员(遵守访问权限),不能调用子类的特有成员,但最终的运行结果看运行类型的具体实现,能调用那些成员看编译类型,具体运行看运行类型。
5.多态的向下转型
语法:子类类型 引用名 = (子类类型) 父类引用;
只能强转父类的引用,不能强转父类的对象。
要求父类的引用必须指向的是当前目标类型的对象。
可以调用子类类型中的所有成员。
public class Test {
public static void main(String[] args) {
//向上转型
A a = new B();
a.say();
//a.abc(); 方法abc为运行类型B类特有的编译类型A类不能调用
//调用那些成员看编译类型,具体运行看运行类型
//向下转型
B b = (B) a;
//父类的引用必须指向的是当前目标类型的对象
b.abc();
}
}
class A {
public void say (){
System.out.println("A类的say()被调用");
}
}
class B extends A {
public void abc(){
System.out.println("B类的abc()被调用");
}
public void say (){
System.out.println("B类的say()被调用");
}
}
运行结果如下:
6.Java动态绑定机制
当调用对象的方法时,该方法会与该对象的内存地址/运行类型绑定。
当调用对象的属性时,不存在动态绑定机制。
public class Test {
public static void main(String[] args) {
A a = new B();//A为编译类型,B为运行类型
System.out.println(a.sum());
//B类中sum()没注释前 结果为 40 注释后结果为 30
//注释后会调用A类的sum方法但因为动态绑定机制sum中的getI方法调用的是B中的
System.out.println(a.sum1());
//B类中sum()没注释前 结果为 30 注释后结果为 20
//调用A类的sum1,i由于是调用对象的属性,不存在动态绑定机制,哪里声明就调用哪的i=10
}
}
public class A {
public int i = 10;
public int sum() {
return getI() + 10;
}
public int sum1() {
return i + 10;
}
public int getI() {
return i;
}
}
public class B extends A {
public int i = 20;
// public int sum() {
// return i + 20;
// }
// public int sum1() {
// return i + 10;
// }
public int getI() {
return i;
}
}
7.多态数组多态参数
多态数组
数组的定义类型为父类类型,里面保存的实际元素类型为子类类型和父类类型。
多态参数
方法定义的形参类型为父类类型,实际类型允许为子类类型。
示例:父类为Employee,子类为Worker和Manage
public class Test {
public static void main(String[] args) {
Test test = new Test();
Employee employee = new Employee("Bob",3000);
Employee[] employee1 = new Employee[5];//多态数组 父类定义
Worker worker = new Worker("Tom",5000);
Worker worker1 = new Worker("Kit",6000);
Manager manager = new Manager("Smith",12000,100000);
Manager manager1 = new Manager("Sab",15000,110000);
employee1[0]=worker;//可放子类
employee1[1]=worker1;
employee1[2]=manager;
employee1[3]=manager1;
employee1[4]=employee;//也可放本类
test.showEmpAnnal(worker);//多态参数 实参可为子类
test.showEmpAnnal(manager);
test.testwork(employee1);
}
public void showEmpAnnal(Employee e){//多态参数 形参为父类
System.out.println(e.getName()+" 的年薪为:"+e.getAnnual());
}
public void testwork(Employee e[]){
for (int i = 0; i <5 ; i++) {
if(e[i] instanceof Worker){
((Worker) e[i]).work();//向下转型
}else if(e[i] instanceof Manager){
((Manager) e[i]).manage();
}else {
System.out.println("员工 "+e[i].getName()+" 正在摸鱼!");
}
}
}
}
来源:https://blog.csdn.net/m0_54024106/article/details/124440757


猜你喜欢
- 类和结构是.NET Framework中的同样类型系统的两种基本构造。两者在本质上都属于数据结构,封装这一组整体作为一个逻辑单位的数据和行为
- CLR支持两种类型:引用类型和值类型。 引用类型总是从托管堆上分配的。 c#中的New操作符返回对象的内存地址。 引用对象的注意点: 1、内
- 一、TimerTimer是Android直接启动定时器的类,TimerTask是一个子线程,方便处理一些比较复杂耗时的功能逻辑,经常与han
- private string CheckCidInfo(string cid) &
- 当前使用的IDEA版本是2020.1。随着IDEA版本的升级,有些插件不再支持,而有些插件变成了收费插件,这些插件将不再推荐。以下列举的,都
- 大多数情况下你不需要访问者模式,但当一旦需要访问者模式时,那就是真的需要它了,这是设计模式创始人的原话。可以看出应用场景比较少,但需要它的时
- 本文实例讲述了C#实现HTTP上传文件的方法。分享给大家供大家参考。具体实现方法如下:发送文件代码如下:/// <summary>
- 前言日志,在我们开发中是一个非常重要的话题,良好的日志打印可以帮助我们快速的定位问题,可能现在我们开发用到最多的日志框架就是slf4j了,但
- 一 点睛注解若想发挥更大作用,还需借助反射机制之力。通过反射,可以取得一个方法上声明的注解的全部内容。一般有两种需求:1 
- 1.easy-captcha工具包生成验证码的方式有许多种,这里选择的是easy-captcha工具包。github开原地址为:easy-c
- 快速排序类using System;using System.Data;using System.Config
- 一、运算符运算符包括下面几种:算术运算符赋值运算符比较运算符逻辑运算符位运算符三目运算符最不常用的是位运算符,但也是最接近计算机底层的。1、
- 本文实例为大家分享了JavaWeb实现注册用户名检测的具体代码,供大家参考,具体内容如下案例说明实现一个可以异步获取用户名是否被注册的小案例
- Bottom SheetBottom Sheet 是 Design Support Library 23.2 版本引入的一个类似于对话框的控
- 先给大家简单介绍下mybatisMyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的J
- 简介本文主要讲解java代码如何利用selenium操作浏览器上传和下载文件代码教程。上传文件常见的 web 页面的上传,一般使用 inpu
- 经测试,是环绕通知改变了返回值,切面方法需要有返回值,来代替被代理方法返回结果改成如下即可:@Around("point_upda
- ServletWebServerApplicationContext实现了父类AbstractApplicationContext的onRe
- spring in action第三版读书笔记spring3.0引入了spring expression language(spel)语言,
- 本文实例讲述了C#使用foreach语句遍历队列(Queue)的方法。分享给大家供大家参考。具体如下:using System;using