1.面向对象三大特性(2)继承
1. 继承的概述:多个类中存在相同的属性和行为时,将这些内容抽取到单独的父类中,那么这个类无需再定义这些属性和行为,只需要继承这个类即可
2. 继承的格式:class 子类名 extends 父类名{ }
3. 继承的代码示例
public class TestDemo {
public static void main(String[] args) {
Dog dog = new Dog();
dog.age = 5;
dog.name = "旺财";
System.out.println(dog.age);
System.out.println(dog.name);
dog.eat();
dog.sleep();
dog.lookDoor();
System.out.println("===============");
Cat cat = new Cat();
cat.age = 4;
cat.name = "啦啦";
System.out.println(cat.age);
System.out.println(cat.name);
cat.eat();
cat.sleep();
cat.catchMouse();
}
}
class Animal{
int age;
String name;
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
class Dog extends Animal{
public void lookDoor(){
System.out.println("狗看门");
}
}
class Cat extends Animal{
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
//输出结果
/*
5
旺财
吃饭
睡觉
狗看门
===============
4
啦啦
吃饭
睡觉
猫抓老鼠
*/
4. 继承的好处:提高了代码的复用性、维护性、让类与类之间产生了关系
5. 继承的弊端:类的耦合性增强了
PS:开发的原则:高内聚,底耦合
6. 继承的特点:
(1)Java只支持单继承,不支持多继承:一个类只有一个父类。但是一个父类可以有多个子类
(2)Java支持多层继承:子类- -父类- -父类
//Son -- Father -- Grandfather
public class TestDemo2 {
public static void main(String[] args) {
Son son = new Son();
System.out.println(son.g); //ggg
System.out.println(son.f); //fff
System.out.println(son.s); //sss
son.show(); //爷爷类中的show方法
son.fuShow(); //父类中的show方法
son.sonShow(); //Son类中的show方法
}
}
class Grandfather{
String g = "ggg";
public void show(){
System.out.println("爷爷类中的show方法");
}
}
class Father extends Grandfather{
String f = "fff";
public void fuShow(){
System.out.println("父类中的show方法");
}
}
class Son extends Father{
String s = "sss";
public void sonShow(){
System.out.println("Son类中的show方法");
}
}
7. 继承的注意事项
(1)子类只能继承父类所有非私有的成员(成员方法和成员变量)
(2)构造方法不参与继承
public class TestDemo3 {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println(zi.age); //50
// zi.name; //报错 无法访问
// zi.show(); //报错,无法访问
zi.show2(); //公共的show方法
}
}
class Fu{
private String name = "fu";
int age = 50;
private int num = 3000;
private void show(){
System.out.println("私有show方法");
}
public void show2(){
System.out.println("公共的show方法");
}
}
class Zi extends Fu{
}
8. 继承中访问变量的规则
(1)子类的成员变量和父类的成员变量不一样,按照名称访问
(2)子类的成员变量与父类的成员变量一样:就近原则
9. this和super的应用
(1)this代表本类对象的引用,super代表父类存储空间的标识
(2)this和super的使用:调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
public class TestDemo01 {
public static void main(String[] args) {
Zi zi = new Zi();
zi.show(20);
}
}
class Fu{
int num = 200;
}
class Zi extends Fu{
int num = 600;
public void show(int num){
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
}
}
//输出结果
/*
20
600
200
*/
(3)this和super的使用:调用构造方法
有了继承关系后,我们在初始化子类的时候先要初始化父类的数据,即:我们在创建子类对象的时候,要先调用父类的构造方法,来完成父类数据的初始化,然后在初始化自己的数据。在每个类的构造方法中的第一行有一行默认的代码super(),在行代码就去调用父类的空参构造
this(…) 调用本类的构造方法
super(…) 调用父类的构造方法
public class TestDemo02 {
public static void main(String[] args) {
Son son = new Son();
/*
父类构造方法执行了
子类构造方法执行了
*/
}
}
class Father{
public Father(){
System.out.println("父类构造方法执行了");
}
}
class Son extends Father{
public Son(){
System.out.println("子类构造方法执行了");
}
}
(4)this和super的使用:调用成员方法
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法
public class TestDemo01 {
public static void main(String[] args) {
Zi zi = new Zi();
zi.test();
}
}
class Fu{
int fuNum = 200;
int f = 600;
public void fuShow(){
System.out.println("父类的show方法");
}
}
class Zi extends Fu{
int num = 20;
int f = 9000;
public void ziShow(){
System.out.println("子类的show方法");
}
public void test(){
System.out.println(super.fuNum); //200
System.out.println(super.f); //600
System.out.println(this.f); //9000
System.out.println(this.num); //20
System.out.println("=================");
ziShow(); //子类的show方法
super.fuShow(); //父类的show方法
this.fuShow(); //父类的show方法
}
}
10. 方法重写
(1)方法重写的概述:子类如果对父类的方法不满意,那么子类可以重写父类中的方法,所以子类中出现了和父类一模一样的方法声明(方法名,参数列表,返回值类型),所以也称为方法覆盖
(2)方法重写的注意事项
①父类中私有的方法不能重写,因为父类中私有的方法根本就不能继承
②子类重写父类方法时,访问权限不能低于父类方法,最好是一样的
③如果还要保留父类的功能,并在此基础上进行扩展,使用super.方法名
④父类的static方法,不能被重写,可以被继承
(3)ctrl+o:在idea中调用方法重写 @Override
public class TestDemo02 {
public static void main(String[] args) {
IPhone ip = new IPhone();
ip.call(); //打视频电话
ip.sendMsg(); //发短信 发彩信
}
}
class Phone {
public void call() {
System.out.println("打电话");
}
public void sendMsg(){
System.out.println("发短信");
}
private void playGame(){
System.out.println("玩游戏");
}
}
class IPhone extends Phone{
@Override
public void call() {
System.out.println("打视频电话");
}
@Override
public void sendMsg() {
super.sendMsg(); //如果还要保留父类的功能,并在此基础上进行扩展,使用super.方法名
System.out.println("发彩信");
}
/*@Override
public void playGame(){
}*/ //父类私有方法子类不可以继承
}
2.final关键字
1. final关键字的起源:由于继承中有一个方法重写的现象,但是有时候不想让子类重写父类的方法,所以就引入一个关键字final
2. final关键字概述:final表示最终的,可以修饰类,变量,成员方法
3. final修饰的特点
(1)final修饰类:被修饰的类不能被继承
(2)final修饰成员方法:被修饰的成员方法不能被重写
(3)final修饰变量:被修饰的变量不能被重新赋值,此变量变成一个常量
(4)final修饰局部变量:如果局部变量是基本类型,其值不能改变。如果局部变量是引用类型,其地址值不能改变
4. final关键字的代码示例
public class TestDemo01 {
public static void main(String[] args) {
final int NUM = 100;
// NUM = 200; //报错,final修饰的变量不能被重新赋值
Son son = new Son();
son.show(); //重写了Father类中的show方法
son.finalShow(); //Father类中被final修饰的方法,子类可以继承,但是不能被重写
System.out.println("================");
final Son son1 = new Son();
// son1 = new Son(); //final 修饰引用类型,指的是 地址值不能再次改变
}
}
//final 修饰类,此类不能被继承。
final class Fu{
public void show(){
System.out.println("Fu类因为被final修饰,所以不能被继承");
}
}
class Father{
public void show(){
System.out.println("Father类的show方法");
}
public final void finalShow(){
System.out.println("Father类中被final修饰的方法,子类可以继承,但是不能被重写");
}
}
class Son extends Father{
@Override
public void show() {
System.out.println("重写了Father类中的show方法");
}
}
3.面向对象三大特性(3)多态
1. 多态的概述:某一个事物,在不同时刻表现出来的不同状态
2. 多态的前提
(1)要有继承关系
(2)要有方法重写
(3)要有父类引用指向子类对象:Fu f = new Zi();
public class TestDemo01 {
public static void main(String[] args) {
//多态:父类引用 指向子类对象
Animal an = new Cat();
an.eat(); //猫吃鱼
}
}
class Animal{
public void eat(){
System.out.println("吃饭");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
3. 多态中的成员访问特点
(1)成员变量:编译看左边,运行看左边
(2)构造方法:创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化
(3)成员方法:编译看左边,运行看右边
(4)静态方法:编译看左边,运行看左边(静态和类相关,算不上重写,所以访问还是看左边的)
public class TestDemo02 {
public static void main(String[] args) {
Fu f = new Zi();
System.out.println(f.num); //20(Fu类的)
// System.out.println(f.aaa); //错误,不能访问子类的成员变量
f.show(); //子类重写了父类的show方法
f.fuStatic(); //父类的静态方法
Fu.fuStatic(); //父类的静态方法
}
}
class Fu{
int num = 20;
public Fu(){
System.out.println("父类构造方法执行了");
}
public void show(){
System.out.println("父类show方法执行了");
}
public static void fuStatic(){
System.out.println("父类的静态方法");
}
}
class Zi extends Fu{
int num = 200;
int aaa = 10;
public Zi(){
System.out.println("子类构造方法执行了");
}
@Override
public void show() {
System.out.println("子类重写了父类的show方法");
}
}
/*
父类构造方法执行了
子类构造方法执行了
20
子类重写了父类的show方法
父类的静态方法
父类的静态方法
*/
4. 多态的好处
(1)提高代码的维护性(继承)
(2)提高代码的扩展性(多态)
public class TestDemo1 {
public static void main(String[] args) {
Animal an1 = new Cat();
MyUtils.testEat(an1); //猫吃鱼
Animal an2 = new Dog();
MyUtils.testEat(an2); //狗吃骨头
Animal an3 = new Rabbit();
MyUtils.testEat(an3); //兔子吃萝卜
Animal an4 = new Panda();
MyUtils.testEat(an4); //熊猫吃竹子
}
}
class Animal{
public void eat(){
System.out.println("吃饭");
}
}
class MyUtils{ //设计一个工具类,调用动物们的eat方法
private MyUtils(){
//私有构造不能被实例化
}
public static void testEat(Animal an){
an.eat();
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
class Rabbit extends Animal{
@Override
public void eat() {
System.out.println("兔子吃萝卜");
}
}
class Panda extends Animal{
@Override
public void eat() {
System.out.println("熊猫吃竹子");
}
}
5. 多态的向下转型
(1)多态的弊端:不能使用子类特有的功能,所以提出了向下转型,把父类的引用强制转换为子类的引用
(2)向下转型的格式:Zi z = (Zi) f;
(3)向下转型的代码示例
public class TestDemo2 {
public static void main(String[] args) {
Fu f = new Zi();
f.show(); //子类重写了父类的show方法执行了
// f.showZi(); //多态形式不能直接调用子类特有的方法
// System.out.println(f.num); //多态形式也不能直接调用子类的变量
//向下转型
Zi z = (Zi) f;
System.out.println(z.num); //200
z.show(); //子类重写了父类的show方法执行了
z.showZi(); //子类特有的showZi方法执行了
}
}
class Fu{
public void show(){
System.out.println("父类的show方法执行了");
}
}
class Zi extends Fu{
int num = 200;
@Override
public void show() {
System.out.println("子类重写了父类的show方法执行了");
}
public void showZi(){
System.out.println("子类特有的showZi方法执行了");
}
}
(4)猫狗案例
public class TestDemo1 {
public static void main(String[] args) {
Animal an = new Cat();
an.eat(); //猫吃鱼
Cat c = (Cat) an;
c.catchMouse(); //猫抓老鼠
System.out.println("=================");
//重新转换对象
an = new Dog();
an.eat(); //狗吃骨头
Dog d = (Dog) an;
d.lookDoor(); //狗看门
}
}
class Animal{
public void eat(){
System.out.println("吃饭");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
public void lookDoor(){
System.out.println("狗看门");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
4.抽象类(上)
1. 抽象类的概述:在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,那么这个类必须是抽象类
2. 使用抽象类的原因:父类把子类共性内容的内容向上抽取出来,但是父类不知道子类对共性内容的具体实现,所以父类只需要给出功能的声明,不需要给出具体的实现,具体的实现交给子类来完成
3. 抽象类的特点
(1)抽象类和抽象方法的定义格式
①抽象类:abstract class 类名{}
②抽象方法:public abstract void 方法名(参数列表){}
(2)抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
(3)抽象类不能直接创建对象
(4)子类必须重写父类的抽象方法
public class TestDemo1 {
public static void main(String[] args) {
// Animal an = new Animal() //抽象类不能直接创建对象
Animal an = new Cat();
an.eat(); //猫吃鱼
an.sleep(); //猫爱白天睡觉
System.out.println("============");
an = new Dog();
an.eat(); //狗吃骨头
an.sleep(); //狗爱夜里睡觉
}
}
abstract class Animal{
public abstract void eat();
public abstract void sleep();
}
class Cat extends Animal{
//父类中的抽象方法,是强制子类必须重写
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫爱白天睡觉");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void sleep() {
System.out.println("狗爱夜里睡觉");
}
}
(5)抽象类的中的构造方法:在子类访问父类的时候进行初始化
(6)抽象类的实例化:通过多态的方式,由具体的子类进行实例化
public class TestDemo2 {
public static void main(String[] args) {
AA a = new BB();
System.out.println(a.num); //100
BB b = (BB) a;
System.out.println(b.num); //100
}
}
abstract class AA{
int num = 100;
public AA(){
System.out.println("AA的构造方法");
}
public abstract void aa();
}
class BB extends AA{
public BB() {
super();
System.out.println("BB的构造方法");
}
@Override
public void aa() {
System.out.println("重写了父类的aa方法");
}
}
/*
AA的构造方法
BB的构造方法
100
100
*/
(7)抽象类的子类,要么是抽象类,要么重写抽象类中所有的抽象方法
public class TestDemo1 {
public static void main(String[] args) {
}
}
abstract class BB{
public abstract void eat();
public abstract void sleep();
}
abstract class CC extends BB{
public abstract void haha();
}
class DD extends CC{
@Override
public void eat() {
}
@Override
public void sleep() {
}
@Override
public void haha() {
}
}
4. 抽象类的成员特点
(1)成员变量:既可以是变量,也可以是常量
(2)构造方法:有,用于子类访问父类数据的初始化
(3)成员方法:即可以是抽象的,也可以是非抽象的
5. 一个类如果没有抽象方法,也可以定义成抽象类,其目的就是为了不能创建该类的对象
6. abstract不能和几个关键字共存
(1)private(私有的):abstract定义的方法必须强制子类重写,而private修饰的方法是私有的,不能被子类继承,更不能被重写
(2)final(最终的):final修饰的方法,子类不能重写。而abstract必须强制子类重写
(3)static(静态的):static方法属于类,不参与重写。而abstract必须强制子类重写
public class TestDemo01 {
public static void main(String[] args) {
// Fu fu = new Fu(); //被abstract修饰的类不能创建对象
}
}
abstract class Fu{
// private abstract void method01(); //private不能和abstract共存
// static abstract void method02(); //static不能喝abstract共存
// public abstract final void method03(); //final不能和abstract共存
}