首页 > 编程语言 >JavaSE复习day4

JavaSE复习day4

时间:2022-12-09 01:55:06浏览次数:68  
标签:复习 day4 子类 void 接口 person JavaSE 方法 public

JavaSE复习day4

胡家伟

13.多态

基本介绍

概念

  • 多态是方法或对象具有多种形态,是面向对象的第三大特征。
  • 多态的前提是两个对象(类)存在继承关系,多态是建立在封装和继承基础上的。

多态的具体实现

对象的多态是多态的核心和重点。

规则

  • 一个对象的编译类型和运行类型可以不一致。
  • 编译类型在定义对象时就确定了,不能改变,而运行类型是可以变化的。
  • 编译类型看定义对象时 = 的左边,运行类型看 = 右边。
//人类
public void say(){
    System.out.println("im a person");
}
//学生类
@Override
public void say() {
    System.out.println("im a student");
}
//主方法
Person person = new Student();
person.say();

输出
im a student

多态的转型

向上转型

  1. 本质:父类的引用指向子类的对象

  2. 特点:

    • 编译类型看左边,运行类型看右边
    • 可以调用父类的所有成员(需遵守访问权限)
    • 不能调用子类的特有成员
    • 运行效果看子类的具体实现
  3. 语法:

    父类类型 引用名 = new 子类类型();

//人类
public void say(){
    System.out.println("im a person");
}
//学生类
@Override
public void say() {
    System.out.println("im a student");
}
public void study(){
    System.out.println("im studying");
} 
//主方法
Person person = new Student();
person.say();
person.study();//无法调用,编译期报错

输出
im a student

向下转型

  1. 本质:一个已经向上转型的子类对象,将父类引用转为子类引用

  2. 特点:

    • 只能强制转换父类的引用,不能强制转换父类的对象
    • 要求父类的引用必须指向的是当前目标类型的对象
    • 当向下转型后,可以调用子类类型中所有的成员
  3. 语法:

    子类类型 引用名 = (子类类型) 父类引用;

//人类
public void say(){
    System.out.println("im a person");
}
//学生类
@Override
public void say() {
    System.out.println("im a student");
}
public void study(){
    System.out.println("im studying");
}
//主方法
Person person = new Student();
Student student = (Student) person;
student.say();
student.study();

输出
im a student
im studying

转型异常

使用强转时,可能出现异常

//异常演示
//向上转型
Person person = new Student();
//调用Student的say
person.say();
//向下转型
Worker worker = (Worker) person;
//运行报错
worker.say();

输出
im a student
Exception in thread "main" java.lang.ClassCastException

这段代码在运行时出现了 ClassCastException 类型转换异常原因是 Student 类与 Worker类 没有继承关系,因此所创建的是Student 类型对象在运行时不能转换成 Worker 类型对象。

instanceof比较操作符

为了避免上述类型转换异常的问题,我们引出 instanceof 比较操作符,用于判断对象的类型是否为XX类型或XX类型的子类型

Person person = new Student();
person.say();
if(person instanceof Student){
    Student student = (Student) person;
    student.study();
    //可以把这两句简写为 ((Student) person).study();
}
if(person instanceof Worker){
    Worker worker = (Worker) person;
    worker.salary();
    //可以把这两句简写为 ((Worker) person).salary();
}

输出
im a student
im studying

动态绑定

  • 当调用对象方法的时候,该方法会和该对象的运行类型绑定

  • 当调用对象属性时,没有动态绑定机制,即哪里声明,哪里使用

    思考

//向上转型(自动类型转换)
//程序在编译阶段只知道 person 是 Person 类型
//程序在运行的时候才知道堆中实际的对象是 Student 类型
Person person = new Student();
//程序在编译时 person 被编译器看作 Person 类型
//因此编译阶段只能调用 Person 类型中定义的方法
//在编译阶段,person 引用绑定的是 Person 类型中定义的 say 方法(静态绑定)
//程序在运行的时候,堆中的对象实际是一个 Student 类型,而 Student 类已经重写了 say 方法
//因此程序在运行阶段对象中绑定的方法是 Student 类中的 say 方法(动态绑定)
person.say();

输出
im a student

应用

多态数组

数组的定义类型为父类类型,里面保存的实际元素类型为子类类型

Person[] people = new Person[3];
people[0] = new Person();
people[1] = new Student();
people[2] = new Worker();
for (Person person : people) {
    person.say();
}

输出
im a person
im a student
im a worker

多态参数

方法定义的形参类型父类类型,实参类型允许为子类类型

public class Test {
    public static void main(String[] args) {
   
        Student student = new Student();
        Worker worker = new Worker();
        
        Test test =new Test();
        
        test.test(student);
        test.test(worker);
        
    }
    //定义方法test,形参为 Person 类型(形参是父类)
    //功能:调用学生的study或工人的salary方法
    public void test(Person person){
        if(person instanceof Student){
            ((Student) person).study();//向下转型
        }
        if(person instanceof Worker){
            ((Worker) person).salary();//向下转型
        }
    }
}

输出
im studying
my salary is 10000

多态的优点

  • 代码更加灵活:无论右边new的时候换成哪个子类对象,等号左边调用方法都不会变化。
  • 提高程序的拓展性:定义方法的时候,使用父类类型作为参数,将来使用时,使用具体的子类类型操作

14.抽象类

概念

父类中的方法,被他的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类

抽象方法

使用abstrct关键字修饰的方法就是抽象方法,值得注意的是,抽象方法只包含一个方法名,没有方法体。

public abstract void run()

抽象类

如果一个类包含抽象方法,那么该类必须是抽象类。

public abstract class Animal {
    public abstract void run();
}

抽象类的使用

继承抽象类的子类必须重写父类所有的抽象方法否则,该子类也必须声明为抽象类。最终,必须有子类实现该父类的抽象方法。

//动物抽象类
public abstract class Animal {
    public abstract void run();
}
//猫类
public class Cat extends Animal{
    @Override
    public void run() {
        System.out.println("A cat is running");
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        new Cat().run();
    }
}
输出
A cat is running

没有抽象方法的抽象类

抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。

//动物抽象类
public abstract class Animal {
    public Animal(){
        System.out.println("动物产生了");
    }
}
//猫类
public class Cat extends Animal{
}
//测试类
public class Test {
    public static void main(String[] args) {
        new Cat();
    }
}

输出
动物产生了

从上面的例子可以看出,子类的构造方法需要访问父类的构造方法,与正常类相同。

抽象类和普通类的区别

  • 抽象类不能被实例化(规定)。
  • 抽象类中可以定义抽象方法,普通类不可以。

抽象方法和普通方法的区别

  • 普通的方法可以被子类重写也可以不重写,总之子类可以有选择性地重写或者不重写父类中的普通方法。
  • 抽象方法必须被子类实现(重写)。

15.接口

概述

  • 接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法,包含抽象方法,默认方法和静态方法。

  • 接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型

    引用数据类型:数组,类,接口。

接口格式

public interface 接口名称 {
// 抽象方法
// 默认方法
// 静态方法
}

抽象方法

使用abstract修饰,可以省略

public abstract void method();
//public abstract 可以省略

默认方法

使用 default 修饰,不可省略,供子类调用或者子类重写

public default void method1() {
    // 执行语句
}

静态方法

使用 static 修饰,供接口直接调用

public static void method2() {
    // 执行语句
}

实现

类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements 关键字。
非抽象子类实现接口:

  • 必须重写接口中所有抽象方法。
  • 继承了接口的默认方法,即可以直接调用,也可以重写。

实现格式

class 类名 implements 接口名 {
// 重写接口中抽象方法【必须】
// 重写接口中默认方法【可选】
}

抽象方法的实现

接口中的抽象方法必须全部实现。

//行为接口
public interface Action {
    public abstract void run();
}
//猫类
public class Cat implements Action{
    @Override
    public void run() {
        System.out.println("A cat is running");
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.run();
    }
}
输出
A cat is running

默认方法的实现

可以继承,可以重写,二选一,但是只能通过实现类的对象来调用。

继承默认方法

继承时,直接调用就可以。

//行为接口
public interface Action {
    public default void eat() {
        System.out.println("进食");
    }
}
//猫类
public class Cat implements Action{
}
//测试类
public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat();
    }
}
输出
进食

重写默认方法

//行为接口
public interface Action {
    public default void eat() {
        System.out.println("进食");
    }
}
//猫类
public class Cat implements Action{
    @Override
    public void eat() {
        System.out.println("吃猫粮");
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat();
    }
}
输出
吃猫粮

静态方法的实现

静态与.class 文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用。

//行为接口
public interface Action {
    public static void die() {
        System.out.println("ta死了");
    }
}
//猫类
public class Cat implements Action{
}
//测试类
public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        //cat.die();// 错误 无法继承方法,也无法调用
        Action.die();
    }
}
输出
ta死了

接口的多实现

在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。

实现格式

class 类名 [extends 父类名] implements 接口名1,接口名2,接口名3... {
    // 重写接口中抽象方法【必须】
    // 重写接口中默认方法【不重名时可选】
}
  • 接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次。
  • 接口中,有多个默认方法时,实现类都可继承使用。如果默认方法有重名的,必须重写一次。
  • 接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。

优先级问题

当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执行父类的成员方法。(只说明默认方法是因作为抽象方法必须要重写,静态方法则是只能使用接口名调用)

//行为接口
public interface Action {
    public default void test(){
        System.out.println("Action");
    }
}
//动物类
public class Animal {
    public void test(){
        System.out.println("Animal");
    }
}
//猫类
public class Cat extends Animal implements Action{
}
//测试类
public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.test();
    }
}
输出
Animal

接口的多继承

一个接口能继承另一个或者多个接口,这和类之间的继承比较相似。接口的继承使用 extends 关键字,子接口继承父接口的方法。如果父接口中的默认方法有重名的,那么子接口需要重写一次。

public interface A {
    public default void method(){
        System.out.println("A");
    }
}
public interface B {
    public default void method(){
        System.out.println("B");
    }
}
public interface C extends A,B{
    @Override
    default void method() {
        System.out.println("C");
    }
}

注意

  1. 接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static final修饰。
  2. 接口中,没有构造方法,不能创建对象。
  3. 接口中,没有静态代码块。

标签:复习,day4,子类,void,接口,person,JavaSE,方法,public
From: https://www.cnblogs.com/chiawei/p/16967880.html

相关文章

  • 期末复习-操作系统与linux管理
    liunx操作系统第一章操作系统引论p2-p51.什么是操作系统操作系统是管理和控制着计算机系统中的各种软硬件资源,合理地组织计算机的工作流程,为用户使用计算机提供接口......
  • 进入python的世界_day48_Django初始
    一、纯手撸web框架1.先搭服务端​ 1.因为浏览器就可以当成C\S开发架构的C客户端,我们先写一个简单的服务端importsocketserver=socket.socket()#这里括号不改任......
  • 操作系统——期末复习题
    单选题1、在下列系统中,(B)是实时系统。A、计算机激光照排系统B、航空定票系统C、办公自动化系统D、计算机辅助设计系统2、在单一处理器上执行程序,多道程序的执行是......
  • day46 6-14 mybatis#{}与$的区别、一二级缓存 & 6-15 事务管理 & SSM三大框架简单回顾
    mybatis——OGNL表达式(mapperxml文件内if标签内)OGNL全称Object-GraphNavigationLanguage,是Java中的一个开源的表达式语言,用于访问对象数据。也是mybatis实现动态......
  • Angular 复习与进阶系列 – 谈谈 ASP.NET Core & Angular & React 在业务开发上各自的
    前言日常,我的开发都围绕着ASP.NETCore和Angular.这篇想聊聊它们各自的特点和解决问题的方式. 以及最重要的,我们该在什么时候使用何种方案更为妥当.  浅谈......
  • Angular 复习与进阶系列 – 目录
    请按顺序阅读1. 关于本系列&初识Angular2 GetStarted3. DependencyInjection依赖注入......
  • JavaSE复习day3
    JavaSE复习day3胡家伟10.匿名对象&高内聚低耦合匿名对象概念匿名对象就是没有名字的对象,创建对象时,只在堆内存中开辟空间,不会在栈内存中开辟空间存储堆内存空间的地址......
  • 进入python的世界_day47_前端——JQ补充、bootstrap前端框架
    一、jQuery补充​ 说在最前面,如果想把JQ对象赋值给一个变量名,起名字依旧要讲究,建议名字前加$,这样别人一看就知道是JQ对象1.筛选器//1.属性选择器$('username')//......
  • CSS Margin中5个经典布局解决方案,重难点知识,记得收藏复习
    前几天我在面试前端开发同学的时候,有问到关于margin基础布局相关内容的过程中,发现很多同学基本解释不清楚,今天刚好有点时间就整理了一篇笔记出来。就以下5点在CSS布局经常......
  • Day1 JAVASE
    构造器:1.和类名相同2.没有返回值作用:1.new本质在调用构造方法2.初始化对象的值注意点:1.在创建类的时候就会有一个构造器去初始化对象的值,因此new才能创建一个实例......