JAVA学习11/08——抽象类与抽象方法、匿名子类、模板方法设计模式、接口、代理模式

抽象类与抽象方法

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。

abstract 关键字的使用

  • 1.abstract:抽象的

  • 2.abstract 可以用来修饰的结构:类、方法

  • 3.abstract 修饰类:抽象类
    》 此类不能实例化
    》 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化全过程)(只要类就要构造器)
    》 开发中,都会提供抽象类的子类,让子类对象实例化,实现相关的操作

  • 4.abstract 修饰方法:抽象方法
    》抽象方法,只有方法的声明,没有方法体。
    》包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法
    》若子类重写了父类中的所有的抽象方法后(直接和间接都要重写),此子类方可实例化
    若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

abstract 使用上的注意点:

  • 1.abstract 不能用来修饰变量、代码块、构造器;

  • 2.abstract 不能用来修饰私有方法、静态方法、final 的方法、final 的类。

public class AbstractTest {
	public static void main(String[] args) {
		//一旦 Person 类抽象了,就不可实例化
//		Person p1 = new Person();
//		p1.eat();
		
	}
}

abstract class Creature{
	public abstract void breath();
}

abstract class Person extends Creature{
	String name;
	int age;
	
	public Person(){
		
	}
	
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	//不是抽象方法
//	public void eat(){
//		System.out.println("人吃饭");
//	}
	
	//抽象方法
	public abstract void eat();
	
	public void walk(){
		System.out.println("人走路");
	}
}

class Student extends Person{
	public Student(String name,int age){
		super(name,age);
	}
	public void eat(){
		System.out.println("学生应该多吃有营养的。");
	}
	@Override
	public void breath() {
		System.out.println("学生应该呼吸新鲜的无雾霾空气");
	}
}

创建抽象类的匿名子类对象

  • 抽象类的匿名子类
    这个类只使用一次的情况就用匿名子类
public class PersonTest {
	public static void main(String[] args) {
		
		method(new Student());	//匿名对象
		
		Worker worker = new Worker(); 
		method1(worker);	//非匿名的类非匿名的对象
		
		method1(new Worker());	//非匿名的类匿名的对象
		
		System.out.println("*********************");
		
		//创建了一个匿名子类的对象:p
		Person p = new Person(){

			@Override
			public void eat() {
				System.out.println("吃东西");
			}

			@Override
			public void breath() {
				System.out.println("呼吸空气");
			}
			
		};
		method1(p);
		System.out.println("**********************"); 
		//创建匿名子类的匿名对象
		method1(new Person(){

			@Override
			public void eat() {
				System.out.println("吃零食");
			}

			@Override
			public void breath() {
				System.out.println("云南的空气");
			}
			
		});
	}
	
	public static void method1(Person p){
		p.eat();
		p.walk();
	}
	
	public static void method(Student s){
		
	}
}
class Worker extends Person{
	
	@Override
	public void eat() {
	}

	@Override
	public void breath() {
	}
}

多态的应用:模板方法设计模式

抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。

解决的问题:

当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。

  • 抽象类的应用:模板方法的设计模式

例一

public class TemplateTest {
	public static void main(String[] args) {
		
		SubTemlate t = new SubTemlate();
		
		t.sendTime();
	}
}
abstract class Template{
	
	//计算某段代码执行所需花费的时间
	public void sendTime(){
		
		long start = System.currentTimeMillis();
		
		code();	//不确定部分,易变的部分
		
		long end = System.currentTimeMillis();
		
		System.out.println("花费的时间为:" + (end - start));
	}
	
	public abstract void code();
}

class SubTemlate extends Template{
	
	@Override
	public void code() {
		
		for(int i = 2;i <= 1000;i++){
			boolean isFlag = true;
			for(int j = 2;j <= Math.sqrt(i);j++){
				if(i % j == 0){
					isFlag = false;
					break;
				}
			}
			if(isFlag){
				System.out.println(i);
			}
		}
	}
}

例二

//抽象类的应用:模板方法的设计模式
public class TemplateMethodTest {

	public static void main(String[] args) {
		BankTemplateMethod btm = new DrawMoney();
		btm.process();

		BankTemplateMethod btm2 = new ManageMoney();
		btm2.process();
	}
}
abstract class BankTemplateMethod {
	// 具体方法
	public void takeNumber() {
		System.out.println("取号排队");
	}

	public abstract void transact(); // 办理具体的业务 //钩子方法

	public void evaluate() {
		System.out.println("反馈评分");
	}

	// 模板方法,把基本操作组合到一起,子类一般不能重写
	public final void process() {
		this.takeNumber();

		this.transact();// 像个钩子,具体执行时,挂哪个子类,就执行哪个子类的实现代码

		this.evaluate();
	}
}

class DrawMoney extends BankTemplateMethod {
	public void transact() {
		System.out.println("我要取款!!!");
	}
}

class ManageMoney extends BankTemplateMethod {
	public void transact() {
		System.out.println("我要理财!我这里有 2000 万美元!!");
	}
}

接口

概述
一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java 不支持多重继承。有了接口,就可以得到多重继承的效果。

另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有 is-a 的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3 机、手机、数码相机、移动硬盘等都支持 USB 连接。

接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。继承是一个"是不是"的关系,而接口实现则是"能不能"的关系。

接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守

接口的使用

  • 1.接口使用 interface 来定义。

  • 2.在 Java 中:接口和类是并列的两个结构

  • 3.如何去定义两个接口:定义接口中的成员

  • 3.1 JDK7 及以前:只能定义全局常量和抽象 方法
    》全局常量:public static final 的,但是书写中,可以省略不写。
    》抽象方法:public abstract 的

  • 3.2 JDK8:除了全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)。

  • 4.接口中不能定义构造器!意味着接口不可以实例化。

  • 5.Java 开发中,接口通过让类去实现(implements)的方式来使用。
    如果实现类覆盖了接口中的所有方法,则此实现类就可以实例化
    如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类

  • 6.Java 类可以实现多个接口 —》弥补了 Java 单继承性的局限性

  • 格式:class AA extends BB implementd CC,DD,EE

  • 7.接口与接口之间是继承,而且可以多继承


  • 8.接口的具体使用,体现多态性
    接口的主要用途就是被实现类实现。(面向接口编程)
  • 9.接口,实际可以看作是一种规范
    接口(interface)是抽象方法和常量值定义的集合。
  • 接口的特点:
  • 用 interface 来定义。
  • 接口中的所有成员变量都默认是由 public static final 修饰的。
  • 接口中的所有抽象方法都默认是由 public abstract 修饰的。
  • 接口中没有构造器。
  • 接口采用多继承机制。
  • 面试题:抽象类与接口有哪些异同?
public class InterfaceTest {
	public static void main(String[] args) {
		System.out.println(Flayable.MAX_SPEED);
		System.out.println(Flayable.MIN_SPEED);
	}
}
interface Flayable{
	
	//全局变量
	public static final int MAX_SPEED = 7900;	
	int MIN_SPEED = 1;//省略了 public static final 
	
	//抽象方法
	public abstract void fly();
	
	void stop();//省略了 public abstract 
	//Interfaces cannot have constructors
//	public Flayable(){
//		
//	}	
}
interface Attackable{
	void attack();
}

class Plane implements Flayable{

	@Override
	public void fly() {
		System.out.println("飞机通过引擎起飞");
		
	}

	@Override
	public void stop() {
		System.out.println("驾驶员减速停止");
	}
	
}
abstract class Kite implements Flayable{

	@Override
	public void fly() {
		
	}
}

class Bullet extends Object implements Flayable,Attackable,CC{

	@Override
	public void attack() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void method1() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void method2() {
		// TODO Auto-generated method stub
		
	}
}

//*********************************
interface AA{
	void method1();
}
interface BB{
	void method2();
}
interface CC extends AA,BB{
	
}

举例

  • 接口的使用
  • 1.接口使用上也满足多态性
  • 2.接口,实际上就是定义了一种规范
  • 3.开发中,体会面向接口编程!
public class USBTest {
	public static void main(String[] args) {
		
		Computer com = new Computer();
		//1.创建了接口的非匿名实现类的非匿名对象
		Flash flash = new Flash();
		com.transferData(flash); 
		//2. 创建了接口的非匿名实现类的匿名对象
		com.transferData(new Printer());
		//3. 创建了接口的匿名实现类的非匿名对象
		USB phone = new USB(){

			@Override
			public void start() {
				System.out.println("手机开始工作");
			}

			@Override
			public void stop() {
				System.out.println("手机结束工作");
			}
			
		};
		com.transferData(phone);
		//4. 创建了接口的匿名实现类的匿名对象
		com.transferData(new USB(){
			@Override
			public void start() {
				System.out.println("mp3 开始工作");
			}

			@Override
			public void stop() {
				System.out.println("mp3 结束工作");
			}
		});
	}
}

class Computer{
	
	public void transferData(USB usb){//USB usb = new Flash();
		usb.start();
		
		System.out.println("具体传输数据的细节");
		
		usb.stop();
	}
	
}

interface USB{
	//常量:定义了长、宽
	void start();
	
	void stop();
}
class Flash implements USB{

	@Override
	public void start() {
		System.out.println("U 盘开始工作");
	}

	@Override
	public void stop() {
		System.out.println("U 盘结束工作");
	}
}
class Printer implements USB{
	@Override
	public void start() {
		System.out.println("打印机开启工作");
	}

	@Override
	public void stop() {
		System.out.println("打印机结束工作");
	}
	
}

接口的应用:代理模式(Proxy)

代理模式是 Java 开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
在这里插入图片描述

举例

public class StaticProxyTest {

	public static void main(String[] args) {
		Proxy s = new Proxy(new RealStar());
		s.confer();
		s.signContract();
		s.bookTicket();
		s.sing();
		s.collectMoney();
	}
}

interface Star {
	void confer();// 面谈

	void signContract();// 签合同

	void bookTicket();// 订票

	void sing();// 唱歌

	void collectMoney();// 收钱
}
//被代理类
class RealStar implements Star {

	public void confer() {
	}

	public void signContract() {
	}

	public void bookTicket() {
	}

	public void sing() {
		System.out.println("明星:歌唱~~~");
	}

	public void collectMoney() {
	}
}

//代理类
class Proxy implements Star {
	private Star real;

	public Proxy(Star real) {
		this.real = real;
	}

	public void confer() {
		System.out.println("经纪人面谈");
	}

	public void signContract() {
		System.out.println("经纪人签合同");
	}

	public void bookTicket() {
		System.out.println("经纪人订票");
	}

	public void sing() {
		real.sing();
	}

	public void collectMoney() {
		System.out.println("经纪人收钱");
	}
}

接口面试题1

interface A {
	int x = 0;
}
class B {
	int x = 1;
}
class C extends B implements A {
	public void pX() {
//		编译不通过,x 不明确
		System.out.println(x);
//		System.out.println(super.x); //1
//		System.out.println(A.x);//0
	}
	public static void main(String[] args) {
		new C().pX();
	}
}

接口面试题2

interface Playable {
	void play();
}
interface Bounceable {
	void play();
}
interface Rollable extends Playable, Bounceable {
	Ball ball= new Ball("PingPang"); //省略了 public static final
}
public class Ball implements Rollable {
	private String name;
	public String getName() {
		return name;
	}
	public Ball(String name) {
		this.name= name;
	}
	public void play() {
		ball = new Ball("Football"); //The final field Rollable.ball cannot be assigned	
		System.out.println(ball.getName());
	}
}

java 8 中关于接口的改进
Java 8 中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个抽象定义的理念。

静态方法:

使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中找到像 Collection/Collections 或者 Path/Paths 这样成对的接口和类。

默认方法:

默认方法使用 default 关键字修饰。可以通过实现类对象来调用。我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。比如:java 8 API 中对 Collection、List、Comparator 等接口提供了丰富的默认方法。
使用

  • 知识点 1:接口中定义的静态方法,只能通过接口来调用。
  • 知识点 2:通过实现类的对象,可以调用接口中的默认方法。
    如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
  • 知识点 3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。–>类优先原则
  • 知识点 4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错。–>接口冲突
    这就需要我们必须在实现类中重写此方法
  • 知识点 5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
ublic static void main(String[] args) {
		SubClass s = new SubClass();
//		s.method1();
//		SubClass.method1();
//		知识点 1:接口中定义的静态方法,只能通过接口来调用。
		CompareA.method1();
//		知识点 2:通过实现类的对象,可以调用接口中的默认方法。
//		如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
		s.method2();
//		知识点 3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,
//		那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则
//		知识点 4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
//		那么在实现类没有重写此方法的情况下,报错。-->接口冲突。
//		这就需要我们必须在实现类中重写此方法
		s.method3();
		
	}
}
class SubClass extends SuperClass implements CompareA,CompareB{
	
	public void method2(){
		System.out.println("SubClass:上海");
	}
	
	public void method3(){
		System.out.println("SubClass:深圳");
	}
	
//	知识点 5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
	public void myMethod(){
		method3(); //调用自己定义的重写的方法
		super.method3(); //调用的是父类中声明的
//		调用接口中的默认方法
		CompareA.super.method3();
		CompareB.super.method3();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值