day_07

1 在多态中访问子类特有成员

将父类的引用 转换成 子类的引用类型

1.1 多态的转型

基本类型的类型转换:

  • 自动类型转换:小的数据类型可以自定转换为大的数据类型
  • 强制类型转换:可以把打的数据类型强制转换为小得数据类型,与可能造成数据的精度损失。

java中对象的强制类型转换称为造型

  • 从子类到父类类型的转换可以自动进行。
  • 从父类到子类的类型转换必须通过造型(强制转换)实现
  • 无继承关系的引用类型间的转换是非法

1.2 instanceof

作用就是检验某一个引用是否是另一个类的实例对象。 返回值是boolean类型

if(ac instanceof  Cat){//返回true则表示是该类的示例对象

}
  • 子类到父类的类型转换 称为向上转型

  • 父类到子类的类型转换 称为向下转型,需要强制转换

1.3 继承成员变量和继承方法的区别

若子类重写父类的方法,就意味着子类中定义的方法彻底覆盖了父类中的同名方法,系统将不会将父类中的方法转移到子类。

对于实例变量则不存在这样的现象,即使子类定义了与父类完全相同的实例变量, 这个实例变量依然不可能覆盖父类中的实例变量。

案例:计算图形面积

定义三个类,父类GeometricObject代表几何形状,子类Circle代表圆形, MyRectangle代表矩形。

定义一个测试类GeometricTest,
编写equalsArea方法测试两个对象的面积是否相等(注意方法的参数类型,利用动态绑定技术),编写displayGeometricObject方法显示对象的面积(注意方法的参数类型,利用动态绑定技术)。
在这里插入图片描述

2 . 面向对象的三大特征在JDK中的体现

  • java.lang.Object
 public class Object

Object 类是所有的java类的根父类。他是java中所有类的直接或间接的超类(基类)

如果在类的声明中,没有使用extends 关键字来指明其父类,则默认的父类就是Object
public class Animal extends Object {}

2.1 Object类的主要的结构

构造方法:

Object()

成员方法:

  • equals(Object obj) 指示一些其他对象是否等于此。
  • finalize() 当垃圾收集确定不再有对该对象的引用时,垃圾收集器在对象上调用该对象。
  • hashCode() 返回对象的哈希码值。
  • toString() 返回对象的字符串表示形式。

2.1.1.finalize

​ 通知垃圾收集器回收当前对象,释放空间。但是,垃圾回收器并不一定会立即执行对象的收集和空间的释放。

2.1.2 equals

Object中equals的实现

    public boolean equals(Object obj) {
        return (this == obj);
    }

String类中的equals

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (coder() == aString.coder()) {
                return isLatin1() ? StringLatin1.equals(value, aString.value)
                                  : StringUTF16.equals(value, aString.value);
            }
        }
        return false;
    }

当一个类 在没有重写equals方法的时候 ,调用equals方法比较 本质上就是==比较

所有类都继承了Object ,也就获得了equals方法。如果要比较对象的属性是否形同,判定对象是否形同,则必须重写equals方法。

  @Override
    public boolean equals(Object obj) {
        Student stu= null;
        if(obj instanceof  Student){
            stu = (Student) obj;
        }
       if(this.getName().equals(stu.getName())&&this.getAge() == stu.getAge()){
           return  true;
       }
        return  false;
    }

重写之后,equals方法的比较规则,方法的实现,可以自行实现。

2.1.3.重写规则:

1 对称性 如果x.equals(y) 返回true 那么 y.equals(x) 也应该返回true

2 自反 性 x.equals(x) 必须返回的也是true

3 传递性 如果 x.equals(y) 是true y.equals(z) 是true 那么 x.equals(z)应该也返回的是true

4 一致性 如果x.equals(y) 是true 只要x和y的内容不变,无论重复x.equals(y)多少次 结果应该都是true

在任何情况下,x.equals(null) 返回的都是false 。

2.1.4 toString

System.out.println(stu1.toString());//cn.lanqiao.oop.Student@49e4cb85

System.out.println(stu2.toString());// cn.lanqiao.oop.Student@2133c8f8

toString方法返回的是String类型,类名+"@"+引用地址

在定义一个类的时候 我们也需要重写toString方法 。来根据我们需要 ,以字符串的形式,输出对象的相关内容

  @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

在idea中,因为equals方法和toString方法的重写,使用频率较高,所以提供了自动重写的方式

2.1.5 hashCode

返回对象的哈希码值 在一定的程度上 可以将hash值理解为对象的内存空间的地址值。

  • 如果两个对象的equals返回true 则他们的hashCode方法 返回的hash码值肯定也是相同的

  • 如果两个对象的hash值相同,那么他们的equals方法不一定为true

在一般情况下,当我们创建一个类的时候,我们都需要重写equals和toString();当重写equals的同时,也必须重写hashCode

3 抽象类和抽象方法

3.1 抽象类的定义

用abstract 修饰的类 就是抽象类
用abstract 修饰方法 就是抽象方法

3.2 抽象类的特点

  1. 抽象类不能示例化
  2. 抽象类是用来被继承的
  3. 可以通过多态来访问成员

3.3 抽象方法的特点

  1. 使用abstract 关键字修饰
  2. 抽象方法不能有方法体
  3. 抽象方法是用来被重写的

3.4 抽象类和抽象方法的关系

  1. 抽象类可以没有抽象方法
  2. 包含抽象方法的类一定是抽象类

3.5 抽象类的子类

抽象类的子类 要么是抽象类,要么就重写父类中的抽象方法

3.6 抽象类的成员特点

  • 成员变量:变量、常量
  • 构造方法:有 意义:方便子类使用父类的成员数据
  • 成员方法:
    抽象方法:限定子类中必须完成的一些特定的功能
    非抽象方法:提高了代码的复用性
  • 编写一个Employee类,声明为抽象类,包含如下三个属性: name, id, salary。提供必要的构造器和抽象方法: work()。
  • 对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。请使用继承的思想,设计CommonEmployee类和Manager类,要求类中提供必要的方法进行属性访问。
public abstract class Employee {//抽象类
    int id;
    String name;
    double salary;
    public Employee() {
    }
    public Employee(int id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    public abstract void work();
}
public class CommonEmployee extends Employee {//子类1
    public void work(){
        System.out.println("普通员工……");
    }
}
public class Manager extends Employee{//子类2
    double bonus;
    public void work(){
        System.out.println("经理:管理普通员工……");
    }
}

4 模板方法设计模式

抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的 通用模板。子类在抽象类的基础上进行扩展改造,但是子类在总体上保留抽象类的行为方式

解决问题:
当功能内部一部分实现是去认定的,一部分是不确定的,可以把不确定的部分暴露出去 让子类去实现

模板模式:
在软件开发中 对于一个算法而言,整体步骤是固定的,通用,让这些步骤我们就可以定义父类中,但是其中某一部分是易变的 此时可以将易变的部分抽出来定义成抽像,让子类重写实现

//计算代码的执行时间
public abstract class Template {
    public  void getTime(){
        //获取开始时间
       long begin =  System.currentTimeMillis();
       // 让我们要测试代码开始执行
        code();
        //获取代码执行结束时的时间
        long end = System.currentTimeMillis();
        System.out.println("执行代码共耗时:" + (end - begin) + "毫秒");
    }
    public abstract void  code();
}

public class SubTemplate  extends  Template{
    @Override
    public void code() {
        for(int i = 0 ; i < 10000;i++){
            System.out.println(i);
        }
    }
}

public class TemplateTest {
    public static void main(String[] args) {
        Template temp = new SubTemplate();
        temp.getTime();
    }
}

5 接口

接口是一种公共的规范标准,只要符合规范标准,就可以通用

Java中 的接口更多的体现在行为的抽象

Java中 接口的本质是契约 规范

5.1 接口的定义

interface 和 class 处于同一级、

public interface 接口名{}

5.2 接口的成员特点

  • 接口中的成员方法:只能是抽象方法,默认修饰符是public abstract
  • 接口中没有构造方法
  • 接口中的变量默认是常量 static final

5.3 接口的特点

  1. 接口不能被实例化
  2. 接口是 用来被实现的
  3. 实现接口 就要实现接口中所有的抽象方法。要么实现类是抽象类,要么实现接口的方法都是抽象方法
public interface Dao {
      int a = 10;
      void add();
      void remove();
      void insert();
}
public class DaoImpl  implements Dao{
    @Override
    public void add() {
    }
    @Override
    public void remove() {
    }
    @Override
    public void insert() {

    }
}
public class DaoTest {
    public static void main(String[] args) {
        Dao  dao = new DaoImpl();// 接口的多态
        int aa = Dao.a;
        System.out.println(aa);
    }
}

多态的体现: 具体类的多态 抽象类的多态 接口的多态
多态的前提:继承或实现
要有方法的重写:父类(父接口)的引用指向子类(子接口)的对象

5.4 接口和类的关系

  • 类和类的关系
    继承关系 只能是单继承,可以是多层继承

  • 接口和类的关系
    实现关系,可以是单实现,也可以多实现。在实现的同时继承一个类

  • 接口间的关系
    接口可以继承接口 接口的继承也是单继承 也可以多重,多层继承

5.6 抽象类和接口的区别

区别点抽象类接口
定义组成包含抽象方法的类 具体方法 变量 构造方法抽象方法和常量
使用子类继承抽象类实现类实现接口
关系抽象类实现接口接口不能继承抽象类,可以继承多个接口
对象通过抽象类的多态性产生实例对象
局限只能单继承没有

6参数传递

6.1使用类名作为形参和返回

  1. 类名作为方法的形参
    方法的形参是类类型 实参就是对应类型的对像
    – 参数传递时 传递的是对象的地址值
  2. 类名作为方法的返回值
    方法的返回值是类类型,真正返回的是该类的对象。实际返回的是对象的地址值
    – 当在参数传递的时候,如果传递的是类类型,本质都是传递的对象的引用地址值

6.2 抽象类作为形参和返回值

1. 抽象类作为形参和返回值
方法的形参是抽象类类型 实参子类对象 实际传递的是子类对象的地址值

方法的返回值 返回的是子类对象 实际也是子类对象的地址值

2. 接口作为形参和返回值
方法的形参是接口类型 实参实现对象 实际传递的是实现对象的地址值

方法的返回值 返回的是实现对象 实际也是实现对象的地址值

6.3 综合案例

运动员和教练:

需求:
现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。为了参见东京奥运会,其他国家的运动员进行交流,乒乓球运动员需要学习英语。篮球运动员需要学习日语

在这个案例中,那些是具体的类 那些是抽象类 那些是接口

分析:

​ 乒乓球运动员

​ 篮球运动员

​ 教练
在这里插入图片描述

思路:

​ 1 定义学习外语的接口 成员方法:学外语

​ 2 定义抽象人类 成员变量:姓名 年龄 构造方法 无参 带参 成员方 getter/setter 吃饭 睡觉

​ 3 定义教练类:继承人类 构造方法 抽象方法 教

​ 4 定义运动员类 继承人类,构造方法 抽象方法 play

​ 5 定义具体的类:

​ 乒乓球运动员 篮球运动员 都需继承运动员 并实现学习外语的接口 实现抽象方法

​ 乒乓球教练 篮球教练 都需要继承教练抽象类

public abstract class Human {
    int age;
    String name;
    public Human() {
    }
    public Human(int age, String name) {
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

public interface Learn {//接口
    public void learn();
}

public abstract class Student extends Human{//运动员
    public Student() {
    }

    public Student(int age, String name) {
        super(age, name);
    }
    public abstract void eat();
    public abstract void play();
}

public class StuBasket extends Student{//篮球运动员类
    public StuBasket() {
    }
    public StuBasket(int age, String name) {
        super(age, name);
    }
    public void play(){
        System.out.println("篮球运动员……");
    }
    public  void learn(){
        System.out.println("篮球运动员学日语");
    }
}
public class StuPinpang extends Student{//乒乓球运动员
    public StuPinpang() {
    }

    public StuPinpang(int age, String name) {
        super(age, name);
    }
    public void play(){
        System.out.println("乒乓球运动员……");
    }
}
public  void learn(){
        System.out.println("乒乓球运动员学英语");
    }
public abstract class Teacher extends Human{//教练类
    public Teacher() {
    }
    public Teacher(int age, String name) {
        super(age, name);
    }
    public abstract void teach();
}
public class TeaBasket extends Teacher{//篮球教练
    public TeaBasket() {
    }
    public TeaBasket(int age, String name) {
        super(age, name);
    }
    public void teach(){
        System.out.println("篮球教练……");
    }
}
public class TeaPinpang extends Teacher{//乒乓球教练
    public TeaPinpang() {
    }
    public TeaPinpang(int age, String name) {
        super(age, name);
    }
    public void teach(){
        System.out.println("乒乓球教练……");
    }
}
public class Test {
    public static void main(String[] args) {
        StuBasket stu1 = new StuBasket();
        TeaBasket tea1 = new TeaBasket();
        StuBasket stu2 = new StuBasket();
        TeaBasket tea2 = new TeaBasket();
        stu1.play();
        stu1.learn();
        tea1.teach();
        stu2.play();
        stu2.learn();
        tea.teach();
    }
}

7.内部类

就是定义在类的内部的类
格式:

class  外部类{
		修饰符 class  内部类{
		
		}
}

内部类的访问特点:
内部类可以直接访问外部类的成员 包括私有成员
外部类要访问内部类的成员 必须创建对象

7.1 成员内部类

根据内部类定义的位置:定义在类中,和方法是同一级别的
在外部类内创建成员内部类的对象格式:

外部类.内部类   内部类对象名 = new 外部类().new 内部类();

Outer.Inner inner = new Outer().new Inner();

成员内部类的使用:
将一个类设计成内部类,大多是因为不想外界访问,所以内部类的定义应该先私有化,私有化之后再提供一个可以让外界调用的方法,方法内部常见内部类对象并调用

7.2 方法内部类

局部内部类:定义在方法中的类
访问范围仅限于所在的方法内,方法之外无法访问。在内部访问时需创建内部类的对象

7.3 匿名内部类

匿名内部类的前提:
存在一个类或接口,这里的类可以是抽象类也可以是具体类
格式:

new 类名(){
重写的方法
}

new 接口名(){
实现方法
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值