新学java的 Day7 笔记 面向对象思想(多态) (抽象 接口 内部类)

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

public class Animal {
    String name;
    int age;
    public void eat(){
        System.out.println("动物进食.....");
    }
}
​
public class Cat  extends Animal{
    String name;
    int age;
​
    @Override
    public void eat() {
        System.out.println("猫吃鱼....");
    }
    public void play(){
        System.out.println("猫抓老师.....");
    }
}
​
public class Dog extends Animal {
    String name;
    int age;
​
    @Override
    public void eat() {
        System.out.println("狗吃骨头....");
    }
    public void work(){
        System.out.println("狗看家....");
    }
}
​
public class AnimalTest {
    public static void main(String[] args) {
        Animal ac = new Cat();
        ac.eat();//只能访问到子类对于父类重写的方法
        Animal ad = new Dog();
        ad.eat();
        Cat  c = new Cat();
        c.eat();
        c.play();
        Dog d = new Dog();
        d.eat();
        d.work();
    }
}

将父类的引用转换为子类的引用对象,就能够访问到子类特有的方法了。

1.1 多态的转型

基本类型的类型转换:

自动类型转换:小的数据类型可以自定转换为大的数据类型

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

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

  • 从子类到父类类型的转换可以自动进行

  • 从父类到子类的类型转换必须通过造型(强制转换)实现

  • 无继承关系的引用类型间的转换是非法

      
  Cat cat = (Cat) ac;
        cat.play();
        Dog dog = (Dog)ad;
        dog.work();

1.2 instanceof

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

 if(ac instanceof  Cat){
            Cat cat = (Cat) ac;
            cat.play();
        }
        Dog dog = (Dog)ad;
        dog.work();
        System.out.println("--------------------------");
        //        以下的转换是失败的
        if(ac instanceof  Dog){//返回true  则表示是该类的实例对象
            Dog cd = (Dog) ac;
            cd.work();
        }else{
            System.out.println("类型不匹配");
        }
        if(ad instanceof  Cat){
            Cat dc = (Cat) ad;
           dc.play();
        }else{
            System.out.println("类型不匹配");
        }
​

将有子类到父类的类型转换 称为向上转型

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

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

package cn.lanqiao.oop;
​
public class FieldMethodTest {
    public static void main(String[] args) {
        Sub sub = new Sub();
        System.out.println(sub.count);//20
        sub.display();//20
        Base b = sub;
        System.out.println(b == sub);//true
        System.out.println(b.count);//10
        b.display();//20
    }
}
class Base{
    int count =10;
    public void display(){
        System.out.println(count);
    }
}
class Sub extends  Base{
    int count = 20;
    public void display(){
        System.out.println(count);
    }
}

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

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

案例:计算图形面积

定义三个类,父类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()

成员方法:

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

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 {
    private int id;
    private String name;
    private double salary;
    public Employee() {
    }
​

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }
​

    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 Manager extends  Employee {
    private double bonus;
​
​
    @Override
    public void work() {
        System.out.println("管理普通雇员。。。。。");
    }
}
public class CommonEmployee  extends  Employee{
    @Override
    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

接口中没有构造方法。

接口中的变量默认是常量 public static final

5.3 接口的特点

1 接口不能被实例化

2 接口是用来被实现的。

3 实现接口就要实现接口中的所有的抽象方法。 实现类要么是抽象的,要么实现接口的所有的抽象方法

jdk8 对接口的新特性 后面讲。

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.5. 接口和类的关系

类和类的关系:

继承关系 只能单继承 可以多层继承

类和接口的关系:

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

接口和接口关系

接口可以继承接口 接口的继承可以是单继承 也可以是多重继承 还可以是多层继承

5.6.抽象类和接口的区别

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

6 参数传递

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

1 类名作为方法的形参

方法的形参是类类型 实参就是对应类型的对象 参数传递时 传递时对象的地址值

2 类名作为方法的返回值

方法的返回值是类类型,真正返回的是该类型的对象。实际返回的是对象的地址值

当在参数传递的时候 如果传递的是类类型 本质都是传递的对象的引用地址值

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

方法的形参是抽象类类型 实参子类对象 实际传递的是子类对象的地址值

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

6.2 使用接口作为形参和返回值

方法的形参是接口类型 实参实现类对象 实际传递的是实现类对象的地址值

方法的返回值时接口类型 返回的是实现类对象 实际也是实现类对象的地址值

6.3 综合案例

运动员和教练:

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

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

分析:

乒乓球运动员

篮球运动员

教练

思路:

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

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

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

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

5 定义具体的类:

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

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

7 内部类

内部类就是定义在类的内部的类

格式:

class  外部类{
        修饰符  class  内部类{
        
        
        }
}
public class Outer {//外部类
    public class inner{//内部类
        
    }
}

内部类的访问特点:

public class Outer {//外部类
    private  int  num = 10;
    public class Inner{//内部类
        private int x = 200;//内部类的成员变量
        public void print(){//内部类的成员方法
            System.out.println(num);
        }
    }

    public void show(){
        Inner inner = new Inner();
        System.out.println(inner.x);
        inner.print();
    }
​

    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.show();
    }
}

内部类可以直接访问外部类的成员 包括私有成员

外部类要访问内部类的成员 必须创建对象

7.1 成员内部类

根据内部类定义的位置:定义在类中,和方法是同一级别

在外部内创建成员内部类的对象格式:

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

成员内部类的使用;

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

public class Outer {//外部类
    private  int  num = 10;
    private class Inner{//内部类
        private int x = 200;//内部类的成员变量
        public void print(){//内部类的成员方法
            System.out.println(num);
        }
    }

    public void show(){
        Inner inner = new Inner();
        System.out.println(inner.x);
        inner.print();
    }
}
public class OuterTest {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.show();
        //在其他类中访问外部类中的内部类
        //Outer.Inner  inner = new Outer().new Inner();
    }
}

7.2 局部内部类

局部内部类定义在方法中的类

public class Outer {//外部类
    private  int  num = 10;
    public void mehtod(){
        int num2 = 20;
        class Inner{// 局部内部类在外界(外部类之外的类)是无法直接访问的
            public void show(){
                System.out.println(num);
                System.out.println(num2);
            }
        }
        Inner inner = new Inner();
        inner.show();
    }
​
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.mehtod();
    }
}

对于局部内部类 在他所在的方法之外是无法访问的。他的访问的范围仅限于他所在的方法。在方法内要访问 需要创建内部类的对象

7.3. 匿名内部类

匿名内部类的前提:

存在一个类或者接口,这里的类可以使抽象类也可以是具体类

匿名内部类:

格式:new 类名(){

重写的方法

}

new 接口名(){

实现方法

}

public class DaoTest{
    public static void main(String[] args) {
         DaoTest daoTest = new DaoTest();
         daoTest.test(new Dao() {
             @Override
             public void add() {
                 System.out.println("匿名内部类实现....");
             }
         });
     }
​
     public void test(Dao dao ){
            dao.add();
     }
 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值