面向对象的三大特征:封装、继承、多态
一、继承
使用***extends***作为继承的关键字,如同于:扩展
——子类继承(扩展)了父类,只能获得父类的成员变量、方法和内部类,不能获得构造器和初始化块。
Java子类到父类的继承是一种由一般到特殊的关系,父类包含的范围比子类要大,
————子类=小类,父类=大类
eg: 老虎类继承动物类,苹果类继承水果类
格式即:
public class 子类 extends 父类
{
var 对象 = new 子类();
}
【]注】Java是单继承的,只能有一个直接父类
如果你不显式地继承父类,Java默认是继承Object类(是一种JDK系统提供的类)——一切都是Object的子类(直接或间接)——一切都是对象
继承的好处:代码的复用
(1)、创建父类:
public class Fruit
{
public double weight;
public void info()
{
System.out.println("水果,重:" + weight+"g");
}
}
(2)、定义子类
public class Pear extends Fruit
//创建了Pear这个子类(空的),继承了Fruit父类,可以获得父类的各种特性,成员变量、方法等。
{
public static void main(String[] args)
{
var a = new Pear();//创建Pear类的对象(实例),赋给变量a后,可以通过访问它来访问父类
a.weight = 100;
a.info();
}
}
或者把继承:public class Pear extends Fruit{ }单独写
再写public class PearTest{ Pear p = new Pear();}
二、方法重写(Override)
规则:
(1)2同:子类的方法重写,其方法名要相同,形参列表要相同;
(2)2小:返回值类型要相同或者更小,声明抛出的异常要相同或更小;
(3)1大:访问权限相同或更大。
eg1:
定义父类及其方法:
public class Brid
{
public void fly()
{
System.out.println("鸟会飞");
}
}
定义子类时重写其方法:
public class Ostrich extends Brid
{
//重写fly方法
@Override//用于报错
public void fly()
{
System.out.println("鸵鸟不会飞");
}
}
测试:
public class OstrichTest
{
public static void main(String[] args)
{
Ostrich os = new Ostrich();
os.fly();
}
}
加上@Override是为了在重写时如果子类方法名与父类不一致,编译时会提示这个错误,否则会视为一个新的方法。
eg2:
验证:返回值类型要相同或者更小
import java.util.*;
class Base
{
//返回值是类
public Object info() //Object是所有类的父类,所以最大
{
System.out.println("父类的info");
return new Random();
}
}
public class 方法重写 extends Base
{
@Override
public String info() //String比Object小,修饰符不能用protected
{
System.out.println("子类的info");
return "Java";
}
public static void main(String[] args)
{
var a = new 方法重写();//new 构造器
a.info();
}
}
【重申】创建对象:new 构造器(参数),由于在定义类的时候没有定义构造器,所以构造器是系统自动提供 的,所以无参数,执行体为空
典型例子
父类引用指向子类对象时:B b = new C();
1、若子类覆盖了某方法,则父类引用调用子类重新定义的新方法
2、若子类未覆盖某方法,则父类引用调用父类本身的旧方法
3、若子类覆盖了某属性,但父类引用仍调用父类本身的旧属性
4、若子类未覆盖某属性,则父类引用调用父类本身的旧属性
5、父类引用不能访问子类新定义的方法
子类引用指向自身对象时:C c = new C();
1、若子类覆盖了某方法,则子类引用调用子类重新定义的新方法
2、若子类未覆盖某方法,则子类引用调用父类本身的旧方法
3、若子类覆盖了某属性,则子类引用调用子类重新定义的新属性
4、若子类未覆盖某属性,则子类引用调用父类本身的旧属性
5、子类引用可以访问子类新定义的方法
*/
class B {
int a = 1;
int b = 2;
void f1() {
System.out.println("B.f1()");
}
void f2() {
System.out.println("B.f2()");
}
}
public class C extends B {
int a = 3;
@Override
void f1() {
System.out.println("C.f1()");
}
void f3() {
System.out.println("C.f3()");
}
public static void main(String[] args) {
B b = new C();// 父类引用指向子类对象
b.f1();// C.f1() 子类覆盖了该方法,所以父类引用调用新方法
b.f2();// B.f2() 子类未覆盖该方法,所以父类引用调用旧方法
// b.f3();//此行去掉注释会报错,父类引用不能访问子类新定义方法
System.out.println(b.a);// 1 子类覆盖了该属性,但父类引用仍旧访问旧属性
System.out.println(b.b);// 2 子类未覆盖该属性,父类访问旧属性
System.out.println();
C c = new C();// 子类引用指向自身对象
c.f1();// C.f1()
c.f2();// B.f2()
c.f3();// C.f3() 子类调用自己新定义的方法
System.out.println(c.a);// 3 子类覆盖了该属性,所以访问新属性
System.out.println(c.b);// 2 子类未覆盖该属性,所以访问旧属性
}
}