08_面向对象_下_02

一/多态的应用:模板方法设计模式
  • 抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
  • 解决问题:
    • 当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
    • 换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式
  • 示例:
 1 package com.teacher.java;
 2 public class TemplateTest {
 3     public static void main(String[] args) {
 4         Template p = new SubTemplate();
 5         p.runTime();
 6     }
 7 }
 8 //整体步骤是固定、通用,code是异变的
 9 abstract class Template{
10     public void runTime(){
11         long start = System.currentTimeMillis();
12         code();
13         long end = System.currentTimeMillis();
14         System.out.println("runTime =" + (end - start));
15     }
16     public abstract void code();
17 }
18 class SubTemplate extends Template{
19     @Override
20     public void code() {
21         for(int i = 2;i <= 1000;i++){
22             Boolean isFlag = true;
23             for(int j = 2;j <= Math.sqrt(i);j++){
24                 if (i % j == 0) {
25                     isFlag = false;
26                     break;
27                 }
28             }
29             if(isFlag){
30                 System.out.println(i);
31             }
32         }
33     }
34 }

 

*二/接口(interface)
  • 一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java 不支持多重继承。有了接口,就可以得到多重继承的效果。
  • 另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有 is-a 的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3 机、手机、数码相机、移动硬盘等都支持 USB 连接。
  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。继承是一个"是不是"的关系,而接口实现则是"能不能"的关系。
  • 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。
1.接口特点:接口中省略的三个关键字 static final abstract public
  • 接口(interface)是抽象方法和常量值定义的集合。
  • 用 interface 来定义。
  • 接口中的所有成员变量都默认是由 public static final 修饰的。通常省略
  • 接口中的所有抽象方法都默认是由 public abstract 修饰的。通常省略
  • 接口中没有构造器。
  • 接口采用多继承机制
2.接口的使用
  • 接口使用 interface 来定义。
  • 在 Java 中:接口和类是并列的两个结构
  • 如何去定义两个接口:定义接口中的成员
  •  JDK7 及以前:只能定义全局常量和抽象方法,全局常量意味着可以通过接口名调用,抽象方法意味着实现类必须重写
    • 全局常量:public static final 的,但是书写中,可以省略不写。常量大写.全局常量通过
    • 抽象方法:public abstract 的,但是书写中,可以省略不写。必须需要实现类重写
  • JDK8:除了全局常量和抽象方法之外,还可以定义静态方法、默认方法。
    • 静态方法:
      • 使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行其方法体。
      • 接口只能调用接口中的静态方法,不能调用默认方法,静态方法不能通过实现类或类的对象来调用
      • 接口只能调用静态方法,而不能调用默认方法,
    • 默认方法:
      • 默认方法使用 default 关键字修饰。默认方法可省略的是public,而不是代表缺省。
      • 默认方法只能通过实现类的对象来调用。如果实现类重写了接口中的默认方法,调用时,调用的是重写的方法
      • 实现类的对象只能调用接口中的默认方法,不能调用静态方法;
      • 对比:接口只能调用静态方法,而不能调用默认方法,
  • 接口中不能定义构造器!意味着接口不可以实例化.
  • Java 开发中,接口通过让类去实现(implements)的方式来使用。
  • 如果实现类覆盖了(也就是重写,一般说实现)接口中的所有方法,则此实现类就可以实例化
  • 如果实现类没有覆盖接口中所有的抽象方法,则此实现类只能是一个抽象类
  • Java 类可以实现多个接口 --->弥补了 Java 单继承性的局限性
    • 格式:class AA extends BB implementd CC,DD,EE   -->先写继承  后写实现
  • 接口与接口之间是继承,而且可以多继承

示例:                                                                            

 1 public class InterfaceTest {
 2     public static void main(String[] args){
 3         Plane2 p = new Plane2();
 4         p.fly();
 5         p.stop();
 6         p.attack();
 7     }
 8 }
 9 
10 //接口1
11 interface Flyable{
12     //全局变量
13     public static final int MAX_SPEED = 7900;
14     int MIN_SPEED = 0;//public static final 可以省略不写
15     
16     //抽象方法
17     public abstract void fly();
18     void stop();//public abstract 可以省略
19     //nterfaces cannot have constructors  接口不能有构造器,意味着不能实例化
20 //     public Flyable(){
21 //         
22 //     }
23 }
24 
25 //接口二
26 interface AttackTest{
27     void attack();
28 }
29 
30 
31 //接口通过类区实现(implements)的方式使用接口
32 class Plane implements Flyable{
33     
34     
35     //方法的实现
36     public void fly() {
37         System.out.println("能够飞");
38     }
39 
40     public void stop() {
41         System.out.println("能够停");
42     }
43 }
44 
45 class Plane2 extends Plane implements Flyable, AttackTest{
46 
47     @Override
48     public void attack() {
49         System.out.println("2代飞机能够攻击");
50         
51     }
52 
53     @Override
54     public void fly() {
55         System.out.println("2代飞机飞的很快");
56         
57     }
58 
59     @Override
60     public void stop() {
61         System.out.println("2代飞机停的很稳");
62         
63     }
64     
65 }
66 //***************************************************************
67 //接口与接口之间是继承,而且可以多继承
68 interface A{
69     void eat();
70 }
71 
72 interface B{
73     void sleep();
74 }
75 //c继承B和A
76 interface C extends A,B{
77     void walk();
78 }
79 //D实现接口C,需要覆盖所以方法
80 class D implements C{
81 
82     @Override
83     public void eat() {
84         System.out.println("D吃");
85         
86     }
87 
88     @Override
89     public void sleep() {
90         System.out.println("D睡");
91         
92     }
93 
94     @Override
95     public void walk() {
96         System.out.println("D走");    
97     }
98 }
  •  JDK8新特性:静态方法和默认方法                                                                
 1 public class InterfaceTest1 {
 2     public static void main(String[] args) {
 3         BB test = new BB();
 4         //接口中的静态方法只能通过接口去调用,不能通过实现类和实现类的对象调用,接口只能调用接口中的静态方法,不能调用默认方法
 5         AA.method1();
 6         //接口中的默认方法,只能通过实现类的对象调用,实现类的对象只能调用接口中的默认方法,不能调用静态方法
 7         test.method2();
 8     }
 9 }
10 //接口
11 interface AA{
12     //静态方法:static
13     public static void method1(){
14         System.out.println("AA:静态:北京");
15     }
16     //默认方法:defaul
17     public default void method2(){
18         System.out.println("AA:默认:北京");
19     }
20     //默认方法可省略的是public,而不是代表缺省
21     default void method3(){
22         System.out.println("AA:默认:省略:北京");
23     }
24 }
25 //实现类
26 class BB implements AA{
27     public void eat(){
28         
29     }
30 }
  •  调用父类和接口中相同名称的属性时候,如何执行                                                                                                                                                            
 1 public class Test121 {
 2     public static void main(String[] args) {
 3         new C().getI();//输出结果 3 2 1    
 4     }
 5 }
 6 interface A{
 7     int I = 1;
 8 }
 9 class B{
10     int I = 2;
11 }
12 class C extends B implements A{
13     int i = 3;
14     
15     public void getI(){
16 //        System.out.println(i);//报错:The field i is ambiguous i是不确定的
17         System.out.println(this.i);//自身的
18         System.out.println(super.i);//父类的
19         System.out.println(A.i);//调用接口A中的
20     }
21 }
  •  如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则
 1 public class Test12 {
 2     public static void main(String[] args) {
 3         Son son = new Son();
 4         son.help();//输出为父类中的默认的同名同参数方法
 5     }
 6 }
 7 
 8 
 9 interface Spoony{
10     default void help(){
11         System.out.println("救媳妇");
12     }
13 }
14 interface Filial{
15     default void help(){
16         System.out.println("救母亲");
17     }
18 }
19 
20 class Father{
21     public void help(){
22         System.out.println("救你妈妈");
23     }
24 }
25 class Son extends Father implements Spoony,Filial{
26     
27 }
  • 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错。-->接口冲突。这就需要我们必须在实现类中重写此方法.此时实现类调用的是重写的方法
 1 public class Test12 {
 2     public static void main(String[] args) {
 3         Son son = new Son();
 4         son.help();//输出为不知道
 5     }
 6 }
 7 interface Spoony{
 8     default void help(){
 9         System.out.println("救媳妇");
10     }
11 }
12 interface Filial{
13     default void help(){
14         System.out.println("救母亲");
15     }
16 }
17 
18 class Father{
19     public void help(){
20         System.out.println("救我媳妇");
21     }
22 
23 }
24 class Son extends Father implements Spoony,Filial{
25 
26     //重写了接口中的默认方法
27     public void help() {
28         System.out.println("不知道");
29     }
30 }
  • 如何在子类(或实现类)的方法中调用父类、接口中被重写的方法                                       
 1 class Son extends Father implements Spoony,Filial{
 2     public void help2() {
 3         System.out.println("不知道");
 4     }
 5     //方法的重写
 6     public void help(){
 7         help2();//调用类内部的方法
 8         super.help();//调用父类的方法
 9         Filial.super.help();//调用接口Filial中的方法
10         Spoony.super.help();//调用Spoony中的方法
11     }
12 }

 

 

  • 接口的具体使用,体现多态性
  • 接口的主要用途就是被实现类实现-->面向接口编程
  • 接口,实际可以看作是一种规范

 

 

 

 

三/内部类

 

1.内部类的使用
  • 1.Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B就是外部类
  •  2.内部类的分类:成员内部类 VS 局部内部类(方法内、代码块内、构造器内)
    • 成员内部类
      • 内部类作为外部类的成员,
        • 内部类可以调用外部类的结构
        • 内部类可以被static 
        • 内部类可以被4种不同的权限修饰
      • 内部类作为一个类
        • 类内可以定义属性、方法、构造器/内部类/代码块等
        • 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
        • 可以abstract修饰,作为抽象类,必须被继承
 1 class AA{
 2     //成员内部类
 3     //静态内部类
 4      static class BB{
 5         
 6     }
 7      //非静态内部类
 8      class CC{
 9         
10      }
11      //局部内部类
12      //方法中
13      public void method1(){
14          class DD{
15              
16          }
17      }
18      //代码块中
19      {
20          
21      }
22      
23      //构造器中
24      public AA(){
25          class EE{
26              
27          }
28      }
29 }

 

2.如何实例化成员内部类
 1 public class InnerClassTest {
 2     public static void main(String[] args) {
 3         //静态内部类实例化
 4         AA.BB p = new AA.BB();
 5         p.eatBB();
 6         //非静态内部类实例化
 7         AA i = new AA();
 8         AA.CC j = i.new CC();
 9         j.eatCC();
10     }
11 }
12 class AA{
13     public void eatAA(){
14         System.out.println("AA吃饭");
15     }
16 
17     //静态内部类
18      static class BB{
19         public void eatBB(){
20             System.out.println("BB吃饭");
21         }
22     }
23      //非静态内部类
24      class CC{
25          public void eatCC(){
26             System.out.println("CC吃饭");
27          }
28      }
29 }

 

3.如何在成员内部类中区分调用的外部类的结构
 1 class AA{
 2     String name = "AA";
 3     public void eatAA(){
 4         System.out.println("AA吃饭");
 5     }
 6     public void walk1(){
 7         System.out.println("走路1");
 8     }
 9     public static void walk2(){
10         System.out.println("走路2");
11     }
12     //静态内部类
13      static class BB{
14         String name = "BB";
15         public void eatBB(){
16             System.out.println("BB吃饭");
17             //静态内部类方法中调用外部类方法//方法中只能调用静态方法
18             walk2();//原型 AA.walk2(); 省略了AA.
19         }
20         //非静态内部类方法中调用外部类属性//适用于重名
21         public void test(String name){
22             System.out.println(name);//形参
23             System.out.println(this.name);//BB中的属性
24 //            System.out.println(AA.name);//报错,此时name是实例变量,不能通过类去调用,需要将name变成类变量
25         }
26     }
27      //非静态内部类
28      class CC{
29          String name = "CC";
30          public void eatCC(){
31             System.out.println("CC吃饭");
32             //非静态内部类方法中调用外部类方法
33             //方法中调用外部非静态方法
34             walk1();//原型:AA.this.walk();省略了AA.this.
35             //方法中调用外部静态方法
36             walk2();//原型 AA.walk2(); 省略了AA.
37         }
38         //非静态内部类方法中调用外部类属性//适用于重名
39         public void test(String name){
40             System.out.println(name);//形参
41             System.out.println(this.name);//CC中的属性
42             System.out.println(AA.this.name);//AA中的属性
43         }
44      }
45 }

 

4.开发中局部内部类的使用:匿名内部类使用较多
 1 package com.teacher.java2;
 2 
 3 import javax.print.attribute.standard.RequestingUserName;
 4 
 5 public class InnerClassTest {
 6 
 7 }
 8 class AA{
 9     //开发中很少用
10     public void method(){
11         class CC{
12       
13         }
14     }
15     
16     //开发中常用的
17     //方法:返回一个实现了Comparable接口的类的匿名对象//方式一:
18     public Comparable getComparable(){
19         //局部内部类:创建一个实现了Comparable接口的类
20         class MyComparable implements Comparable{
21 
22             @Override
23             public int compareTo(Object o) {
24                 // TODO Auto-generated method stub
25                 return 0;
26             }
27         }
28         return new MyComparable();//返回一个实现了Comparable接口的类的对象
29     }
30 }
31 
32 class BB{    
33     //方法:返回一个实现了Comparable接口的匿名实现类的匿名对象    //方式二:
34     public Comparable getComparable(){
35         return new Comparable(){
36             @Override
37             public int compareTo(Object o) {
38                 // TODO Auto-generated method stub
39                 return 0;
40             }
41         };//原型  return new Comparable(){};
42     }
43 }
  •  内部类注意的一个点:
    • 在局部内部类的方法中(比如:show)如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)的话, * 要求此局部变量声明为final的。
    • jdk 7及之前版本:要求此局部变量显式的声明为final的
    • jdk 8及之后的版本:可以省略final的声明
 1 class AA{
 2     public void method(){
 3         int num = 10; //此时num是一个常量, final int num = 10; JDK8以上版本final省略了,8以前的需要加上final
 4         class CC{
 5             public void show(){
 6                 System.out.println(num);
 7             }    
 8         }
 9     }
10 }

 

posted @ 2022-04-10 09:36  默以思道  阅读(31)  评论(0)    收藏  举报