JAVA基础(10.接口和多态)

目录

1. 接口(重点)

1.1接口

1.1.1 概念理解

1.1.2 接口申明&多继承性

1.2接口实现类

1.2.1 接口实现类概念

1.2.2 接口与实现类案例

2. 多态(polymorphic)

2.1 什么是多态? 

2.2 多态作用:

2.3 多态使用:(重点)

2.4 多态注意事项:


1. 接口重点

1.1接口

1.1.1 概念理解

接口是一种约定规范,是多个抽象方法的集合。仅仅只是定义了应该有哪些功能,本身不实现功能,

至于每个功能具体怎么实现,就交给实现类完成

接口中的方法是抽象方法,并不提供功能实现,体现了规范和实现相分离的思想,也体现了组件之间

低耦合的思想。

所谓耦合度,表示组件之间的依赖关系。依赖关系越多,耦合性越强,同时表明组件的独立性越差,

在开发中往往提倡降低耦合性,可提高其组件独立性,举一个低耦合的例子。

电脑的显卡分为集成显卡和独立显卡:

n 集成显卡:显卡和主板焊死在一起,显卡坏了,只能换主板

n 独立显卡:显卡和主板相分离,显卡插到主板上即可,显卡坏了,只换显卡,不用换主板

接口也体现的是这种低耦合思想,接口仅仅提供方法的定义,却不提供方法的代码实现。那么得专门

提供类并去实现接口,再覆盖接口中的方法,最后实现方法的功能,在多态案例中再说明

1.1.2 接口申明&多继承性

接口可以认为是一种特殊的类,但是定义类的时候使用 class 关键字,定义接口使用 interface 关键字

public interface 接口名{

抽象方法 1();

抽象方法 2();

抽象方法 2();

}

接口表示具有某些功能的事物,接口名使用名词,有人也习惯以 I 打头如 IWalkable.java。

接口定义代码:

public interface IWalkable {

void walk();

}

接口中的方法都是公共的抽象方法,等价于:

public interface IWalkable {

public abstract void walk();

}

类可以继承类,但是只能单继承的,接口也可以继承接口,但是却可以继承多个接口,也就是说一个

接口可以同时继承多个接口,如两栖动物可以行走也可以拥有。

可行走规范:

public interface IWalkable {

void walk();

}

可游泳规范:

public interface ISwimable {

void swim();

}

两栖动物规范,即可以游泳,又可以行走。

public interface IAmphibiable extends IWalkable,ISwimable{

}

此时子接口能继承所有父接口的方法。

1.2接口实现类

1.2.1 接口实现类概念

和抽象类一样,接口是不能创建对象的,此时必须定义一个类去实现接口,并覆盖接口中的方法,这

个类称之为实现类,类和接口之间的关系称之为实现关系(implements)。

public class 类名 implements 接口名 1,接口名 2{

覆盖接口中抽象方法

}

在类实现接口后,覆盖接口中的抽象方法,完成功能代码,此时接口和实现类之间的关系:

n 接口:定义多个抽象方法,仅仅定义有哪些功能,却不提供实现。

n 实现类:实现接口,覆盖接口中抽象方法,完成功能具体的实现。

1.2.2 接口与实现类案例

/**
 *	IUSB3_0接口
 *	1. 接口interface语法:(重点)
		声明接口语法:
			public interface I接口名 {
		 		全局常量;// 默认都会有一个public static final修饰成员变量,建议简写	// 调用方式:只能是通过: 接口名.常量名;
					【必须是声明的同时接着赋值】 	命名:全大写用_隔开:MAX_VALUE					
		 		抽象方法;// 前面会有默认的public abstract修饰,可以简写
		 
		 		// 从jdk1.7开始有的
		 		public default 返回值类型 方法名(...){  // 调用方式:只能是通过  实现类对象.方法名(...);
		 			
		 		}
				// 从jdk1.7开始有的
		 		public static 返回值类型 方法名(...){  // 调用方式:只能是通过: 接口名.方法名(...);
		 
		 		}
		 		
		 		接口没有构造方法,语法规定
		 	}
		 	
		按照上面的语法提示,将接口中所有的成员写出来即可
		 	
		 接口要使用,必须有实现类:
		 语法:
		 	public(abstract) class 接口名Impl implements 接口名1,接口2...{
		 		如果是一个非抽象的类必须重写全部的抽象方法
		 	}
		 	
	4 注意事项 (重点)
		1. 接口命名规则:IXxx【I接口名:不是阿里巴巴规范要求,只是建议的写法】
 		2. 接口实现类命名规则:接口名Impl
		3. 接口中没有构造方法,也不能new对象
 		4. 如果接口中只有一个抽象方法,该接口就是函数式接口,函数式接口可以用@FunctionalInterface
 		 注解修饰,函数式接口可以使用jdk8新特性lambda表达式。
 		 
		5. 只要一个接口中只有一个抽象方法,不管有没有@FunctionalInterface,该接口都是函数式接口。
		6. 接口必须被子类通过implements全部实现其内的抽象方法
		
 */
@FunctionalInterface // 该注解,表示当前接口是函数式接口。函数式接口可以使用jdk8新特性lambda表达式。
public interface IMyInterface {// 按照上面的语法提示,将接口中所有的成员写出来即可
	/** 全局常量: public static final 数据类型 常量名[全大写,下划线隔开],声明同时必须直接赋值 */
	public static final int MAX_VALUE = 2;// 调用方式: 接口名.常量名;
	
	/** 全局常量: 数据类型 常量名[全大写,下划线隔开],声明同时必须直接赋值。简写,省略了修饰符 */
	int MIN_VALUE = 1;// 前面默认会有:public static final修饰,建议省略 
	
	/**
	 * testAbstract抽象方法
	 */
	void testAbstract();// 默认前面有	public abstract修饰,建议省略
	
	/**
	 *  从jdk1.7开始有的default方法语法:
	 *  public default 返回值类型 方法名(...) {  // 调用方式:实现类对象.方法名(...);
		
		}
	 */
	public default void testDefault1() {
		System.out.println("testDefault1");
	}
	
	/**
	 *  从jdk1.7开始有的default方法语法:
	 *  public default 返回值类型 方法名(...) {  // 调用方式:实现类对象.方法名(...);
		
		}
	 */
	public default void testDefault2() {
		System.out.println("testDefault2....");
	}
	
	/**
	 *  从jdk1.7开始有的static方法语法:
	 *  public static 返回值类型 方法名(...) {  // 调用方式: 接口名.方法名(...);

		}
	 */
	public static void testStatic1() {
		System.out.println("testStatic1------>");
	}
	
	/**
	 *  从jdk1.7开始有的static方法语法:
	 *  public static 返回值类型 方法名(...) {  // 调用方式: 接口名.方法名(...);

		}
	 */
	public static void testStatic2() {
		System.out.println("testStatic2=============>");
	}
	
	// 没有构造方法
//	public IMyInterface() {}
	
}

实现类:
/**
 *	IMyInterface接口实现类MyInterfaceImpl
 *	 接口实现类语法:
	 	public(abstract) class 接口名Impl implements 接口名1, 接口2...{
	 		如果是一个非抽象的类必须重写全部的抽象方法
	 	}
 */
public class MyInterfaceImpl implements IMyInterface {
	
	@Override
	public void testAbstract() {
		System.out.println("实现类重写后的抽象方法testAbstract....");
	}

}

测试类:
/**
 *	接口测试类:将接口中成员全都调用一次
 *		测试方式:
 *			1. 调用接口中常量和static方法:
 *				static修饰的调用方式:接口名.常量/static方法(...)
 *
 *			2. 创建实现类对象,调用default方法和 重写后的抽象方法
 *				非static修饰的调用方式:实现类对象.default方法(...)/抽象方法(...)
 *
 */
public class MyInterfaceTest {

	public static void main(String[] args) {
		// 调用IMyInterface接口中常量:接口名.常量
		System.out.println(IMyInterface.MIN_VALUE);// 1
		System.out.println(IMyInterface.MAX_VALUE);// 2
		
		// 调用IMyInterface接口中static方法:接口名.static方法(...);
		IMyInterface.testStatic1();
		IMyInterface.testStatic2();
		
		// 创建MyInterfaceImpl实现类对象
		MyInterfaceImpl my = new MyInterfaceImpl();
		// 通过实现类对象my调用default方法: 实现类对象.default方法(...)
		my.testDefault1();
		my.testDefault2();
		
		// 通过实现类对象my调用抽象方法: 实现类对象.抽象方法(...)
		my.testAbstract();
		
//		new IMyInterface();// 接口不能创建对象
	}

}

2. 多态polymorphic

2.1 什么是多态? 

简单理解 : 看成一种事物多种形态

示例  :

今天晚上大家请我吃大餐 :  龙虾   喝粥  思想大餐....

我准备买一辆:  独轮车 自行车  拖拉机   布加迪模型....

Java 程序中的体现:

 

多态概念:

将子类对象装到父类的变量中保存(向上造型/向上转型),当父类变量调用方法的时候,如果子类重写了该方法,会直接执行子类重写之后的方法。(父类变量可以装任意类型的子类对象)。

多态案例1:

父类:
public class Animal {
	int age = 1;
	public void eat() {
		System.out.println("吃....");
	}
}

子类:
public class Person extends Animal{
	int age = 2;
	@Override
	public void eat() {
		System.out.println("吃肉...");
	}
	
	public void coding() {
		System.out.println("撸代码...");
	}
}

public class Pig extends Animal{
	int age = 3;
	@Override
	public void eat() {
		System.out.println("吃白菜");
	}
	
	public void gongBaiCai() {
		System.out.println("拱白菜");
	}
}

测试代码:
public class AnimalTest {

	public static void main(String[] args) {
		Animal animal = new Person();//多态的方式(向上造型/向上转型)
		Animal animal2 = new Pig();//多态的方式(向上造型/向上转型)
		
		//调用方法
		animal.eat();//吃肉...   执行子类重写后的方法
		animal2.eat();//吃白菜    执行子类重写后的方法

		System.out.println(animal.age);//1     成员变量没有多态 
		
//		animal.gongBaiCai();//多态不能调用子类独有方法
	}

}

2.2 多态作用:

可以屏蔽子类差异性,提高代码的扩展性(通过代码理解,不要从字面理解)

2.3 多态使用:(重点)

1. 向上造型/向转型

语法:

父类类型  父类变量 = new 子类类型();

父类变量.方法();//子类若重写,则会执行子类重写后的方法

例如:
Animal animal = new Person();//多态的方式(向上造型/向上转型)
Animal animal2 = new Pig();//多态的方式(向上造型/向上转型)

//调用方法
	    animal.eat();//吃肉...   执行子类重写后的方法
	    animal2.eat();//吃白菜    执行子类重写后的方法

2. 向下造型/向下转型 =>就是为了调用子类特有方法

例如:(接上面案例)
   现在需要调用子类Person中特有的方法或者调用子类Pig中特有的方法,不能调用怎么办?
这个时候就需要强制转换(向下造型/向下转型):
强制转换(向下造型/向下转型)语法:	
数据类型 变量 = (数据类型)值/变量;

在向下造型前,必须进行类型判断,需要判断当前父类变量中装的是哪一个子类类型的对象
	类型判断方式1:
	   if(父类变量 instanceof 子类类型1){
		//强制类型转换
		子类类型1	子类变量 = (子类类型1)父类变量;
		//现在就可以调用子类特有方法
		子类变量.子类特有方法(...);
	   }else if(父类变量 instanceof 子类类型2){
		//强制类型转换
		子类类型2	子类变量 = (子类类型2)父类变量;
		//现在就可以调用子类特有方法
  		子类变量.子类特有方法(...);
  	  }...
	
类型判断方式2:
  	if(父类变量.getClass() == 子类类型1.class){
  		//强制类型转换
		子类类型1	子类变量 = (子类类型1)父类变量;
		//现在就可以调用子类特有方法
		子类变量.子类特有方法(...);
	}else if(父类变量.getClass() == 子类类型2.class){
		//强制类型转换
		子类类型2	子类变量 = (子类类型2)父类变量;
		//现在就可以调用子类特有方法
		子类变量.子类特有方法(...);
	}...

     如果不进行类型判断再强转,就有可能发生ClassCastException类造型异常
测试类代码如下:
public class AnimalTest {

	public static void main(String[] args) {
		Animal animal = new Person();//多态的方式(向上造型/向上转型)
		Animal animal2 = new Pig();//多态的方式(向上造型/向上转型)
		animal = new Pig();//多态的方式(向上造型/向上转型)
		
		//调用方法
		animal.eat();
		animal2.eat();
		System.out.println(animal.age);//1     成员变量没有多态 
		
//如果这里需要调用Pig类中特有方法,就需要将animal强转为Pig类型
		//类型判断的方式1
		if (animal instanceof Pig) {//判断animal中是不是装的Pig对象,如果是才强转
			Pig pig = (Pig)animal;
			//调用Pig特有方法
			pig.gongBaiCai();
		} else if (animal instanceof Person) {
			//如果这里需要调用Person类中特有方法,就需要将animal强转为Person类型
			Person person = (Person)animal;
			//调用Person特有方法
			person.coding();
		}
		
		//类型判断的方式2
		if (animal.getClass() == Pig.class) {//判断animal中是不是装的Pig对象,如果是才强转
			Pig pig = (Pig)animal;
			//调用Pig特有方法
			pig.gongBaiCai();
		} else if (animal.getClass() == Person.class) {
			//如果这里需要调用Person类中特有方法,就需要将animal强转为Person类型
			Person person = (Person)animal;
			//调用Person特有方法
			person.coding();
		}
	}
}
多态案例2:
父类:
public class Vip {
	/**
	 * 会员特权
	 */
	public void privilege() {
		System.out.println("我有特权...");
	}
}

子类:
public class Vip1 extends Vip{
	/**
	 * 会员特权
	 */
	public void privilege() {
		System.out.println("我是5000元俱乐部会员");
	}
	public void low() {
		System.out.println("我很low");
	}
}

public class Vip2 extends Vip{
	/**
	 * 会员特权
	 */
	public void privilege() {
		System.out.println("我是500000元俱乐部会员");
	}
	public void normal() {
		System.out.println("我很一般");
	}
}


public class Vip3 extends Vip{
	/**
	 * 会员特权
	 */
	public void privilege() {
		System.out.println("我是500000000000元俱乐部会员");
	}
	public void great() {
		System.out.println("我很NB....");
	}
}

测试类:
public class VipTest {

	public static void main(String[] args) {
		/*
		 * 模拟会员登陆的时候特权展示
		 * 
		 */
		Vip vip = new Vip2();//屏蔽子类差异性
		
		//调用特权
		vip.privilege();//调用特权方法,如果子类重写了,会执行对应子类重写后的方法
		
		//判断当前VIP中装的子类是哪一个,展示对应的特权
		if (vip instanceof Vip1) {//类型判断
			//强制转换
			Vip1 vip1 = (Vip1)vip;
			//调用特有方法
			vip1.low();
		}else if (vip instanceof Vip2) {//类型判断
			//强制转换
			Vip2 vip2 = (Vip2)vip;
			//调用特有方法
			vip2.normal();
		}else if (vip instanceof Vip3) {//类型判断
			//强制转换
			Vip3 vip3 = (Vip3)vip;
			//调用特有方法
			vip3.great();
		}
	}

}

多态案例3:
父类:
public class Dog {
	public void eat() {
		System.out.println("吃...");
	}
}

public class Hasky extends Dog {
	@Override
	public void eat() {
		System.out.println("沙发..");
	}
        public void breakHome() {
		System.out.println("拆家..");
	}
        
}

public class Teddy extends Dog {
	@Override
	public void eat() {
		System.out.println("吃天吃地吃空气");
	}
        public void f__k() {
		System.out.println("都懂..");
	}
    
}


public class Tudog extends Dog {
	@Override
	public void eat() {
		System.out.println("啃骨头。。。");
	}
        public void protectHome() {
		System.out.println("看家护院");
	}
    
}


public class Person {
	/*public void feedDog(Hasky dog) {
		dog.eat();
	}
	
	public void feedDog(Teddy dog) {
		dog.eat();
	}
	
	public void feedDog(Tudog dog) {
		dog.eat();
	}
	如果有几万种狗,就需要写几万个方法喂狗,不可取
	*/
	public void feedDog(Dog dog) {//屏蔽子类差异性。写一个父类类型,所有的子类对象都可以接收
		dog.eat();// 会执行dog变量中装的对应子类eat方法
// 调用子类狗特有方法
            // 类型判断
            if(dog instanceof TuDog) {
                Tudog tu = (Tudog)dog;
                tu.protectHome();
}....
	}
}

测试类:
public class DogTest {

	public static void main(String[] args) {
		//测试喂狗案例
		Hasky hasky = new Hasky();	
		Tudog tudog = new Tudog();	
		Teddy teddy = new Teddy();
		
		Person person = new Person();
		person.feedDog(hasky);// Dog dog = new Hasky();
		person.feedDog(tudog);
		person.feedDog(teddy);
	}
}

原理分析:

2.4 多态注意事项:

1. 成员变量没有多态

2. 不能调用子类特有的方法,如果需要调用子类特有的方法,必须进行强制类型转换(向下造型/向 下转型),向下造型需要进行子类类型判断

3. 父类变量能点(调用)出哪些成员(成员变量和方法),是由当前类和其父类决定,优先从当前类 开始查找,直到找到Object了为止,如果Object中有没有,就不能调用

2.5. 继承关系的构造方法执行流程:(了解)

类加载流程:

从最高父类构造方法开始执行,逐级向下执行,直到当前类的构造方法结束

如图:

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值