一、继承——extends

子类继承父类,子类拥有父类的变量和方法

1. 继承类型

java不支持多继承,但支持多重继承

java继承类可以同样的字段吗 java中可以继承两个类吗_学习

尽管java不支持用extends继承多个父类,但可以用implements实现多个接口

2. 继承特性

  • 子类拥有父类的成员变量和方法,但不继承构造方法
  • 子类可以对父类的方法进行重写
  • java的继承是单继承(C++可以多继承)
public class Animal { 
    private String name;   
    private int id; 
    public Animal(String myName, int myid) { 
        //初始化属性值
    } 
    public void eat() {  //吃东西方法的具体实现  } 
    public void sleep() { //睡觉方法的具体实现  } 
} 
 
public class Penguin  extends  Animal{     //继承父类
}

3. 继承关键字

  • extends:继承父类,只能继承一个
  • implements:实现接口,可以实现多个,用逗号隔开
  • final:final类不可以被继承,final方法不可以被重写
  • super:用来引用当前对象的父类,可以使用父类的变量和方法
  • this:指向自己的引用,可以使用自己的变量和方法
class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();       // this 调用自己的方法
    super.eat();      // super 调用父类方法
  }
}

4. 构造器

  • 子类是不继承父类的构造器,但可以调用。
  • 如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。
  • 如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
  • 子类的所有构造方法内部, 第一行会(隐式)自动先调用父类的无参构造函数super();
  • 如果子类构造方法第一行显式调用了父类构造方法,系统就不再调用无参的super()了。
class SuperClass {
  private int n;
  SuperClass(){
    System.out.println("SuperClass()");
  }
  SuperClass(int n) {
    System.out.println("SuperClass(int n)");
    this.n = n;
  }
}
// SubClass 类继承
class SubClass extends SuperClass{
  private int n;
  
  SubClass(){ // 自动调用父类的无参数构造器
    System.out.println("SubClass");
  }  
  
  public SubClass(int n){ 
    super(300);  // 调用父类中带有参数的构造器
    System.out.println("SubClass(int n):"+n);
    this.n = n;
  }
}

二、重写——override

子类对父类的方法进行重写,则子类对象调用此方法时,调用的是子类重写的方法

1. 重写规则

  • 参数与父类方法相同
  • 返回类型可以与父类方法不同,但必须是父类方法返回类型的派生类
  • 访问权限不能比父类中被重写的方法的访问权限更低
  • 父类的成员方法只能被它的子类重写
  • 声明为 final 的方法不能被重写
  • 声明为 static 的方法不能被重写,但是能够被再次声明
  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法
  • 构造方法不能被重写
  • 如果不能继承一个类,则不能重写该类的方法

2. super

重写父类的方法之后,在该方法中调用父类被重写的方法用super.方法名(参数列表)

class Animal{
   public void move(){
      System.out.println("动物可以移动");
   }
}
 
class Dog extends Animal{
   public void move(){
      super.move();         // 应用super类的方法
      System.out.println("狗可以跑和走");
   }
}

3. 重载overload

重载是在同一类中,方法名相同,参数列表一定不同的若干方法

重载与重写的区别

区别点

重载方法

重写方法

参数列表

必须修改

一定不能修改

返回类型

可以修改

一定不能修改

异常

可以修改

可以减少或删除,一定不能抛出新的或者更广的异常

访问

可以修改

一定不能做更严格的限制(可以降低限制)


三、多态

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

1. 多态的必要条件

  • 继承:子类继承父类
  • 重写:子类重写父类中的方法
  • 父类引用指向子类对象:Parent p = new Child();
abstract class Animal {  
    abstract void eat();  
}  
  
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
    public void work() {  
        System.out.println("抓老鼠");  
    }  
}  
  
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
    public void work() {  
        System.out.println("看家");  
    }  
}

public class Test {
    public static void main(String[] args) {
      show(new Cat());  // 以 Cat 对象调用 show 方法
      show(new Dog());  // 以 Dog 对象调用 show 方法
                
      Animal a = new Cat();  // 向上转型  
      a.eat();               // 调用的是 Cat 的 eat
      Cat c = (Cat)a;        // 向下转型  
      c.work();        // 调用的是 Cat 的 work
  }  
            
    public static void show(Animal a)  {
      a.eat();  
        // 类型判断
        if (a instanceof Cat)  {  // 猫做的事情 
            Cat c = (Cat)a;  
            c.work();  
        } else if (a instanceof Dog) { // 狗做的事情 
            Dog c = (Dog)a;  
            c.work();  
        }  
    }  
}

2. 多态的实现方式

方式一:重写

方式二:接口

方式三:抽象类和抽象方法


四、抽象

1. 抽象类

如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

特点

  • 抽象类也有成员变量、成员方法、构造方法等
  • 抽象类不能实例化对象,因此必须要被继承,只有被继承后,抽象类中的方法和变量才能使用

2. 抽象方法

  • 抽象方法一定在抽象类里,抽象类中不一定有抽象方法
  • 抽象方法只包含一个方法名,而没有方法体
  • 若一个类继承了一个抽象类,则一定要重写抽象类中的抽象方法,除非该类也是抽象类
  • 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法
public abstract class Employee
{
   private String name;
   private String address;
   private int number;
   
   public abstract double computePay();    //抽象方法无方法体
   
   //其余代码
}
public class Salary extends Employee
{
   private double salary; // Annual salary
  
   public double computePay()    //重写父类的抽象方法
   {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
 
   //其余代码
}

五、接口

1. 接口的概念

  • 接口是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。
  • 接口并不是类,类描述对象的属性和方法,接口则包含类要实现的方法
  • 接口无法被实例化,但是可以被实现
  • 一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类

接口与类的区别

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

接口特性

  • 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract
  • 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量
  • 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法

抽象类和接口的区别

  • 抽象类中可以包含非抽象方法,但接口中所有方法都是抽象方法
  • 抽象类中的成员变量可以是各种类型,而接口中的成员变量只能是 public static final 类型
  • 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
  • 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

2. 接口的声明

  • 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
  • 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
  • 接口中的方法都是公有的。
/* 文件名 : Animal.java */
interface Animal {
   public void eat();        //抽象方法
   public void travel();
}

3. 接口的实现

当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。

类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。

/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
 
   public void eat(){            //实现接口的方法
      System.out.println("Mammal eats");
   }
 
   public void travel(){        //实现接口的方法
      System.out.println("Mammal travels");
   } 
 
   public int noOfLegs(){
      return 0;
   }
 
   public static void main(String args[]){
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
}

4. 接口的继承

一个接口能继承另一个接口,和类之间的继承方式比较相似。

接口的继承使用extends关键字,子接口继承父接口的方法。

接口允许多继承,父类用逗号隔开

// 文件名: Sports.java
public interface Sports
{
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}
 
// 文件名: Football.java
public interface Football extends Sports
{
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}

5. 标记接口

没有任何方法的接口被称为标记接口。标记接口主要用于以下两种目的:

  • 建立一个公共的父接口: 正如EventListener接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。
  • 向一个类添加数据类型: 这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。

六、包

1.package

包的作用

  • 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
  • 包也采用了树形目录的存储方式,同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别
  • 包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。

以下是一些 Java 中的包:

  • java.lang-打包基础的类
  • java.io-包含输入输出功能的函数

package目录结构

在源文件开头声明package,表示该类在某个包中

package net.java.util;
public class Something{
   ...
}

上述代码中类的存储路径为 net\java\util\Something.java

编译的时候,编译器为包中定义的每个类、接口等类型各生成一个字节码文件(.class文件)

2. import

若要使用某一包内某一个类的成员,则要用import引入该类

类A要使用类B的成员,有以下方法:

  •  若两个类在同一个包中,(两个类的源文件都声明在同一个package)则类A可以使用类B的非private成员
  • 若两个类不在同一包中,类A在使用类B成员时需要加上包名
  • 若两个类不在同一包中,则类A的源文件需要import 类B所在包,然后使用类B的非private成员
import net.java.util.classname;    //引入包中某一个类
import net.java.util.* ;            //引入某一包中全部类