Java面向对象【多态+抽象类+接口】

面向对象

前提

  • 要有继承关系
  • 要有方法重写
  • 要有父类引用子类对象
public class Animal {
	
	public void eat() {
		System.out.println("动物吃饭");
	}
}
public class Cat extends Animal{
	public void eat() {
		System.out.println("猫吃鱼");
	}
}
public class Dog extends Animal{
	
	public void eat() {
		System.out.println("猫吃鱼");
	}

}
public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Animal animal = new Cat();
		animal.eat();
	}

}

1. 多态中成员访问特点

1.1 成员变量

  • 编译看左边(父类),运行看左边(父类 )
public class Demo2_Polymorphic{

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Father father = new Son();
		System.out.println(father.num);
		
		Son son = new Son();
		System.out.println(son.num);
	}

}

class Father {
	int num = 10;
}

class Son extends Father{
	int num = 20; 
}

输出

10
20

原因:且看内存图
执行Father father = new Son(); father是父类,编译时只能看到 super 区域。
在这里插入图片描述

  • 执行到Son son = new Son();因为 son 是子类,所以它编译时可以看到地址0x0022中的全部内容,因为自己有num值,所以调用 son.num。
    在这里插入图片描述

1.2 成员方法

  • 编译看左边(父类),运行看右边(子类)【这种也叫动态绑定】
public class Demo2_Polymorphic {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Father father = new Son();
		father.print();
	}

}

class Father {
	int num = 10;
	public void print() {
		System.out.println("father");
	}
}

class Son extends Father{
	int num = 20; 
	public void print() {
		System.out.println("son");
	}
}

输出结果:son
原因:且看内存图

在这里插入图片描述

  • f.print() 编译时

在这里插入图片描述

  • f.print() 运行时

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

1.3 静态成员方法

  • 编译看左边(父类),运行看左边(父类 )
  • 静态和类相关,算不上重写,所以访问还是左边

所以,只有非静态的成员方法才是编译看左,运行看右

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Father father = new Son();
		father.method();    //相当于Father.method() 
	}

}

class Father {
	int num = 10;
	public void print() {
		System.out.println("father");
	}
	public static void method() {
		System.out.println("father static method");
	}
}

class Son extends Father{
	int num = 20; 
	public void print() {
		System.out.println("son");
	}
	public static void method() {
		System.out.println("son static method");
	}
}

输出:father static method

1.4 多态中向上转型和向下转型

  • Person p = new SuperMan(); // 向上转型
  • SuperMan() sm = (SuperMan)p; //向下转型

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

1.5 多态的利弊与 instanceof

好处

  • 提高代码的维护性(继承保证)
  • 提高代码的扩展性(多态保证)
  • 可以当作形式参数,可以接收任何子类对象

弊端

  • 不能使用子类特有的属性和方法

开发时很少使用父类引用指向子类对象,直接创建子类对象更方便,当作参数时使用多态最好,因为扩展性强。

public class Animal {
	
	public void eat() {
		System.out.println("动物吃饭");
	}
}
public class Cat extends Animal{
	public void eat() {
		System.out.println("猫吃鱼");
	}
	public void catMouse() {
		System.out.println("抓老鼠");
	}
}
public class Dog extends Animal{
	
	public void eat() {
		System.out.println("狗吃肉");
	}
	
	public void lookHome() {
		System.out.println("看家");
	}

}
public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//method(new Cat());
		//method(new Dog());
		
		Animal animal = new Cat();//开发时很少使用父类引用指向子类对象,直接创建子类对象更方便
		method(animal);

	}
	public static void method(Animal a) {//当作参数时使用多态最好,因为扩展性强。
		// instanceof 判断前面的引用是否是后边的数据类型
		if (a instanceof Cat) {
			Cat cat = (Cat)a;
			cat.eat();
			cat.catMouse();
		}
		else if(a instanceof Dog){
			Dog dog = (Dog)a;
			dog.eat();
			dog.lookHome();
		}
		else {
			a.eat();
		}
	}

}

1.6 面试题(有助理解)

多态调用成员方法:编译看左边,运行看右边。

public class demo1 {
    public static void main(String[] args) {
        A a=new B();
        a.show();
        B b=new C();
        b.show();
    }
}
class A{
    public void show(){
        show2();
    }
    public void show2(){
        System.out.println("我");
    }
}
class B extends A{
	/*public void show(){
        show2();
    }*/
    public void show2(){
        System.out.println("爱");
    }
}
class C extends B{
    public void show(){
        super.show();
    }
    public void show2(){
        System.out.println("你");
    }
}

输出:

爱
你

解析:

A a=new B();
a.show();

首先,编译看左边,A类中有show()方法,所以不会报错,编译通过;运行看右边,B类没有show()方法,但是因为他是 A 的子类,父类中有show()方法,且调用的show2()方法。【所以你就当作他有show()方法,且调用show2()】

B b=new C();
b.show();

首先,编译看左边,B类中没有show()方法,但是因为他是 A 的子类,父类中有show()方法,所以编译通过;运行看右边, 调用super.show() 我们可以把A中的show()当作是B中的show(),且调用show2()。C类有show2()方法,所以直接运行。

2. 抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

特点:

  • 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类或者接口
  • 抽象类不能被实例化
  • 抽象类的子类要么是抽象类,要么重写父类所有的抽象方法。

注意:在 Java 中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。

2.1 抽象类成员特点

  • 成员变量:可以是变量,也可以是final常量,abstract不能修饰成员变量。
  • 构造方法:有
  • 成员方法
    • 抽象方法:强制要求子类必须做的事,所以子类必须重写
    • 非抽象类:子类继承的事情,提高代码复用率
public abstract class Animal {
	
	private String name;
	private int age;
	
	public Animal() {}//空参
	public Animal(String name,int age) {//有参
		this.name = name;
		this.age = age;
	}
	
	public abstract void eat();

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	
}

public class Dog extends Animal{
	
	public Dog() {}
	
	public Dog(String name,int age) {
		super(name,age);
	}
	public void eat() {
		System.out.println("狗吃肉");
	}
	
	public void lookHome() {
		System.out.println("看家");
	}

}
public class Cat extends Animal{
	
	public Cat() {}
	
	public Cat(String name,int age) {
		super(name,age);
	}
	
	public void eat() {
		System.out.println("猫吃鱼");
	}
	
	public void catMouse() {
		System.out.println("抓老鼠");
	}
}
public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Cat cat = new Cat("加菲",8);
		System.out.println(cat.getName()+"........"+cat.getAge());
		cat.eat();
		cat.catMouse();
		
		Dog dog  = new  Dog();
		System.out.println(dog.getName()+"........"+dog.getAge());
		dog.eat();
		dog.lookHome();

	}
}
加菲........8
猫吃鱼
抓老鼠
null........0
狗吃肉
看家

2.2 抽象类面试题

在这里插入图片描述

2.3 总结

  1. 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。

  2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

  3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。

  4. 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法

  5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

3. 接口

概念:

  • 从狭义的角度讲就是指 java 中的 interface
  • 从广义的角度讲对外提供规则的都是接口。

特点

  • 接口用关键字interface表示
    • interface 接口名{}
  • 接口中方法都是抽象的
  • 类实现接口用implements表示
    • class类名implements 接口名{}
  • 接口不能实例化
    • 那么,接口如何实例化呢?
    • 按照多态的方式来实例化。
  • 接口的子类
    • 可以是抽象类。但是意义不大。
    • 可以是具体类。要重写接口中的所有抽象方法。(推荐方案)

3.1 接口的成员特点

成员变量;只能是常量,并且是静态的并公共的。

  • 默认修饰符: public static final
  • 建议:自己手动给出。

构造方法:

  • 接口没有构造方法。

成员方法:只能是抽象方法

  • 默认修饰符: public abstract
  • 建议:自己手动给出。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值