Day10【接口、多态】

#今日内容

  • 接口
  • 多态

##01. 接口概述与生活举例

  • 结合例子, 接口是什么思想?
总结: 接口就是一种公共的规范标准

		接口是对外暴露的一种规则


	定义接口的人:
		
		声明规则的

	使用接口的人:

		根据规则完成功能的人

##02. 接口的定义基本格式

  • 接口的基本定义格式
格式: interface 接口名{}
  • 接口有会产生字节码文件吗?
总结: 会的
  • 接口中可以定义的内容有?
  • 接口在jdk1.7的特点:
	只能定义常量
	抽象方法	
  • 接口在jdk1.8的特点:
	默认方法
	静态方法
  • 接口在jdk1.9的特点:
	私有方法



	总结:

		1. 常量		--> 自定义常量	-> final
		2. 抽象方法	-> 必掌握


		3. 默认方法	-> 了解
		4. 静态方法	-> 了解
		5. 私有方法  -> 了解

##03. 接口的抽象方法定义

  • 接口中定义抽象方法的特点:
总结:
		定义的方法即使写成 void show();   系统也会默认加上2个关键字 public abstract


细节:
		abstract关键字不能和哪些关键字共存

		1. private
				-> 因为被abstract修饰的方法强制要求子类重写, 而被private修饰的方法子类重写不了, 二者冲突	
		2. static
				-> 如果允许被static修饰, 就可以通过类名点去调用没有方法体的抽象方法, 这样做没有意义.
		3. final
				-> 变量 方法  类

					变量 : 就变成了常量, 只能被赋值一次

					方法 : 不能被重写

					类 : 不能被继承


				-> 因为被abstract修饰的方法强制要求子类重写, 而被final修饰的方法, 子类不能重写, 二者冲突.

##04. 接口的抽象方法使用

  • 思路: 接口不能实例化, 必须由实现类(子类的一种)去实现接口
  • 实现接口的格式为:
总结:
		
	class 实现类类名 implements 接口名{

    }

建议:

	作为接口的实现类(子类), 要么重写所有的抽象方法	--> 推荐方案

	要么将自己也变成一个抽象类		-> 不推荐


步骤:
	1. 定义接口   interface 接口名 {   ....      }
	2. 找一个实现类实现这个接口-> implements           class  实现类名 implements 接口名 {  ...  }
	3. 创建实现类对象, 并调用方法


思路:

	抽象类 -> 共性的内容

	接口 -> 扩展的规则

##05. 接口的默认方法定义

  • jdk8开始, 才可以定义默认方法
  • 定义默认方法的时候, 需要加入关键字default
格式:	

	public default 返回值类型 方法名(){

	}
  • 加入默认方法, 可以解决什么样的问题?
结论: 可以解决接口的升级问题


interface A {
    public abstract void methodA();


	// 这里如果是一个抽象方法的话, 会影响到很多的实现类.
    public default void show(){
        System.out.println("我是新增加的功能show");
    }

}

class AImp1 implements A {
    @Override
    public void methodA() {
        System.out.println("AImp1....");
    }
}

class AImp2 implements A{
    @Override
    public void methodA() {
        System.out.println("AImp2....");
    }
}

##06. 接口的默认方法使用

  • 调用方式是?
  • 实现类是否可以对默认方法进行重写?
总结:

	1. 可以直接创建 实现类 的对象进行调用

	2. 可以

		如果实现类重写了, 那么调用的时候, 使用的就是重写之后的逻辑

		如果没有重写, 使用的就是接口当中默认的逻辑


eg.

		public interface Animal {
            public default void method (){
                System.out.println("默认方法");
            }
		}


public Dog implements Animal {
@Override
public void method (){ //注意重写默认方法的时候, 不能写"default"关键字.按照普通的成员方法写就行了.
System.out.println(“重写的默认方法”);
}
}

	概念: 接口是一个干爹, 干爹中的数据, 实现类也是可以继承使用的.

##07. 接口的静态方法定义

  • jdk1.8开始, 可以开始定义静态方法
  • 格式为?
总结: 

	public static 返回值类型 方法名(参数列表){
		方法体;
	}

##08. 接口的静态方法使用

  • 调用方式是?
总结:
	1. 接口名称.静态方法名称();
	
	[ 注意事项 ]静态方法无法通过实现类名或者是实现类对象进行调用.只能通过接口名.静态方法名进行调用.


	interface Inter{
		public static void method(){
			System.out.println("1");
		}
	}

	interface Inter2{
		public static void method(){
			System.out.println("2");
		}
	}


class InterImp implements Inter,Inter2{

	}


	InterImp ii = new InterImp();
	ii.method();			// 错误写法


main(){
Inter.method(); // 接口名称.静态方法名称();
}


问题: 为什么接口中的静态方法, 不允许对象名调用.

		特点: 接口和类之间是实现关系, 可以单实现, 也可以多实现


			 	既然可以多实现, 就有可能, 多个接口中定义了相同的静态方法, 但是方法体不一样.

				这时候就会出现冲突问题.


		所以, 接口中的静态方法. 只允许接口名.进行调用, 不允许对象名调用!


##09. 接口的私有方法定义

  • jdk1.9开始, 接口可以定义私有方法
  • 什么情况下需要将接口中的方法进行私有?
总结:
	如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法 去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助
	换句话说: 
	当发现接口中的多个默认方法中, 出现了重复的代码, 我们可以将这段代码抽取到一个方法当中.
		但又不希望实现类将整个逻辑性不强的方法继承使用, 就可以将该方法进行私有.


举例:

	public interface MyInterfacePrivateA {

	    public default void methodDefault1() {
	        System.out.println("默认方法1");
	        methodCommon();
	    }
	
	    public default void methodDefault2() {
	        System.out.println("默认方法2");
	        methodCommon();
	    }
	
	    private void methodCommon() {
	        System.out.println("AAA");
	        System.out.println("BBB");
	        System.out.println("CCC");
	    }
	
	}

##10. 接口的私有方法使用

  • 代码分析
结论 : 接口中定义的私有方法, 就是解决(普通/静态)方法中, 重复代码的问题.

##11. 接口的常量定义和使用

  • 接口中的变量只能是常量
总结: 因为默认加入了三个关键字 : public static final

	int num = 10;
  • fianl修饰变量
>* 基本数据类型

		其值不能发生改变

		final int a = 10;
		a = 20;	// 错误.

>* 引用数据类型

		地址值不能发生改变, 但是可以通过setXxx方法修改属性值.

		final Person p = new Person("张三",23);
		p.setAge(24);	// 正确
		p = new Person("李四",24);	// 错误
  • 注意事项:
1. 接口中的常量, 必须给出初始化值.

	-> final修饰的变量, 如果是成员变量的话, 初始化时机.


​ 解释:

			因为final修饰成员变量的初始化时机一共分为两种
				 1. 在创建成员变量的之后, 就直接赋值 --> 推荐方案
				 2. 在构造方法弹栈之前完成赋值

			注意的是, 接口中没有构造方法, 所以能够选择的初始化时机, 就只能是在创建成员变量的时候, 直接赋值.
  • 江湖规矩
定义标识符的时候, 需要见名知意, 驼峰命名

	1. 变量 : 如果是一个单词, 所有字母小写			: age
				如果是多个单词, 从第二个单词的首字母开始大写 : maxAge

	2. 常量 : 如果是一个单词, 所有字母大写			: VALUE
				如果是多个单词, 所有字母大写, 但是单词之间需要以下划线隔开	: MAX_VALUE

	3. 类名 : 如果是一个单词, 首字母大写		Demo
				如果是多个单词, 每个单词的首字母大写	TestFinal

	4. 方法名: 如果是一个单词, 所有字母小写		: method()
				如果是多个单词, 从第二个单词的首字母开始大写 : getAge();


	5. 包名 : 一般都是公司的域名倒着写

					itheima.com

						com.itheima.xx

##12. 接口的内容小结

  • 在Java 9+版本中,接口的内容可以有:
    1. 成员变量其实是常量,格式:
[public] [static] [final] 数据类型 常量名称 = 数据值;
注意:
	常量必须进行赋值,而且一旦赋值不能改变。
	常量名称完全大写,用下划线进行分隔。
    1. 接口中最重要的就是抽象方法,格式:
[public] [abstract] 返回值类型 方法名称(参数列表);
注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。
    1. 从Java 8开始,接口里允许定义默认方法,格式:
[public] default 返回值类型 方法名称(参数列表) { 方法体 }
注意:默认方法也可以被覆盖重写
    1. 从Java 8开始,接口里允许定义静态方法,格式:
[public] static 返回值类型 方法名称(参数列表) { 方法体 }
注意:静态方法不能通过实现类的类名或者实现类的对象进行调用, 只能通过接口名.静态方法名进行调用.
    1. 从Java 9开始,接口里允许定义私有方法,格式:
普通私有方法:private 返回值类型 方法名称(参数列表) { 方法体 }
静态私有方法:private static 返回值类型 方法名称(参数列表) { 方法体 }
  • 接口的思想(重要)
总结:

	对比抽象类的思想

		抽象类: 被继承体现的是一种is..a的关系, 抽象类中的行为都是共性的行为.

		接口 : 接口当中定义的都是一些扩展的规则(特性的行为), 体现的是一种like..a的关系.

##13. 继承父类并实现多个接口

  • 注意事项:
总结:
	1.子接口重写默认方法时,default关键字可以保留。
	  子类重写默认方法时,default关键字不可以保留。 子父类中不能出现default关键字, 出现就是错误代码.
	
	2.接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static final修饰。 
	3.接口中,没有构造方法,不能创建对象。 
	4.接口中,没有静态代码块。 
  • 接口的出现, 打破了java只支持单继承的局限性, 为什么?
总结:  因为接口和类之间是实现关系, 可以单实现,也可以多实现
			并且可以在继承了一个类的同时, 实现多个接口


		interface A{

		}
		
		interface B{

		}

		interface C{


		}


		class InterImp extends Object implements A,B,C{


}

  • 接口的子类需要注意哪些?
总结:

	1. 实现一个接口, 要么重写所有的抽象方法, 要么该实现类自己本身也是一个抽象类.

	2. 如果实现类实现多个接口, 多个接口中存在重复的抽象方法, 实现类之重写一个即可 

	3. 如果实现类所实现的多个接口中, 存在重复的默认方法,  必须对冲突的默认方法重写
		
		interface A{
			public default void method(){
				System.out.println("A");
			}
		}

		interface B{
			public default void method(){
				System.out.println(B);
			}
		}

		class InterImp implements A, B{
			@Override
			public void method(){
				System.out.println("...");
			}
		}


	4. 如果实现类, 从父类中继承下来的方法, 和接口中默认的方法重名了.

			优先用父类的方法.


public class Test1_Extends {
public static void main(String[] args) {
Dog d = new Dog();
d.eat();
d.show();
}
}

			class Animal{
			    public void eat(){
			        System.out.println("动物吃饭");
			    }
			
			    public void show(){
			        System.out.println("父类的show方法");
			    }
			}


			interface Inter{
			    void eat();
			
			    public default void show(){
			        System.out.println("接口中的show方法");
			    }
			
			}
			
			class Dog extends Animal implements Inter{
			    // 虽然和接口的抽象eat冲突, 这里使用的是父类的eat方法
			    public void eat(){
			        System.out.println("动物吃饭");
			    }
			    // 父类的show方法和接口中默认的show方法冲突, 优先使用的是父类的show方法
			    // d.show();
			}

##14. 接口之间的多继承

  • 类与类的关系:
    * 继承关系, 只支持单继承, 不支持多继承, 但是可以多层继承
  • 类与接口的关系:
    * 实现关系, 可以单实现, 也可以多实现, 并且可以在继承了一个类的同时, 实现多个接口
  • 接口与接口的关系:
    * 继承, 可以单继承, 也可以多继承!
	interface A{
		void showA();
	}

	interface B{
		void showB();
	}

	interface C extends A,B{
		void showC();
	}


	class InterImp implements C{
		//重写三个抽象方法, 因为C当中继承到了showA, showB();
	}


* 单独注意:

	如果多个父接口当中, 出现了重复的默认方法, 那么子接口必须对方法进行覆盖重写, 而且不能省略default关键字 !!


	interface A{
		public defalut void show(){
			System.out.println("a");
		}
	}

	interface B{
		public defalut void show(){
			System.out.println("B");
		}
	}

	interface C extends A,B{
		@Override
		public defalut void show(){		// defalut不能省略.
			System.out.println("C");
		}
	}

##15. 多态的概述

  • 什么是多态?
总结: 事物存在的多种形态


class Animal{

}

class Dog extends Animal{

}

main(){
	
	Dog d = new Dog();		// 事物以狗的形态出现

	Animal a = new Dog();	// 事物以动物的形态出现

}

##16. 多态的格式与使用

  • 多态的前提是?
总结:

	1. 要有继承关系, 实现关系

	2. 要有父类引用指向子类对象.		--> 多态的写法

##17. 多态中成员变量的使用特点

  • 多态中成员变量的使用特点?
总结:
	1. 编译看左边(父类), 运行看左边(父类)

		Fu f = new Zi();

		System.out.println(f.num);		// 父类当中num所记录的值


细节:

	编译看左边(父类), 运行看左边(父类)

		因为当前是父类引用指向子类对象, 父类的引用带有局限性, 只能看到堆内存当中super的一小块区域
		所以可以拿到的只能是super区域当中, 父类记录的数值.



问题: 静态成员变量呢?

		静态修饰的成员跟类相关, 跟对象没有关系.

		 Animal a = new Dog();
	     System.out.println(a.abc);       

		此处虽然是对象名.abc, 但在编译的时候也会翻译成类名.abc

		Animal.abc	--> 调用静态成员, 类名是谁的, 调用的就是谁的数值.

##18. 多态中成员方法的使用特点

  • 多态中成员方法的访问提点?
总结:
	1. 编译看左边(父类), 运行看右边(子类)

动态绑定机制:


	动态绑定:

          在多态创建对象并调用成员方法的时候, 编译时会检测父类当中是否有此方法的声明

                有 : 编译通过, 但是运行的时候执行子类的方法

                没有 : 编译失败.
	.

##19. 使用多态的好处

  • 无论右边new的是那个子类对象, 左边都不会发生变化
总结:

	1.
		Animal a = new Dog();

		Animal a = new Cat();

		...


结论:

	多态的出现, 提高了代码的复用性, 因为有继承保证

	提高了代码的扩展性	--> 必掌握


		问题: 怎么就提高了?

				可以将方法的形参定义为父类类型, 该方法就可以接受这个父类的任意子类对象了.


		注意: 将方法形参定义为父类类型之后, 该方法可以接受这个父类的任意子类对象, 在方法内部一般都是调用的共性内容

				如果想要调用特性内容, 就需要向下转型, 莫不如直接创建子类对象.

##20. 对象的向上转型

  • 什么是多态的向上转型?
总结:

	1.	Animal a = new Dog();		// 父类引用指向子类对象


对比:

	double d = 10;

##21. 对象的向下转型

  • 为什么要向下转型?
总结:
	多态的弊端: 不能调用子类特有的属性和行为.
	
	如果非要调用子类特有的功能, 就必须向下转型.


	向下转型的举例:
			超人的例子.


​ 注意: 向下转型的强转必须发生在子父类的关系内, 而且必须是转上去, 才能转下来.

			什么情况下需要用到向下转型?
				答:  为了调用子类特有的属性和行为.

			ClassCastException(类型转换异常): 引用数据类型的强转, 出现了错误.

				例如:  

					1. Animal a = new Cat();
					   Dog d = (Dog)a;			--> Cat和Dog之间没有子父类关系, 不能强转

					2. Animal a = new Animal();
    					Dog d = (Dog) a;		--> 必须要先进行向上转型, 才可以将数据正常的转型下来.

##22. 用instanceof关键字进行类型判断

  • instanceof关键字的作用是什么?
总结:
	1. 判断左边的引用, 是否是右边的数据类型.


public static void useAnimal(Animal a){ // Animal a = new Cat();
a.eat();

	       if(a instanceof Dog){
	           Dog d = (Dog) a;
	           d.lookHome();
	       }else if (a instanceof Cat){
	           Cat c = (Cat) a;
	           c.catchMouse();
	       }
	    }


多态的好处:

	多态可以提高代码的扩展性, 可以将方法的形参定义为父类类型, 该方法就能接收这个父类的任意子类对象.

		方法内部一般只调用该体系当中共性的内容, 如果要调用特性的, 干脆就创建子类对象. 

##23. 笔记本USB接口案例_分析

  • 看图说话

##24. 笔记本USB接口案例_实现

  • 示例代码
总结:

	1. 


你可能感兴趣的:(自学java)