2. 面向对象(二)

简介: 2. 面向对象(二)

2.9 继承


2.9.1 概述


如果有多个类中有相同的特征和行为(属性和方法),并且这多个类之间从逻辑上讲是有一定的关联的。那么此时,我们可以将这些共同的部分单独写到一个类中。


  • Monkey: name, age, gender,  walk(), sleep(), eat()
  • Tiger: name, age, gender,  walk(), sleep(), eat()
  • Elephent:  name, age, gender,  walk(), sleep(), eat()


可以将上述三种类中,共同的部分提取出来


Animal: name, age, gender,  walk(), sleep(), eat()


此时,被提取出的这个类,称作是--父类,基类,超类


具有相同特征的那些类,称作是--子类,派生类


从A类派生出B类:A是B的父类,B是A的子类


他们之间的关系,是继承:子类继承自父类


为什么使用继承:


代码复用+功能拓展


继承的实现


通过extends关键字可以实现类与类的继承


格式:


public class Person {
  private String name;
  private int age;
  public Person() {}
  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;
  }
}
public class Student extends Person {
  public void study() {
    System.out.println("学生要学到");
  }
}
public class Teacher extends Person {
  public void teach() {
    System.out.println("老师要讲到");
  }
}

2.9.2 继承的优缺点


优点:


  • 提高了代码的复用性: 多个类相同的成员可以放到同一个类中;
  • 提高了代码的维护性:如果功能的代码需要修改,修改一处即可;
  • 让类与类之间产生了关系,是多态的前提;


缺点


  • 好处的第三点同时也是继承的弊端,类与类之间产生了关系,让类的耦合性增强了;
  • 设计原则:高内聚低耦合;


Java继承中成员变量的特点


  • 成员变量名称不一样,使用的时候非常简单
  • 成员变量名称一样的情况:
  • 在子类中访问变量:(就近原则)
  • 在方法的局部范围找,如果有就使用
  • 在子类的成员范围找,如果有就使用
  • 在父类的成员范围找,如果有就使用
  • 如果还找不到 就报错


public class Father {
  //为了演示案,这里使用public修饰了成员变量,实际开发中用private
  //年龄
  public int age = 45;
}
public class Son extends Father {
  //身高
  public int height = 170;
  //年龄
  public int age = 20;
  public void show() {
    System.out.println(height);
    System.out.println(age);
  }
  public void printAge() {
    int age = 10;
    System.out.println(age);
  }
}
public class ExtendsTest {
  public static void main(String[] args) {
    Son s = new Son();
    //s.show();
    s.printAge();
  }
}

2.9.3 super关键字


  • super含义
  • this代表本类对象的引用
  • super代表父类存储空间的标识(可以理解为父类对象引用)
  • 用法(this和super均可如下使用)
  • 访问成员变量
    this.成员变量 super.成员变量
  • 访问构造方法
    this(…) super(…)
  • 访问成员方法
    this.成员方法() super.成员方法()
public class Father {
  public int age = 45;
}
public class Son extends Father {
  public int age = 20;
  public void printAge() {
  int age = 10;
  System.out.println(age);
  //我要访问子类成员范围的age
  System.out.println(this.age);
  //我要访问父类成员范围的age
  System.out.println(super.age);
}
}
public class ExtendsTest {
public static void main(String[] args) {
Son s = new Son();
s.printAge();
}
}



2.9.4 继承中的构造方法


一个对象在实例化的时候,需要先去实例化从父类继承到的成员,因为子类继承父类,会继承父类的非私有成员。


而子类在初始化的时候,可能会使用父类的数据,如果父类数据没有先初始化,子类就不能使用这些数据,所以,在子类初始化之前,一定要先完成父类数据的初始化。


在实例化父类部分的时候,默认使用父类中的无参构造


问题:如果父类中没有无参构造,或者父类中的无参构造子类无法访问(使用private修饰无参构造),则此时子类对象无法完成实例化。


解决:


  1. 给父类中添加一个子类能够访问到的无参构造方法
  2. 在子类的构造方法中,手动调用父类中能够访问到的构造方法,来实例化父类部分


public class Father {
  public Father() {
    System.out.println("Father无参构造方法");
  }
  public Father(String name) {
    System.out.println("Father带参构造方法");
    System.out.println(name);
  }
}
public class Son extends Father {
  public Son() {
    //super();
    super("杨幂");
    System.out.println("Son无参构造方法");
  }
  public Son(String name) {
    //super();
    super("杨幂");
    System.out.println("Son带参构造方法");
    System.out.println(name);
  }
}
public class ExtendsTest {
  public static void main(String[] args) {
    Son s = new Son();
    System.out.println("---------");
    Son s2 = new Son("小幂");
  }
}

2.9.5 继承中成员方法


通过子类对象去访问一个方法


  • 首先在子类中找
  • 然后在父类中找
  • 如果还是没有就会报错


public class Father {
  public void show() {
    System.out.println("Father show");
  }
}
/*
 * Java继承中成员方法的访问特点:
 *    A:子类中方法和父类中方法的声明不一样,这个太简单
 *    B:子类中方法和父类中方法的声明一样,调用的到底是谁的呢?
 *      执行的是子类中的方法。
 */
public class Son extends Father {
  public void method() {
    System.out.println("Son method");
  }
  public void show() {
    System.out.println("Son show");
  }
}
public class ExtendsTest {
  public static void main(String[] args) {
    Son s = new Son();
    s.method();
    s.show();
    //s.function();
  }
}

2.9.6 方法重写


用子类的方法实现覆盖掉父类的实现


方法重写:子类中出现了和父类中一摸一样的方法声明


应用:当子类需要父类的功能,而功能主体子类有自己特有的内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容


注意:


注解


@Override:


是一个注解,常用在方法的重写中。表示在进行方法重写之前,进行一个验证。验证这个方法,到底是不是在重写父类中的方法。这个注解,可以添加,也可以不添加。但是,一般情况下,我们都是要加上去的


  • 表明该方法的重写父类的方法
  • 方法重写的注意事项
  • 父类中私有方法不能被重写
  • 子类重写父类方法时,访问权限不能更低
  • 子类重写父类方法时,建议访问权限一摸一样


注意:


  • 访问权限问题:
    子类方法的访问权限不能比父类方法中的访问权限低,要大于等于父类方法的访问权限
    public > protected > default > private
  • 关于返回值类型:在重写的时候,要求方法名和参数必须和父类中方法相同
    子类方法的返回值类型可以和父类方法中返回值类型相同。也可以是父类方法中返回值类型的子类型。
    重载和重写


public class Phone {
  public void call(String name) {
    System.out.println("给"+name+"打电话");
  }
}
public class NewPhone extends Phone {
  public void call(String name) {
    System.out.println("开启视频功能");
    super.call(name);
  }
}
/*
 * 方法重写:子类中出现了和父类中一模一样的方法声明的情况。
 * 
 * 方法重写的应用:
 *    当子类需要父类的功能,而功能主体子类又有自己的特有内容的时候,就考虑使用方法重写,
 *    这样即保证了父类的功能,还添加了子类的特有内容。
 */
public class PhoneTest {
  public static void main(String[] args) {
    Phone p = new Phone();
    p.call("孙俪");
    System.out.println("-----------");
    NewPhone np = new NewPhone();
    np.call("孙俪");
  }
}


继承的特点


  • Java语言是单继承的,一个类只能有一个父类,一个类可以有多个子类
    在某些语言中是支持多继承的。例如:C++、python...
    但是在多继承中,会有一个问题:二义性。
    虽然很多语言都抛弃了多继承,但是还是会用其他的方式来间接的实现类似多继承。
    例如:在java中是用接口实现的。
  • Java中所有的类都直接或者简介的继承自 Object
  • 子类可以访问到父类中能看的见的成员:被public或者protected修饰的
  • 构造方法不能继承。


2.10 抽象类与抽象方法


抽象类:


abstract class 类名 {
}


用关键字abstract修饰的类,就是抽象类


  1. 抽象类使用abstract来修饰,抽象类不能实例化对象。
  2. 抽象类中是可以写非静态的成员的,这时候这些非静态成员是可以继承给子类的。
  3. 抽象类中是可以包含构造方法的。


抽象方法:


用关键字abstract修饰的方法,就是抽象方法,抽象方法,只能够写在抽象类中。


public abstract 返回值类型 方法名(参数);


特点:


抽象方法:


抽象方法使用abstract来修饰,只有声明,没有实现。


结合抽象类和抽象方法:


非抽象子类在继承一个抽象父类时,要实现父类中所有的抽象方法。


//研发工程师 
abstract class Developer {
  public abstract void work();//抽象函数。需要abstract修饰,并分号;结束
}
//JavaEE工程师
class JavaEE extends Developer{
  public void work() {
    System.out.println("正在研发淘宝网站");
  }
}
//移动端工程师
class Android extends Developer {
  public void work() {
    System.out.println("正在研发某款app");
  }
}


抽象类的特点:


  • 抽象类与抽象方法都必须使用 abstract来修饰
  • 抽象类不能直接创建对象
  • 抽象类中可以有抽象方法,也可以没有抽象方法
  • 抽象类的子类:实现了抽象方法的具体类或者抽象类


2.11 接口


2.11.1 接口概念


接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的”类”。


接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类来完成。这样将功能的定义与实现分离,优化了程序设计。


请记住:一切事物均有功能,即一切事物均有接口。


接口的特点:


  • 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
  • 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
  • 接口中的方法都是公有的。


接口与类相似点:


  • 一个接口可以有多个方法。
  • 接口文件保存在 .java 结尾的文件中,文件名使用接口名。
  • 接口的字节码文件保存在 .class 结尾的文件中。
  • 接口相应的字节码文件必须在与包名称相匹配的目录结构中。


接口与类的区别:


  • 接口不能用于实例化对象。
  • 接口没有构造方法。
  • 接口中所有的方法必须是抽象方法。
  • 接口不能包含成员变量,除了 static 和 final 变量。
  • 接口不是被类继承了,而是要被类实现。
  • 接口支持多继承。


抽象类和接口的区别


  • 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
  • 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
  • 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
  • :JDK 1.8 以后,接口里可以有静态方法和方法体了。


访问权限修饰符 interface 接口名 {
抽象方法1;
抽象方法2;
抽象方法3;
}


访问权限修饰符:和类一样,只能有 public 和默认的default权限。


  • 接口不是类,不能实例化对象。
  • 接口,暂时和类写成平级的关系。
  • 接口名字是一个标识符,遵循大驼峰命名法


接口中成员的定义:


  • 属性:接口中的属性,默认的修饰符是 public static final
  • 构造方法:接口中不能写构造方法
  • 方法:
    接口中的方法都是抽象方法
    接口中的方法访问权限修饰符都是public


2.11.2 接口的实现


接口不能实例化


按照多态的方式,由具体的实现类实例化。其实这也是多态的一种,接口多态。


接口的实现类,要么是抽象类,要么重写接口中的所有抽象方法


implements


public class XX extends YY implements ZZ {
XX
}


  • 一个非抽象类在实现接口后,需要实现接口中所有的抽象方法。
  • 一个类在继承自一个父类后,还可以再去实现接口。
    如果同时有父类和接口,那么继承父类在前,实现接口在后
  • 一个类可以实现多个接口
    如果一个类实现的多个接口中有相同的方法,这个方法在实现类中只需要实现一次即可。
  • 接口之间是有继承关系的,而且接口之间的继承是多继承。


接口用关键字interface表示
格式:public interface 接口名 {}


类实现接口用implements表示


格式:public class 类名 implements 接口名 {}


public class InterfaceDemo {
  public static void main(String[] args) {
    Cat cat = new Cat();
    cat.clumb()
  }
}
public class Cat implements Clumbing {
  @Override
  public void clumb() {
    System.out.println("猫会爬树");
  }
}
//定义了一个爬树的接口
public interface Clumbing {
  //抽象方法
  public abstract void clumb();
}


2.11.3  类、抽象类、接口


三者比较:


类与类


继承关系,只能单继承,但是可以多层继承(生物-》动物=》猫类)


类与接口


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


接口与接口


继承关系,可以单继承,也可以多继承


三者区别


  • 成员区别


抽象类 变量,常量;有抽象方法;抽象方法,非抽象方法


接口 常量;抽象方法


  • 关系区别


类与类 继承,单继承


类与接口 实现,单实现,多实现


接口与接口 继承,单继承,多继承


  • 设计理念区别


抽象类 被继承体现的是:”is a”的关系。共性功能


接口 被实现体现的是:”like a”的关系。扩展功能


interface 缉毒{
  public abstract void 缉毒();
}
//定义犬科的共性功能
abstract class 犬科{
public abstract void 吃饭();
public abstract void 吼叫();
}
// 缉毒犬属于犬科一种,让其继承犬科,获取犬科的特性,
//由于缉毒犬具有缉毒功能,那么它只要实现缉毒接口即可,这样即保证缉毒犬具备犬科的特性,也拥有了缉毒的功能
class 缉毒犬 extends 犬科 implements 缉毒{
  public void 缉毒() {
  }
  void 吃饭() {
  }
  void 吼叫() {
  }
}
class 缉毒猪 implements 缉毒{
  public void 缉毒() {
  }
}


2.12 多态


2.12.1概述


某一个事物,在不同时刻表现出来的不同状态。


  • 举例


猫可以是猫的类型。猫 m = new 猫();


同时猫也是动物的一种,也可以把猫称为动物


动物 d = new 猫();


  • 多态的前提和体现
  • 有继承关系
  • 有方法重写
  • 有父类引用指向子类对象


public class TestDemo {
  public static void main(String[] args) {
    //多态
    Animal a = new Cat();
    a.eat();
  }
}
public class Cat extends Animal {
  public int age = 20;
  public int weight = 10;
  public void eat() {
    System.out.println("猫吃鱼");
  }
  public void playGame() {
    System.out.println("猫捉迷藏");
  }
}
public class Animal {
  public int age = 40;
  public void eat() {
    System.out.println("吃东西");
  }
}


2.12.2多态的优缺点:


优点:


提高了程序的扩展性


缺点:


不能访问子类特有功能


/*
 * 多态的好处:提高了程序的扩展性
 *    具体体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作。
 * 多态的弊端:不能使用子类的特有功能
 */
public class TestDemo {
  public static void main(String[] args) {
    AnimalOperator ao = new AnimalOperator();
    Cat c = new Cat();
    ao.useAnimal(c);
    Dog d = new Dog();
    ao.useAnimal(d);
    Pig p = new Pig();
    ao.useAnimal(p);
  }
}
public class AnimalOperator {
  /*
  public void useAnimal(Cat c) { //Cat c = new Cat();
    c.eat();
  }
  public void useAnimal(Dog d) { //Dog d = new Dog();
    d.eat();
  }
  */
  public void useAnimal(Animal a) { //Animal a = new Cat();
    a.eat();
  }
}
public class Cat extends Animal {
  public void eat() {
    System.out.println("猫吃鱼");
  }
}
public class Dog extends Animal {
  public void eat() {
    System.out.println("狗啃骨头");
  }
  public void lookDoor() {
    System.out.println("狗看门");
  }
}
public class Pig extends Animal {
  public void eat() {
    System.out.println("猪拱白菜");
  }
}


目录
相关文章
|
5月前
|
Java
面向对象
面向对象
48 7
|
9月前
|
C++
c++面向对象
c++面向对象
49 0
|
Java
1.7 面向对象
1.7 面向对象
67 0
再次认识面向对象
再次认识面向对象
60 0
到底什么是面向对象。
到底什么是面向对象。
64 0
|
Java
2. 面向对象
面向过程,其实就是面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些功能方法相互调用,完成需求。
149 1
|
Java 编译器
初识面向对象上
初识面向对象上
143 0
初识面向对象上
|
设计模式 存储 安全
第4章 面向对象
面向对象的方方面面(异常单独列一章)。
169 0
|
存储 Java
面向对象(二)
面向对象(二)
面向对象(二)