第四章 面向对象

一、面向过程和面向对象

1、 面向过程(POP) 与 面向对象(OOP)

  • 二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的 是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能封装进对
    象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
  • 面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如 抽象、分类、继承、聚合、多态等。

2、对比

在这里插入图片描述

3、面向对象的思想概述

(1)程序员从面向过程的执行者转化成了面向对象的指挥者
(2)面向对象分析方法分析问题的思路和步骤:

  • 根据问题需要,选择问题所针对的现实世界中的实体。 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
  • 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序 语言,把类构造成计算机能够识别和处理的数据结构。
  • 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。

4、面向对象的三大特征

  • 封装 (Encapsulation)
  • 继承 (Inheritance)
  • 多态 (Polymorphism)

二、Java基本元素:类和对象

1、类(class):抽象的概念

(1)定义:类是对一类事物的描述,是抽象的、概念上的定义
(2)成员:属性和方法
在这里插入图片描述
(3)格式:
修饰符 class 类名 {
属性声明;
方法声明;
}

2、对象(Object)的创建和使用

(1)定义:对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
(2)格式:new +类名 列入 Person person=new Person();
(3)使用:对象名.方法名或属性名
例如:person.name=15;//给对象person的属性name赋值 person.getName();

三、类的成员

1、属性

(1)格式:修饰符 数据类型 属性名 = 初始化值 ;
(2)修饰符:

  • 常用的权限修饰符有:private、缺省、protected、public
  • 其他修饰符:static、final (暂不考虑)
    (3)属性名:属于标识符,符合命名规则和规范即可
    (4)代码演示:
public class Person{
private int age; //声明private变量 age
public String name =Lila; //声明public变量 name
}

(4)属性的分类

  • 在方法体外,类体内声明的变量称为成员变量。
  • 在方法体内部声明的变量称为局部变量。
    在这里插入图片描述
    (5)成员变量和局部变量的区别
    在这里插入图片描述
    (6)对象属性的默认初始化赋值
    在这里插入图片描述

2、方法

(1)定义

  • 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中 也称为函数或过程。
  • 将功能封装为方法的目的是,可以实现代码重用,简化代码
  • Java里的方法不能独立存在,所有的方法必须定义在类里。
    (2)格式:
    在这里插入图片描述
    在这里插入图片描述
    (3)方法的调用:对象.方法名( )
    如果方法是静态方法(static修饰的方法),可以直接用类名直接调用: 类名.方法名()
    (4)方法的重载:
    概念: 方法重载指同一个类中定义的多个方法之间的关系,满足下列条件的多个方法相互构成重载
  • 多个方法在同一个类中
  • 多个方法具有相同的方法名
  • 多个方法的参数不相同,类型不同或者数量不同

所谓方法重载就是指我们可以定义一些名称相同的方法,通过定义不同的参数来区分这些方法,然后再调用时,Java虚拟机就会根据不同的参数列表来选择合适的方法执行。也就是说,当一个重载方法被调用时,Java用参数的类型或个数来决定实际调用的重载方法。因此,每个重载方法的参数的类型或个数必须是不同。

注意

  • 重载仅对应方法的定义,与方法的调用无关,调用方式参照标准格式

  • 重载仅针对同一个类中方法的名称与参数进行识别,与返回值无关,换句话说不能通过返回值来判定两个方法是否相互构成重载
    代码演示:

public class MethodDemo {
	public static void fn(int a) {
    	//方法体
    }
    public static int fn(double a) {
    	//方法体
    }
}
 
public class MethodDemo {
	public static float fn(int a) {
    	//方法体
    }
    public static int fn(int a , int b) {
    	//方法体
    }
}

(5)方法的重写:
概念
由于类与类的继承关系,使得子类具有父类的属性和方法,此时子类具有父类所有特征,还可以在子类中重新定义,以及追加属性和方法。

所谓方法重写就是子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样)。

方法重写的特点

  • 参数列表与被重写方法的参数列表必须完全相同。
  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7
    及更高版本可以不同)。
  • 访问权限不能比父类中被重写的方法的访问权限更低。 例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为
    protected。
  • 父类的成员方法只能被它的子类重写。
  • 声明为 final 的方法不能被重写。
  • 声明为 static 的方法不能被重写,但是能够被再次声明。
  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
  • 构造方法不能被重写。
  • 如果不能继承一个类,则不能重写该类的方法。

演示代码:

public class Animal {
    public void eat() {
        System.out.println("动物吃东西");
    }
    
    void jump() {
        System.out.println("动物可以跳高");
    }
}
 
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
 
    @Override
    public void jump() {
        System.out.println("猫一蹦蹦三米");
    }
}

@Override注解

  • 限定某个方法,是重写父类方法,该注解只能用于方法,起到检验作用
  • @Override表示指定重写父类的方法,如果写了@Override注解,子类写了父类没有的方法则报错
  • 如果不写@Override注解,而子类写了父类的方法,任然构成重写
  • @Override只能修饰方法,不能修饰其他类,包,属性等

代码演示:

public class Fu {
    private void show() {
        System.out.println("Fu中show()方法被调用");
    }
 
    void method() {
        System.out.println("Fu中method()方法被调用");
    }
}
 
public class Zi extends Fu {
    /* 编译【出错】,子类不能重写父类私有的方法*/
    @Override
    private void show() {
        System.out.println("Zi中show()方法被调用");
    }
   
    /* 编译【出错】,子类重写父类方法的时候,访问权限需要大于等于父类 */
    @Override
    private void method() {
        System.out.println("Zi中method()方法被调用");
    }
 
    /* 编译【通过】,子类重写父类方法的时候,访问权限需要大于等于父类 */
    @Override
    public void method() {
        System.out.println("Zi中method()方法被调用");
    }
}

(6)重载和重写的对比
方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。

  • 方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
  • 方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
  • 方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
    在这里插入图片描述

3、构造器

(1)构造器的特征

  • 它具有与类相同的名称
  • 它不声明返回值类型。(与声明为void不同)
  • 不能被static、final、synchronized、abstract、native修饰,不能有 return语句返回值

(2)构造器的作用:创建对象;给对象进行初始化

  • 如:Order o = new Order(); Person p = new Person(“Peter”,15);
  • 如同我们规定每个“人”一出生就必须先洗澡,我们就可以在“人”的 构造器中加入完成“洗澡”的程序代码,于是每个“人”一出生就会自动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们 要“洗澡”了。
    (3)格式:
    修饰符 类名 (参数列表) {
    初始化语句;
    }
    (4)代码演示
public class Person { 构造器重载举例
private String name;
private int age;
private Date birthDate;
public Person(String n, int a, Date d) {
name = n;
age = a;
birthDate = d;
}
public Person(String n, int a) {
name = n;
age = a;
}
public Person(String n, Date d) {
name = n;
birthDate = d;
}
public Person(String n) {
name = n;
age = 30;
}
}

4、代码块

(1) 代码块(或初始化块)的作用: 对Java类或对象进行初始化
(2)代码块(或初始化块)的分类:
一个类中代码块若有修饰符,则只能被static修饰,称为静态代码块
(static block),没有使用static修饰的,为非静态代码块。
static代码块通常用于初始化static的属性
(3) 静态代码块:用static 修饰的代码块
可以有输出语句。
可以对类的属性、类的声明进行初始化操作。
不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
若有多个静态的代码块,那么按照从上到下的顺序依次执行。
静态代码块的执行要先于非静态代码块。
静态代码块随着类的加载而加载,且只执行一次。
(4) 非静态代码块:没有static修饰的代码块
可以有输出语句。
可以对类的属性、类的声明进行初始化操作。
除了调用非静态的结构外,还可以调用静态的变量或方法。
若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
每次创建对象的时候,都会执行一次。且先于构造器执行。

四、类的成员五:内部类

1、成员内部类

(1)内部类与外部类的关系

  • 成员内部类的创建需要依赖于外部类对象-(成员方法必须通过对象调用),在没有外部类实例之前无法创建成员内部类对象
  • 内部类与外部类相对独立,不是is a 的关系(发动机-汽车)
  • 私有属性的互相访问,内部类可以直接访问外部类,而外部类访问内部类需要内部类的对象来访问
    (2)创建内部类的语法
    在外部类内部创建内部类对象(Inner inner = new Inner())
    在外部类外部创建内部类对象,外部类.内部类 inner = new Outter().new Inner();
  • 在内部类内部使用隐藏的外部类对象(隐藏的this)
  • 成员内部类:类比成员方法,不能拥有静态域但是可以访问外部类的静态域
    (3)代码演示
class Outer {
private int s;
public class Inner {
public void mb() {
s = 100;
System.out.println("在内部类Inner中s=" + s);
}
}
public void ma() {
Inner i = new Inner();
i.mb();
}
}
public class InnerTest {
public static void main(String args[]) {
Outer o = new Outer();
o.ma();
}
}
public class Outer {
private int s = 111;
public class Inner {
private int s = 222;
public void mb(int s) {
System.out.println(s); // 局部变量s
System.out.println(this.s); // 内部类对象的属性s
System.out.println(Outer.this.s); // 外部类对象属性s
}
}
public static void main(String args[]) {
Outer a = new Outer();
Outer.Inner b = a.new Inner();
b.mb(333);
}
}

2、静态内部类

(1)定义

  • 定义在外部类的内部,使用static修饰,类比静态方法,静态内部类不需要外部类对象产生就能使用,不能访问外部类的成员域,但能访问静态域

(2)静态内部类的创建语法:

  • 外部类内部:与成员内部类一样
  • 外部类外部:StaticInnerClass.Inner inner = new StaticInnerClass.Inner();

3、方法内部类

定义在方法内部:类比局部变量
a.对外部完全隐藏,因此方法内部类不能有任何访问修饰符
b.方法内部类没有访问形参是,这个形参是可以在方法中随意修改的,一旦方法内部类中使用了形参,这个形参必须被声明为final。

4、匿名内部类

(1)概述
匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一
个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或
实现一个类。

(2)格式
new 父类构造器(实参列表)|实现接口(){
//匿名内部类的类体部分
}
(3)特点

  • 匿名内部类必须继承父类或实现接口
  • 匿名内部类只能有一个对象
  • 匿名内部类对象只能使用多态形式引用
    (4)代码演示
interface A{
public abstract void fun1();
}
public class Outer{
public static void main(String[] args) {
new Outer().callInner(new A(){
//接口是不能new但此处比较特殊是子类对象实现接口,只不过没有为对象取名
public void fun1() {
System.out.println(“implement for fun1");
}
});// 两步写成一步了
}
public void callInner(A a) {
a.fun1();
}
}

五、OOP的特征

1、封装和隐藏

(1)概念:
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提
高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露
的暴露出来。这就是封装性的设计思想。

(2)Java中通过将数据声明为私有的(private),再提供公共的(public)
方法:getXxx()和setXxx()实现对该属性的操作,以实现下述目的:
(3)四种访问修饰符
在这里插入图片描述

(3)代码演示

class Animal {
private int legs;// 将属性legs定义为private,只能被Animal类内部访问
public void setLegs(int i) { // 在这里定义方法 eat() 和 move()
if (i != 0 && i != 2 && i != 4) {
System.out.println("Wrong number of legs!");
return;
}
legs = i;
}
public int getLegs() {
return legs;
}
}
public class Zoo {
public static void main(String args[]) {
Animal xb = new Animal();
xb.setLegs(4); // xb.setLegs(-1000);
//xb.legs = -1000; // 非法
System.out.println(xb.getLegs());
}
}

2、继承性

(1)继承的概念

  • 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
  • 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
    生活中的继承:
    在这里插入图片描述
    兔子和羊属于食草动物类,狮子和豹属于食肉动物类。

食草动物和食肉动物又是属于动物类。

所以继承需要符合的关系是:is-a,父类更通用,子类更具体。

虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。
(2)格式
类的继承格式
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:

类的继承格式

  • class 父类 { }
  • class 子类 extends 父类 { }
    (2)继承特点:
  • 子类拥有父类非 private 的属性、方法。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。
  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B
    类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

3、多态性

(1)特点

  • 多态性,是面向对象中最重要的概念,在Java中的体现: 对象的多态性:父类的引用指向子类的对象 。 可以直接应用在抽象类和接口上
  • Java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明 该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。简称:编译时,看左边;运行时,看右边。
  • 若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism)
  • 多态情况下,
    “看左边”:看的是父类的引用(父类中不具备子类特有的方法)
    “看右边”:看的是子类的对象(实际运行的是子类重写父类的方法)
  • 对象的多态 —在Java中,子类的对象可以替代父类的对象使用 一个变量只能有一种确定的数据类型 , 一个引用类型变量可能指向(引用)多种不同类型的对象
    Person p = new Student();
    Object o = new Person();//Object类型的变量o,指向Person类型的对象
    o = new Student(); //Object类型的变量o,指向Student类型的对象
  • 子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型(upcasting)。
    (2)对象的多态性:父类的引用指向子类的对象的理解
  • 一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法
    Student m = new Student();
    m.school = “pku”; //合法,Student类有school成员变量
    Person e = new Student();
    e.school = “pku”; //非法,Person类没有school成员变量
    属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。
    总结:父类的引用指向子类的对象生成的变量只能调用父类有的属性和方法,如果方法中有被子类重写的,就需要调用子类重写的父类方法。
public class PolymorphicTest {

    public static void main(String[] args) {
        Person person = new Student();
        person.breath();
    }


}

class Person {
    int name;
    int age;

    public void eat() {
        System.out.println("人是铁饭是钢");
    }

    public void breath() {
        System.out.println("人需要呼吸");
    }
}

class Student extends Person {
    int id;
    public void eat(String s) {
        System.out.println("学生需要排队买饭"+s);
    }
    public void learn(){
        System.out.println("我正在学习");
    }
    
}

六、关键字this和super

1、this

(1)在Java中,this关键字比较难理解,它的作用和其词义很接近。

  • 它在方法内部使用,即这个方法所属对象的引用;
  • 它在构造器内部使用,表示该构造器正在初始化的对象。
  • this可以调用类的属性、方法和构造器
    (2)什么时候使用this关键字呢?
  • 当在方法内需要用到调用该方法的对象时,就用this。 具体的:我们可以用this来区分属性和局部变量。 比如:this.name =name;
    (3)代码演示在这里插入图片描述

2、super

(1)特性

  • super可用于访问父类中定义的属性
  • super可用于调用父类中定义的成员方法
  • super可用于在子类构造器中调用父类的构造器
  • 尤其当子父类出现同名成员时,可以用super表明调用的是父类中的成员
  • super的追溯不仅限于直接父类
  • super和this的用法相像,this代表本类对象的引用,super代表父类的内存 空间的标识
  • 子类中所有的构造器默认都会访问父类中空参数的构造器
  • 当父类中没有空参数的构造器时,子类的构造器必须通过this(参 数列表)或者super(参数列表)语句指定调用本类或者父类中相应的构造器。同时,只能”二选一” ,且必须放在构造器的首行
  • 如果子类构造器中既未显式调用父类或本类的构造器,且父类中又 没有无参的构造器,则编译出错
    在这里插入图片描述

代码演示

class Person {
protected String name = "张三";
protected int age;
public String getInfo() {
return "Name: " + name + "\nage: " + age;
}
}
class Student extends Person {
protected String name = "李四";
private String school = "New Oriental";
public String getSchool() {
return school;
}
public String getInfo() {
return super.getInfo() + "\nschool: " + school;
}}
public class StudentTest {
public static void main(String[] args) {
Student st = new Student();
System.out.println(st.getInfo());
}}

3、this和super的区别

在这里插入图片描述

七、关键字:static和final

1、static

(1)使用范围:
在Java类中,可用static修饰属性、方法、代码块
(2)被修饰后的成员具备以下特点:

  • 随着类的加载而加载
  • 优先于对象存在
  • 修饰的成员,被所有对象所共享
  • 访问权限允许时,可不创建对象,直接被类调用:类名.方法名
    (3)应用实例
class Person {
private int id;
public static int total = 0;
public Person() {
total++;
id = total; }
public static void main(String args[]){
Person Tom=new Person();
Tom.id=0;
total=100; // 不用创建对象就可以访问静态成员
} }
public class StaticDemo {
public static void main(String args[]) {
Person.total = 100; // 不用创建对象就可以访问静态成员
//访问方式:类名.类属性,类名.类方法
System.out.println(Person.total);
Person c = new Person();
System.out.println(c.total); //输出101
}}

(4)实例应用

public final class Test {
public static int totalNumber = 5;
public final int ID;
public Test() {
ID = ++totalNumber; // 可在构造器中给final修饰的“变量”赋值
}
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.ID);
final int I = 10;
final int J; J = 20;
J = 30; // 非法
} }

(5)main方法

  • 由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是
    public,又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的,该方法接收一个String类型的数组参数,该数组中保存执行Java命令 时传递给所运行的类的参数。
  • 又因为main() 方法是静态的,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情 况,我们在之前的例子中多次碰到。

2、final

  • 在Java中声明类、变量和方法时,可使用关键字final来修饰,表示“最终的”。
    final标记的类不能被继承。提高安全性,提高程序的可读性。 String类、System类、StringBuffer类
  • final标记的方法不能被子类重写。 比如:Object类中的getClass()。
  • final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只能被赋值一次。
  • final标记的成员变量必须在声明时或在每个构造器中或代码块中显式赋值,然后才能使用。
  • 常量:final double MY_PI = 3.14;
  • static final 变量名:全局常量

八、Object

(1)Object类是所有Java类的根父类

  • 如果在类的声明中未使用extends关键字指明其父类,则默认父类 为java.lang.Object类
    (2)Object方法结构
    在这里插入图片描述
    (3)==操作符与equals方法
  • 基本类型比较值:只要两个变量的值相等,即为true。 int a=5; if(a==6){…}
  • 引用类型比较引用(是否指向同一个对象):只有指向同一个对象时,“”才 返回true。
    Person p1=new Person();
    Person p2=new Person();
    if (p1
    p2){…}
  • 用“==”进行比较时,符号两边的数据类型必须兼容(可自动转换的基本 数据类型除外),否则编译出错
  • equals():所有类都继承了Object,也就获得了equals()方法。还可以重写。只能比较引用类型,其作用与“==”相同,比较是否指向同一个对象。格式:obj1.equals(obj2)
  • 特例:当用equals()方法进行比较时,对类File、String、Date及包装类 (WrapperClass)来说,是比较类型及内容而不考虑引用的是否是同一个对 象;原因:在这些类中重写了Object类的equals()方法。
  • 当自定义使用equals()时,可以重写。用于比较两个对象的“内容”是否都 相等

(4)toString()方法

  • toString()方法在Object类中定义,其返回值是String类型,返回类名和它 的引用地址。
  • 在进行String与其它类型数据的连接操作时,自动调用toString()方法
    Date now=new Date();
    System.out.println(“now=”+now); 相当于
    System.out.println(“now=”+now.toString());
  • 可以根据需要在用户自定义类型中重写toString()方法
    如String 类重写了toString()方法,返回字符串的值。
    s1=“hello”;
    System.out.println(s1);//相当于System.out.println(s1.toString());
  • 基本类型数据转换为String类型时,调用了对应包装类的toString()方法
    int a=10; System.out.println(“a=”+a);

九、包装类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

十、抽象类和抽象方法

1、概述

  • 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
  • 抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
  • 由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
  • 父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。
  • 在 Java 中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。

2、抽象类注意要点

  • 用abstract关键字来修饰一个类,这个类叫做抽象类。 用abstract来修饰一个方法,该方法叫做抽象方法。
  • 抽象方法:只有方法的声明,没有方法的实现。以分号结束: 比如:public abstract void talk();
  • 含有抽象方法的类必须被声明为抽象类。
  • 抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重 写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
  • 不能用abstract修饰变量、代码块、构造器;
  • 不能用abstract修饰私有方法、静态方法、final的方法、final的类。

3、应用实例

public abstract class Vehicle{
public abstract double calcFuelEfficiency(); //计算燃料效率的抽象方法
public abstract double calcTripDistance(); //计算行驶距离的抽象方法
}
public class Truck extends Vehicle{
public double calcFuelEfficiency( ) { //写出计算卡车的燃料效率的具体方法 }
public double calcTripDistance( ) { //写出计算卡车行驶距离的具体方法 } }
public class RiverBarge extends Vehicle{
public double calcFuelEfficiency( ) { //写出计算驳船的燃料效率的具体方法 }
public double calcTripDistance( ) { //写出计算驳船行驶距离的具体方法} }

十一、接口

1、接口的概述

(1)接口(interface)是抽象方法和常量值定义的集合。
(2) 接口的特点:

  • 用interface来定义。
  • JDK7.0及之前接口中只能定义全局常量和抽象方法,但JDK8.0及以上还定义了静态方法和默认方法。
  • 接口中的所有成员变量都默认是由public static final(全局常量)修饰的。
  • 接口中的所有抽象方法都默认是由public abstract(没写出来)修饰的。
  • 接口中没有构造器。
  • 接口采用多继承机制。

2、注意要点

  • 定义Java类的语法格式:先写extends,后写implements 。:
    class SubClass extends SuperClass implements InterfaceA{ }
  • 一个类可以实现多个接口,接口也可以继承其它接口。
  • 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
  • 接口的主要用途就是被实现类实现。(面向接口编程)
  • 与继承关系类似,接口与实现类之间存在多态性
  • 接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义
    (JDK7.0及之前),而没有变量和方法的实现。

3、简单举例


public interface Runner{

public static final int ID=1;

public abstract void start();

public abstract void run();

public abstract void stop();

}

4、接口多继承

class A implements a,b,c....

public interface Swimmer {
	public abstract void swim();
}


public interface Runner {
	public abstract void run();
}

public class Creator {
	public void eat() {

	}
}



public class Man extends Creator implements Runner, Swimmer {
	public void run() {
		System.out.println("我会跑");
	}

	public void swim() {
		System.out.println("我会游泳");
	}

	public void eat() {
		System.out.println("我能吃饭");
	}
}


public class ManTest {
	public static void main(String[] args) {
		ManTest mt = new ManTest();
		Man m = new Man();
		mt.m1(m);
		mt.m2(m);
		mt.m3(m);
	}

	public void m1(Runner f) {
		f.run();
	}

	public void m2(Swimmer s) {
		s.swim();
	}

	public void m3(Creator c) {
		c.eat();
	}
}

5、抽象类和接口的比较

​​在这里插入图片描述

6、JDK8.0 接口新特性

  • Java 8中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完 全合法的,只是它看起来违反了接口作为一个抽象定义的理念。
  • 静态方法:使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行 其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中找到像Collection/Collections或者Path/Paths这样成对的接口和类。
  • 默认方法:默认方法使用 default 关键字修饰。可以通过实现类对象来调用。我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。 比如:java 8API中对Collection、List、Comparator等接口提供了丰富的默认 方法。
  • 若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同 参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接口时,会出现:接口冲突。
  • 解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突。 若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非 抽象方法,则不会出现冲突问题。因为此时遵守:类优先原则。接口中具有 相同名称和参数的默认方法会被忽略。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值