稳稳当当学java之抽象类和接口(11)

第十三章 抽象类和接口

1.作业回顾

1,编写一个Person类,包括属性(name、age),有参构造器、方法say(返回自我介绍的字符串)。

2.编写一个Student类,继承Person类,增加sno、score属性,以及有参构造器,在子类中调用父类的构造器。

3.编写一个方法showInfo(返回自我介绍的字符串)。

1.编写一个Person类,包括属性(name、age),有参构造器、方法say(返回自我介绍的字符串)。

public class Person {
	//属性(name、age)
	private String name;
	private int age;
	
	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 Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	
	//方法say(返回自我介绍的字符串)
	public String say() {
		return "我叫" + name + ",我今年:" + age + "岁了";
	}	
}
//2.编写一个Student类,继承Person类,增加sno、score属性,以及有参构造器,在子类中调用父类的构造器。

public class Student extends Person {
	//增加sno、score属性
	private int sno;
	private int score;
	
	public int getSno() {
		return sno;
	}
	public void setSno(int sno) {
		this.sno = sno;
	}
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
	
	//有参构造器
	public Student(String name, int age, int sno, int score) {
		super(name, age);
		this.sno = sno;
		this.score = score;
	}
	
	//3.编写一个方法showInfo(返回自我介绍的字符串)。
	public String showInfo() {
		return super.say() + "我的学号是" + sno + "我的分数是" + score;
	}	
}

public class Day128 {
	
	//1.编写一个Person类,包括属性(name、age),有参构造器、方法say(返回自我介绍的字符串)。 
	//2.编写一个Student类,继承Person类,增加sno、score属性,以及有参构造器,在子类中调用父类的构造器。
	//3.编写一个方法showInfo(返回自我介绍的字符串)。
	
	public static void main(String[] args) {
		Student s = new Student("张三", 20, 20191101, 100);
		System.out.println(s.showInfo());			
	}//我叫张三,我今年:20岁了我的学号是20191101我的分数是100
}

2.继承规则二

子类并不会继承超类的private成员,但是子类可以调用超类的public,protected,default方法来访问超类的私有字段。

public class Animal {
	private String name;

	public Animal(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

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

public class Dog extends Animal{
	private int age;

	public Dog(String name, int age) {
		super(name);
		this.age = age;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	
	public void say() {
		System.out.println("我叫" + getName() + "我今年" + age + "岁了");
	}
}
public class Day1302 {
	public static void main(String[] args) {
		Dog d = new Dog("小狗1", 10);
		d.say(); //我叫小狗1我今年10岁了
	}
}

父类型的变量可以引用子类型的对象

import java.util.Date;

class Animal {

}

class Pet extends Animal {

}

class Dog extends Pet {

}

public class Day1303 {
	public static void main(String[] args) {
		//超类型的变量可以引用子类型的对象
		Animal a1 = new Pet();
		Animal a2 = new Dog();
		Pet a3 = new Dog();
		
		//由于Object类是所有类型的的超类,因此Object类的变量可以引用任何类的实例
		Object o1 = new Animal();
		Object o2 = new String();
		Object o3 = new Date();
	}
}

java中不支持多继承,即只能继承一个类。但是可以使用继承链。

class Dog extends Animal,Pet { //编译错误
    
}

3.方法重写

子类可以创建和超类拥有同样签名(方法名和参数列表)的方法,这叫做方法重写。

class Animal {
	public void bark() {
		System.out.println("不知道");
	}
}

class Cat extends Animal {
	public void bark() {
		System.out.println("喵喵喵");
	}
}

public class Day1304 {
	public static void main(String[] args) {
		Cat c = new Cat();
		c.bark();
	}
}

方法重写的规则

1.子类重写的方法不能比超类有更小的访问权限。

2.被标记为final的方法不能被重写。

3.在重写的方法中可以使用super关键字来调用其超类的方法。

4.重写方法的返回值类型不能比父类的大。

5.子类只能重写它可见的方法。 static成员不考虑继承问题,因此不能被重写。

4.多态

多态是指:执行同一个方法却产生不同的行为。 多态的前提是继承和方法重写。

多态:执行哪个方法看的是引用的对象的类型,而不是变量的类型。

class Animal {
	public void bark() {
		System.out.println("不知道");
	}
}

class Dog extends Animal {
	public void bark() {
		System.out.println("汪汪汪");
	}
}

class Cat extends Animal {
	public void bark() {
		System.out.println("喵喵喵");
	}
}

public class Day1305 {
	public static void main(String[] args) {
		//执行同一个方法却产生不同的行为
		//a1引用的是Animal类型的对象,因此会调用Animal类的bark方法,运行时看对象的类型
		Animal a1 = new Animal();
		a1.bark(); //不知道
		
		//a2引用的是Dog类型的对象,因此会调用Dog类的bark方法,运行时看对象的类型
		Animal a2 = new Dog();
		a2.bark(); //汪汪汪
		
		//a3引用的是Cat类型的对象,因此会调用Cat类的bark方法,运行时看对象的类型
		Animal a3 = new Cat();
		a3.bark(); //喵喵喵
		
		//执行同一个方法却产生不同的行为
		Animal[] arr = { new Animal(), new Dog(), new Cat()};
		//调用实际引用的对象的方法
		arr[0].bark(); //不知道
		arr[1].bark(); //汪汪汪
		arr[2].bark(); //喵喵喵
	}	
}
class Animal {
	public void bark() {
		System.out.println("不知道");
	}
}

class Dog extends Animal {
	public void bark() {
		System.out.println("汪汪汪");
	}

	public void run() {
		System.out.println("run");
	}
}

public class Day1306 {
	public static void main(String[] args) {
		// 变量的类型是Animal,对象的类型是Dog
		Animal a1 = new Dog();
		// 运行时看对象的类型
		a1.bark(); // 汪汪汪
		// 编译时看变量的类型,只能看到Animal类的方法,看不到实际引用对象的方法
//		a1.run(); //编译错误
		
		// 变量类型是Animal,它只能调用bark方法,但却不能调用run方法。 
		// 可以使用强制类型转换将变量a1的变量类型转换为Dog,这样就能调用run方法。
		Dog a2 = (Dog) a1;
		a2.run(); // 正确
		
		Animal a3 = new Animal(); 
		// 可以使用强制类型转换将a3的变量类型转换为Dog 
		// 但是a3,a4实际引用的是Animal类型的对象,而此对象没有run方法。
		Dog a4 = (Dog) a3; 
//		a4.run(); //运行时错误,没有run方法。编译时通过
	}
}

5.final修饰符

被final修饰的类不能被继承。

被final修饰的方法不能被重写。 被final修饰的变量不能被修改。

被final修饰的参数不能被修改。

6.抽象类

在这里插入图片描述

图形对象都具有某些属性(位置)和方法(moveTo,draw)。

对于所有的图形,这些属性和方法中的一些是相同(位置,moveTo)。draw有些特殊。每个子类的draw方法提供的功能不同。

可以在父类中提供一个draw方法,在 子类中使用方法重写来完成特定的draw方法。

class GraphicObject {
	// x,y代表图形的位置
	protected int x;
	protected int y;

	public GraphicObject(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}

	// 移动到(x,y)点上
	void moveTo(int x, int y) {
		this.x = x;
		this.y = y;
	}

	void shoeLocation() {
		System.out.println("x = " + x + ", y = " + y);
	}

	void draw() {
		// 不确定要画什么,无法实现
	}
}

class Circle extends GraphicObject {
	// 构造器
	Circle(int x, int y) {
		super(x, y);
	}

	public void draw() {
		System.out.println("画一个圆[" + x + ", " + y + "]");
	}
}

class Rectangle extends GraphicObject {
	// 构造器
	Rectangle(int x, int y) {
		super(x, y);
	}

	public void draw() {
		System.out.println("画一个矩形[" + x + ", " + y + "]");
	}
}

public class Day1307 {
	public static void main(String[] args) {
		//GraphicObject应该是抽象的,不应该有具体的对象
		GraphicObject g = new GraphicObject(0, 0);
		
		Circle c = new Circle(0, 2);
		c.shoeLocation(); //x = 0, y = 2
		c.draw(); //画一个圆[0, 2]
		
		Rectangle r = new Rectangle(5, 6);
		r.shoeLocation(); //x = 5, y = 6
		r.draw(); //画一个矩形[5, 6]
	}
}

上面的例子中存在两个问题: GraphicObject类的draw方法内部是空的,此方法应该在,因为所有图形都应该有draw方法。但是对于基类GraphicObject而言它又不知道如何实现该方法。

GraphicObject(图形)应该是抽象的,不应该有具体的对象。 对于这样的情况可以使用抽象类来实现更加优雅。

//有抽象方法的类必须声明为抽象类,因此声明GraphicObject需要加关键字abstract
//抽象类不能被实例化
abstract class GraphicObject {
	// x,y代表图形的位置
	protected int x;
	protected int y;

	public GraphicObject(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}

	// 移动到(x,y)点上
	void moveTo(int x, int y) {
		this.x = x;
		this.y = y;
	}

	void shoeLocation() {
		System.out.println("x = " + x + ", y = " + y);
	}
	
	//抽象方法,没有方法体
	//声明为抽象方法,因为不知道如何实现它
	//如果父类声明了抽象方法,那么子类就必须要实现它,因此这个方法对所有的子类进行了约束
	abstract void draw();
}

class Circle extends GraphicObject {
	// 构造器
	Circle(int x, int y) {
		super(x, y);
	}
	
	//子类必须实现实现父类的抽象方法,否则这个类必须声明为抽象类
	public void draw() {
		System.out.println("画一个圆[" + x + ", " + y + "]");
	}
}

class Rectangle extends GraphicObject {
	// 构造器
	Rectangle(int x, int y) {
		super(x, y);
	}
	
	//子类必须实现实现父类的抽象方法,否则这个类必须声明为抽象类
	public void draw() {
		System.out.println("画一个矩形[" + x + ", " + y + "]");
	}
}

public class Day1308 {
	public static void main(String[] args) {
		//GraphicObject应该是抽象的,不应该有具体的对象
		//抽象类不能创建对象
//		GraphicObject g = new GraphicObject(0, 0);
		
		Circle c = new Circle(0, 2);
		c.shoeLocation(); //x = 0, y = 2
		c.draw(); //画一个圆[0, 2]
		
		Rectangle r = new Rectangle(5, 6);
		r.shoeLocation(); //x = 5, y = 6
		r.draw(); //画一个矩形[5, 6]
	}
}

抽象类使用abstract来声明,它可以包含抽象方法,也可以不包含抽象方法。

有时候声明为抽象类,但又不包含抽象方法,仅仅是为了避免被实例化。

抽象类无法被实例化,但是可以被继承。

被abstract修饰的方法称为抽象方法,抽象方法只有声明,没有实现。 如果一个类包含了抽象方法,那它必须被声明为一个抽象类。

如果一个类继承了抽象类,它通常需要实现抽象类的抽象方法,如果没有实现,那这个子类也必须被声明为抽象的。

抽象类天生就是用来被继承的。抽象类实现了它所有子类必须使用的通用方法,这样子类就可以直接继承使用。抽象方法则留给子类根据自己的情况做不同的实现。

定义抽象方法的意义在于:给所有的子类制定一种规则,子类必须要实现抽象方法。

7.接口

接口定义了一个类所能对外提供的功能。接口不能被实例化,只能被实现。 接口可以理解为纯粹的抽象类,接口中的所有方法都是抽象的。 接口描述了一种规则。

//使用关键字interface声明一个接口。接口声明功能。
interface Flyable {
	//public abstract不是必须的,接口的方法默认是public abstract。
	//public abstract void fly();
	void fly();
}

//使用关键字implements来实现一个接口。类实现接口中声明的功能。
class Aeroplane implements Flyable {
	//实现一个接口,必须实现接口中的所有方法,否则此类必须声明为抽象类
	@Override
	public void fly() {
		System.out.println("飞机能飞,飞机使用发动机飞");	
	}	
}

class Bird implements Flyable {
	@Override
	public void fly() {
		System.out.println("鸟能飞,鸟使用翅膀飞");	
	}	
}

public class Day1309 {
	public static void main(String[] args) {
		Bird bird = new Bird();
		bird.fly(); //鸟能飞,鸟使用翅膀飞	
		Aeroplane aeroplane = new Aeroplane();
		aeroplane.fly(); //飞机能飞,飞机使用发动机飞
		
		//接口类型的变量可以引用实现了这个接口的类的实例
		Flyable flyable1 = new Bird(); //Bird实现了Flyable接口,因此这个对象可以被flyable1引用
		flyable1.fly(); //鸟能飞,鸟使用翅膀飞      多态,会调用其引用对象的fly方法
		Flyable flyable2 = new Aeroplane();//Aeroplane实现了Flyable接口,因此这个对象可以被flyable2引用
		flyable2.fly(); //飞机能飞,飞机使用发动机飞       多态,会调用其引用对象的fly方法
	}	
}

接口中的变量总是public static final的,接口中的变量不能声明为private。

interface ExampleInterface1{
	//接口中的变量默认是public static final。静态常量
    //value1,value2,value3,value4都是public static final
	int value = 10;
	public int value2 = 15;
	public static int value3 = 20;
	public static final int value4 = 25;
    
//	private int value5 = 10; //编译错误
}

接口中的方法默认是public abstract的。

interface ExampleInterface1{
	//默认是public abstract
	void method1();
	//接口中的方法不允许private
//	private void method6(); //编译错误	
}

接口继承

interface ExampleInterface1{
	
	//默认是public abstract
	void method1();
	//接口中的方法不允许private
//	private void method6(); //编译错误	
}

//子接口
interface SubInterface1 extends ExampleInterface1 {
	void method2();
}

//实现SubInterface
class C1 implements SubInterface1 {

	@Override
	public void method1() {
		
	}

	@Override
	public void method2() {
		
	}	
}

interface ExampleInterface2 {
	void method2();
}

//一个例可以实现多个接口,它必须要实现接口中的所有方法
//可以不实现接口中的所有方法,但是类必须声明为抽象类。
class SampleImpl implements ExampleInterface1, ExampleInterface2 {

	@Override
	public void method2() {
		System.out.println("method2的实现");	
	}

	@Override
	public void method1() {
		System.out.println("method1的实现");	
	}	
}

public class Day1310 {
	public static void main(String[] args) {
		//接口类型的变量可以引用实现了这个接口的类的实例
		ExampleInterface1 i1 = new SampleImpl();
		i1.method1(); //调用SampleImpl对象的method1方法    //method1的实现
//		i1.method2(); //编译错误,看不到method2方法
		
		ExampleInterface2 i2 = new SampleImpl();
		i2.method2(); //调用SampleImpl对象的method2方法    //method2的实现
//		i1.method1(); //编译错误,看不到method1方法
		
		ExampleInterface1 i3 = (ExampleInterface1)i2;
		i3.method1(); //编译正确,能看到method1方法              //method1的实现
//		i3.method2(); //编译错误,看不到method2方法
	}	
}

8.练习

1,将Frock类声明为抽象类,尺寸在Frock类中定义,在类中声明抽象方法calcArea方法,用来计算衣服的布料面积。编写Shirt类继承Frock类,实现 calcArea方法,用来计算衬衣所需的布料面积(尺寸 * 1.3)。编写Coat类继承Frock类,实现 calcArea方法,用来计算外套所需的布料面积(尺寸*1.5)。编写Test类,测试calcArea方法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十年之伴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值