一、继承——extends
子类继承父类,子类拥有父类的变量和方法
1. 继承类型
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.* ; //引入某一包中全部类