【Java基础】面向对象(三)

  • 一、多态
    • 概念
    • 引用类型转换
  • 二、Object类
    • 概述
    • 常用方法
  • 三、抽象类
    • 抽象类与抽象方法的定义
    • 注意事项
  • 四、接口
    • 概述
    • 接口定义
      • 含有抽象方法
      • 含有默认方法和静态方法
      • 含有私有方法和私有静态方法
    • 接口实现
      • 一个类可以实现多个接口
      • 一个类继承类同时可以实现接口
      • 接口的多继承
    • 和抽象类的区别
    • 接口的好处

一、多态

概念

多态是继封装、继承之后,面向对象的第三大特性。

生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞
机,飞起来也是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。

多态 (多种形态) 是同一个行为具有多个不同表现形式或形态的能力,多态就是同一个接口使用不同的实例而执行不同操作

  1. 父类类型 变量名 = new 子类对象;
  2. 变量名.方法名();
  3. 父类类型:指子类对象继承的父类类型,或者实现的父接口类型。

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去
调用子类的重写方法。

使用多态的好处是,可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。

示例:

public class Animal {//成员变量private String name;private int age;public void run() {System.out.println("动物跑起来......");}
}
public class Cat extends Animal {//新增的属性private String color;@Overridepublic void run() {System.out.println("猫跑起来.....");}//新增的方法public void catchMouse() {System.out.println("抓老鼠......");}}
public class Dog extends Animal {//新增的属性private String kind;@Overridepublic void run() {System.out.println("狗狗跑起来......");}//新增的方法public void keepDoor() {System.out.println("看门........");}
}
package com.tuling.part1;public class TestAnimal {public static void show(Animal animal) {//会根据传入的参数的不同,调用不同的子类重写的方法,体现了多态的特征animal.run();//分别调用子类的重写,体现了多态的特征}public static void main(String[] args) {show(new Animal());show(new Cat());//以Cat为对象调用show方法show(new Dog());//以Dog为对象调用show方法}
}

父子对象之间的转换分为了向上转型和向下转型 , 它们区别如下:

  • 向上转型: 通过子类对象 (小范围) 实例化父类对象 (大范围),这种属于自动转换。

注意: 其意义在于当我们需要多个同父的对象调用某个方法时,通过向上转换后,则可以确定参
数的统一,方便程序设计。

对象的向上转型(安全的):会失去子类新增
子类对象,被看做了父类的类型,那么就不能访问子类的新增, 只能访问父类的属性和方法,以及子类重写。

示例:

引用类型转换

public class TestAnimal {public static void show(Animal animal) {animal.run();//没有办法访问子类新增的方法
//        animal.catchMouse();
//        animal.keepDoor();}public static void main(String[] args) {//Java面向对象的多态Animal cat = new Cat();//向上转型System.out.println("------------");Animal animal = new Animal();System.out.println("------------");Animal dog = new Dog();//向上转型System.out.println("===========================");show(cat);//访问子类重写System.out.println("----------------");show(animal);System.out.println("----------------");show(dog);//访问子类重写}
}
  • 向下转型: 通过父类对象 (大范围) 实例化子类对象 (小范围),这种属于强制转换。

为什么要转型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不
能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。

instanceof关键字
在 Java 中,向下转型是为了通过父类强制转换为子类,从而来调用子类独有的方法,为了保证向下转型的顺利完成,在 Java 中提供了一个关键字 instanceof, 通过 instanceof 可以判断某对象是否是某类的实例,如果是则返回 true, 否则为 false。

instanceof:判断某个对象是否是某个类的实例:类以及继承的父类。

示例:

public class TestAnimal {public static void show(Animal animal) {animal.run();//没有办法访问子类新增的方法
//        animal.catchMouse();
//        animal.keepDoor();if (animal instanceof Cat) {Cat catObj = (Cat) animal;//向下转型catObj.catchMouse();} else if (animal instanceof Dog) {Dog dogObj = (Dog) dogobj;//向下转型dogObj.keepDoor();}}public static void main(String[] args) {//Java面向对象的多态Animal cat = new Cat();//向上转型System.out.println("------------");Animal animal = new Animal();System.out.println("------------");Animal dog = new Dog();//向上转型System.out.println("===========================");show(cat);System.out.println("----------------");show(animal);System.out.println("----------------");show(dog);}
}

父类 对象1 = new 父类();
子类 对象2 = new 子类();
父类 对象3 = new 子类();

看一个对象能够访问哪些成员,看=左边是定义的是什么类型

  • 父类类型:只能访问父类的属性和方法
  • 子类类型:可以访问父类的属性和方法,子类新增,子类重写

看一个对象最终访问哪个方法,看=右边是什么类型的对象

  • 父类对象:父类属性和方法
  • 子类对象:父类的属性和方法,以及子类重写的方法

二、Object类

概述

所有的类,都是以继承结构存在的。如果没有显式的父类,默认继承Object类。

class Person{}
相当于
class Person extends Object {}
class Student extends Person {}//学生类继承Person类

  • 超类、基类,所有类的直接或间接父类,位于继承树的最顶层。
  • 任何类,如没有书写extends显式继承某个类,都默认直接继承Object类,否则为间接继承。
  • Object类中所定义的方法,是所有对象都具备的方法。
  • Object类型可以存储任何对象。
  • 作为参数,可接受任何对象
  • 作为返回值,可返回任何对象

常用方法

getClass()

public final Class<?> getClass(){...}
//返回引用中存储的实际对象类型
//通常用于判断两个引用中实际存储对象类型是否一致

hashCode()

public int hashCode(){...}
//返回该对象的十进制的哈希码值
//哈希算法根据对象的地址或字符串或数字计算出来的int类型的数值

toString()

 public String toString(){...}//返回该对象的字符串表示(表现形式)//可以根据程序需求覆盖该方法,如:展示对象各个属性值

equals()

public boolean equals(Object obj){...}
//默认实现为(this == obj),比较两个对象地址是否相同
//可进行覆盖,比较两个对象的内容是否相同

equals重写步骤:

  1. 比较两个引用是否指向同一个对象。
  2. 判断obj是否为null。
  3. 判断两个引用指向的实际对象类型是否一致。
  4. 强制类型转换。
  5. 依次比较各个属性值是否相同。

示例:

import java.util.Objects;public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = 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;}//    @Override
//    public String toString() {//        return "name:" + name + ";age" + age;
//    }@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}/*** equals重写步骤:* 比较两个引用是否指向同一个对象。* 判断obj是否为null。* 判断两个引用指向的实际对象类型是否一致。* 强制类型转换。* 依次比较各个属性值是否相同。*/
//    @Override
//    public boolean equals(Object obj){//        if(this==obj){//            return true;
//        }
//        if(obj==null||this.getClass()!=obj.getClass()){//            return false;
//        }
//        //向下转型是为了调用子类新增的属性和方法
//        Person person = (Person) obj;
//
//        if(this.getName().equals(person.getName())&&this.getAge()==person.getAge()){//            return true;
//        }
//
//
//        return false;
//    }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
public class TestPerson {public static void main(String[] args) {Person p1 = new Person("wowo", 23);Class<? extends Person> aClass = p1.getClass();//返回引用中存储的实际对象类型。System.out.println("aClass:" + aClass);Person p2 = new Person();Class<? extends Person> aClass1 = p2.getClass();System.out.println("aClass1:" + aClass1);Student stu = new Student();System.out.println(stu.getClass());System.out.println("-----------------------------------------------");System.out.println("p1.hashCode:" + p1.hashCode());//返回该对象的十进制的哈希码值。System.out.println("p2.hashCode():" + p2.hashCode());System.out.println("-------------------------------");System.out.println("p1:" + p1.toString());//有时候我们不只想看这个对象的全类名,我们想看这个对象的成员变量的值System.out.println("------------------------------------");Person person1 = new Person("zhangsan", 23);Person person2 = new Person("zhangsan", 23);System.out.println("person1 == person2:" + (person1 == person2));//==比较的是内存地址System.out.println("person1.equals(person2):" + (person1.equals(person2)));//我们比较两个对象,其实我们是想比较一下对象的成员变量的值是否相等}
}

finalize()方法

  • 当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列。
  • 垃圾对象:没有有效引用指向此对象时,为垃圾对象。
  • 垃圾回收: 由GC销毁垃圾对象,释放数据存储空间。
  • 自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
  • 手动回收机制:使用System.gc(); 通知JVM执行垃圾回收。

示例:

public class Student extends Person {@Overrideprotected void finalize() throws Throwable {System.out.println("Student finalize()方法。。。。。");}
}
public class TestFinalize {public static void main(String[] args) {new Student();new Student();new Student();System.out.println("-------------");//手动GCSystem.gc();System.out.println("回收垃圾");}
}

三、抽象类

程序是用来模拟现实世界、解决现实问题的;现实世界中存在的都是“动物”具体的子类对象,并不存在“动物”对象,所以,Animal不应该被独立创建成对象。

将子类的共同特征进行抽取,抽象成一个父类。如果有的功能在父类中定义了,但是没有具体的实
现,那么可以定义为抽象的,等待子类实现即可。

作用:

  1. 可被子类继承,提供共性属性和方法。
  2. 可声明为引用,更自然的使用多态。

抽象类 :包含抽象方法的类;

  • 被abstract修饰的类,称为抽象类;
  • 抽象类意为不够完整的类、不够具体的类;

抽象方法 : 没有方法体的方法。

抽象类与抽象方法的定义

  • 抽象类定义的格式
public abstract class 类名 {}
  • 抽象方法定义的格式
public abstract 返回值类型 方法名(参数);

示例:

//抽象类
public abstract class Animal {//有抽象方法一定要定义成抽象类//成员变量private int age;private String color;//无参构造函数public Animal() {}//有参构造函数public Animal(int age, String color) {this.age = age;this.color = color;}//抽象方法public abstract void eat();//抽象方法public abstract void run();//成员方法public void print() {System.out.println("name.....");}//类方法public static void test() {}
}
//子类,实现父类中定义的抽象方法
public class Cat extends Animal {@Overridepublic void eat() {System.out.println("猫吃鱼.....");}@Overridepublic void run() {System.out.println("猫跑起来....");}
}

注意事项

  • 抽象类和抽象方法都需要被 abstract 修饰。抽象方法一定要定义在抽象类中
  • 抽象类不可以直接创建对象,原因:调用抽象方法没有意义。
  • 只有覆盖了抽象类中所有的抽象方法后,其子类才可以创建对象,否则该子类还是一个抽象类。
  • 之所以继承抽象类,更多的是在思想,是面对共性类型操作会更简单
  • 抽象类不允许被实例化,因为可能包含有抽象方法,必须等待子类来继承,并且实现抽象方法。子类积极的实现父类中的抽象方法,但是如果没有全部实现,那么子类也是抽象的,要再等子类来继承,并且实现抽象方法。

重要的结论:抽象类和类比较,除了不能实例化之外,没有任何区别。

  1. 抽象类一定是个父类 ?
  • 是的,因为不断抽取而来的。
  1. 抽象类中是否可以不定义抽象方法?
  • 是可以的,那这个抽象类的存在到底有什么意义呢?
  • 不让该类创建对象,方法可以直接让子类去使用。
  1. abstract关键字,不能和static,private,final等关键字搭配使用

abstract与static:

层面 内容
what abstract用来声明抽象方法,抽象方法没有方法体,不能被直接调用,必须在子类overriding后才能使用;static用来声明静态方法,静态方法可以被类及其对象调用
how static与abstract不能同时使用
why 用static声明方法表明这个方法在不生成类的实例时可直接被类调用,而abstract方法不能被调用,两者矛盾

四、接口

概述

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

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

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

接口就是一种约定、契约,一种规范。例如,生活中的USB接口,鼠标、键盘、U盘等只要遵循了USB接口规范,那么就可以正常使用。

接口定义

含有抽象方法

抽象方法:使用 abstract 关键字修饰,可以省略,没有方法体,供子类实现使用。
代码如下:

public interface InterFaceName {public abstract void method();
}

含有默认方法和静态方法

默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。
静态方法:使用 static 修饰,供接口直接调用。
代码如下:

public interface InterFaceName {public default void method() {// 执行语句}public static void method2() {// 执行语句 }
}

含有私有方法和私有静态方法

(注意:需要JDK9及以上才可以定义)
私有方法:使用 private 修饰,供接口中的默认方法或者静态方法调用。
代码如下:

public interface InterFaceName {private void method() {// 执行语句}
}

接口实现

接口要有实现类来实现接口中的抽象方法。
子类和抽象父类的关系:extends
实现类和接口的关系:implements

类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。

非抽象子类实现接口:

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

实现格式:

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

注意:

  • 接口中抽象方法必须全部实现;
  • 接口中默认方法可以继承,可以重写,二选一,但是只能通过实现类的对象来调用;
  • 接口中静态方法只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用。
    示例:
//接口
public interface Usb {//静态的常量public static final double PI = 3.14;//定义的变量会默认加上public static final,故可省略不写//抽象方法;public abstract void start();//定义的抽象方法会默认加上public abstract,故可省略不写public abstract void stop();//默认方法public default void fun1() {//定义的默认方法会默认加上public,故可省略不写System.out.println("默认方法......");}//静态方法public static void fun2() {//定义的静态方法会默认加上public,故可省略不写System.out.println("静态方法......");}//JDK9及以上可定义私有方法
//    private void fun3(){//        System.out.println("私有方法");
//    }}
public class Mouse implements Usb {@Overridepublic void start() {System.out.println("鼠标开始工作");}@Overridepublic void stop() {System.out.println("鼠标结束工作");}//重写了@Overridepublic void fun1() {System.out.println("鼠标的默认方法....");}
}
public class Keyboard implements Usb {@Overridepublic void start() {System.out.println("键盘开始工作...");}@Overridepublic void stop() {System.out.println("键盘结束工作...");}}

一个类可以实现多个接口

  • 接口最重要的体现:解决单继承的弊端,将多继承这种机制在Java中通过多实现完成了。
    示例:
public interface Fu1 {void fun1();
}
public interface Fu2 {void fun2();
}
class Sun implements Fu1, Fu2 {@Overridepublic void fun1() {}@Overridepublic void fun2() {}}
  • 多继承的弊端是什么?

多继承时,当多个父类中有相同的功能时,子类调用会产生不确定性。其实核心原因就是在于多继承父类中功能有主体,而导致调用运行时,不确定运行哪个主体内容。

  • 为什么多实现能解决这一弊端呢?

因为接口中的功能都没有方法体,由子类来明确。

一个类继承类同时可以实现接口

  • 类与类之间可以通过继承产生关系,接口和类之间可以通过实现产生关系。当一个类已经继承了一个父类,它又需要扩展额外的功能,这时接口就派上用场了。
  • 子类通过继承父类扩展功能,通过继承扩展的功能都是子类应该具备的基础功能。如果子类想要继续扩展其他类中的功能,这时就需要通过实现接口来完成。
  • 接口的出现解决了单继承的局限性。父类中定义的事物的基本功能,接口中定义的事物的扩展功能。

示例:

public class Fu {}
//一个类可以实现多个接口
//一个类继承类同时可以实现接口
//接口的多继承
public class Zi extends Fu implements Fu1, Fu2 {@Overridepublic void fun1() {}@Overridepublic void fun2() {}}

接口的多继承

  • 多个接口之间可以使用 extends 进行继承

示例:

public interface Children extends Fu1, Fu2 {void childFu1();
}
  • 在开发中如果多个接口中存在相同方法,这时若有个类实现了这些接口,那么就要实现接口中的方法,由于接口中的方法是抽象方法,子类实现后也不会发生调用的不确定性。

和抽象类的区别

相同点:

  • 都存在抽象方法;
  • 不能创建对象,不能实例化;
  • 可以作为引用类型;
  • 具备Object类中所定义的方法。

不同点:

  • 所有属性都是公开静态常量,隐式使用public static final修饰;
  • 所有方法都是公开抽象方法,隐式使用public abstract修饰;
  • 没有构造方法、动态代码块、静态代码块。

接口的好处

  • 接口的出现降低了耦合性
  • 设计与实现完全分离,更容易更换具体实现;
  • 更容易搭建程序框架。

【Java基础】面向对象(三)相关推荐

  1. Java基础-面向对象第二特征之继承(Inheritance)

    Java基础-面向对象第二特征之继承(Inheritance) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.继承的概述 在现实生活中,继承一般指的是子女继承父辈的财产.在程序 ...

  2. Java 基础 - 面向对象(不错N多教程集合)

    著作权归https://pdai.tech所有. 链接:Java 基础 - 面向对象 | Java 全栈知识体系 本文主要介绍Java OOP 面向对象基础和相关类图.@pdai Java 基础 - ...

  3. Java校招笔试题-Java基础部分(三)

    导语   Java 面试题集2021版 Java基础部分三 26.说说has a 与is a的区别 27.一个房间里有一把椅子,椅子有四条腿,房子和椅子是什么关系,椅子和椅子腿是什么关系? 28.什么 ...

  4. Java实习生常规技术面试题每日十题Java基础(三)

    目录 1.是否可以从一个static方法内部发出对非static方法的调用? 2.Integer与int的区别? 3.Overload和Override的区别.参数列表相同,返回值不同的方法,是否是重 ...

  5. 基于Java基础-面向对象实现植物大战僵尸简易版

    基于Java基础-面向对象实现植物大战僵尸简易版 前言 游戏设计 游戏对象 游戏内容 游戏优化 放置植物的优化 移除植物的优化 游戏可玩性的优化 添加游戏背景音乐 后续优化 源码分享 前言 从零开始学 ...

  6. (20)Java基础 --面向对象(1)

    目录 面向对象 一.概述 二.生活举例 三.类与对象的关系 四.类的构成 五.类的定义 类的属性 类的方法 创建实例(对象) 内存分配图 六.对象的基本使用 七.局部变量与成员变量的区别 八.面向对象 ...

  7. JAVA基础(三)-面试篇

    系列文章目录 JAVA基础系列只是列出博主在刷牛客JAVA转项练习的总结 JAVA基础篇一:继承.多态.导包问题 .排序.变量初始值等 JAVA基础篇二:父子类问题.Map空值问题.异常.真假问题等 ...

  8. JAVA基础第三章 面向对象进阶--多态等

    3.1变量及其传递 1.变量实际是内存空间.引用型变量里存储的是引用,可以理解为对象实体的地址.指针.句柄.总之,通过这个引用我们就可以操纵这个对象. 例: MyDate m,n;  //定义两个My ...

  9. Java基础-----面向对象

    文章目录 面向对象 类与对象 匿名对象 创建对象的内存分析 栈(stack) 堆(heap) 方法区 PC寄存器 本地方法栈 内部类 成员内部类 局部内部类 匿名内部类 静态内部类 包装类 拆箱和装箱 ...

  10. java基础面向对象_Java基础面向对象

    一.面向过程的思想和面向对象的思想 面向对象和面向过程的思想有着本质上的区别,作为面向对象的思维来说,当你拿到一个问题时,你分析这个问题不再是第一步先做什么,第二步再做什么,这是面向过程的思维,你应该 ...

最新文章

  1. [给12306支招]取消车票预订-采用全额预售(充值)
  2. 数据不平衡、不平衡采样、调整分类阈值、过采样、欠采样、SMOTE、EasyEnsemble、加入数据平衡的流程、代价敏感学习BalanceCascade、
  3. 用iptables做IP的静态映射
  4. wireshark网络分析就这么简单 pdf_才知道,PDF、Excel、Word互转这么简单?涨知识了...
  5. Django入门-项目创建与初识子应用
  6. linux 卸载kde,Ubuntu KDE终端系统安装与卸载
  7. postgres的数据库备份和恢复
  8. 华软计算机网络技术,[计算机硬件及网络]计算机网络技术专业自评报告华软.doc...
  9. 硬件信息修改大师_零成本学习之单片机硬件开发(1)
  10. python2.7 安装numpy no module name zlib
  11. service XXX does not support chkconfig(service报错)
  12. JavaScript基础之Array对象和Boolean对象
  13. windows的又一个问题
  14. 计算机ps图片在哪里看,如何在Photoshop中查看照片的EXIF信息如何删除照片的exif信息...
  15. 网上图书购买系统可行性研究报告
  16. 逻辑回归及美团逻辑回归总结
  17. 基于Web的酒店客房管理系统的设计与实现
  18. win7控件无法安装怎么办【系统天地】
  19. 【Adobe Illustrator 教程】4. 认识渐变工具
  20. 计算机组装图解,电脑组装图解

热门文章

  1. 6-10 两个字符串穿插 (10分) PTA
  2. Linux IGMP SNOOPING 学习笔记 之三 igmp snooping实现需求分析
  3. 计算机学校教师培训方案,教师培训电脑多媒体实施方案
  4. 微信小程序获取上一个页面的路由地址
  5. Matlab 定点化函数fi
  6. DataBinding源码分析
  7. 看ChatGPT这形势,留给我们开发人员的时间不多了
  8. 港科百创 | 本末科技完成近亿元A轮融资
  9. Tik Tok小店:英国tiktok小店怎么核对结算
  10. 0427-android-距离感应了解一下