内部类

image.png
image.png

  • 隐藏类的实现细节
  • 对Outer单独服务
  • 方便访问外部类的私有成员,而不需要共有的get和set方法

    内部类的分类

    image.png

    普通(成员)内部类

    image.png ```java package com.lagou.task10;

/**

  • @author 西风月
  • @date 2020/7/15
  • @description */ public class NormalOuterTest { public static void main(String[] args) {
    1. //NormalOuter.NormalInner ni = new NormalOuter.NormalInner(); //需要包含com.lagou.task10.NormalOuter.NormalInner的封闭实例 需要通过引用.的方式访问
    2. NormalOuter no = new NormalOuter();
    3. NormalOuter.NormalInner ni = no.new NormalInner();
    4. ni.show();
    } } java package com.lagou.task10;

/**

  • @author 西风月
  • @date 2020/7/15
  • @description */

/**

  • 编程实现普通内部类的定义与使用 */ public class NormalOuter { private int cnt = 1;

    //定义普通内部类, 隶属于外部类的成员,并且是对象层级 public class NormalInner {

    private int ia = 2;
    
    public NormalInner() {
        System.out.println("普通内部类的构造方法执行了!");
    }
    public void show() {
        System.out.println("外部类变量cnt的数值是:" + cnt);
        System.out.println("ia = " + ia);
    }
    

    } }


- 使用方式:

![image.png](https://cdn.nlark.com/yuque/0/2020/png/1567843/1594789105861-9bac1fcd-03f7-4af7-abd8-bf58ed68dc17.png#align=left&display=inline&height=337&margin=%5Bobject%20Object%5D&name=image.png&originHeight=673&originWidth=1318&size=401048&status=done&style=none&width=659)
```java
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */
public class NormalOuterTest {
    public static void main(String[] args) {
        //NormalOuter.NormalInner ni = new NormalOuter.NormalInner(); //需要包含com.lagou.task10.NormalOuter.NormalInner的封闭实例 需要通过引用.的方式访问
        NormalOuter no = new NormalOuter();
        NormalOuter.NormalInner ni = no.new NormalInner();
        ni.show();
        System.out.println("==================================");
        ni.show2(88);
    }
}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */

/**
 *  编程实现普通内部类的定义与使用
 */
public class NormalOuter {
    private int cnt = 1;

    //定义普通内部类, 隶属于外部类的成员,并且是对象层级
    public /*final */ class NormalInner {
//    private class NormalInner {
        private int ia = 2;
        private int cnt = 3;

        public NormalInner() {
            System.out.println("普通内部类的构造方法执行了!");
        }
        public void show() {
            System.out.println("外部类变量cnt的数值是:" + cnt);
            System.out.println("ia = " + ia);
        }

        public void show2(int cnt) {
            System.out.println("形参变量cnt=" + cnt);
            System.out.println("内部类中cnt=" + this.cnt);
            System.out.println("外部类中cnt=" + NormalOuter.this.cnt);
        }

    }
}

静态内部类

image.png
image.png

package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */
public class StaticOuter {
    private int cnt = 1;
    private static int scnt = 2;

    public static class StaticInner {
        private int ia = 3;

        public StaticInner() {
            System.out.println("静态内部类的构造方法哦!");
        }

        public void show() {
            System.out.println("ia = " + ia);
            System.out.println("外部类: scnt = " + scnt);
            //System.out.println("外部类: cnt = " + cnt); 错误:静态上下文中访问非静态的成员报错,此时非静态成员可能未初始化
        }
    }
}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */
public class StaticOuterTest {
    public static void main(String[] args) {
        StaticOuter.StaticInner si = new StaticOuter.StaticInner();
        si.show();
    }
}

image.png
image.png

package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */

/**
 *  编程实现普通内部类的定义与使用
 */
public class NormalOuter {
    private int cnt = 1;

    //定义普通内部类, 隶属于外部类的成员,并且是对象层级
    public /*final */ class NormalInner {
//    private class NormalInner {
        private int ia = 2;
        private int cnt = 3;

        public NormalInner() {
            System.out.println("普通内部类的构造方法执行了!");
        }
        public void show() {
            System.out.println("外部类变量cnt的数值是:" + cnt);
            System.out.println("ia = " + ia);
        }

        public void show2(int cnt) {
            System.out.println("形参变量cnt=" + cnt);
            System.out.println("内部类中cnt=" + this.cnt);
            System.out.println("外部类中cnt=" + NormalOuter.this.cnt);
        }

    }
}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */
public class StaticOuter {
    private int cnt = 1;
    private static int scnt = 2;

    public /*static*/ void show() {
        System.out.println("外部类中的方法! ");
    }

    public static class StaticInner {
        private int ia = 3;
        private static int scnt = 4;

        public StaticInner() {
            System.out.println("静态内部类的构造方法哦!");
        }

        public void show() {
            System.out.println("ia = " + ia);
            System.out.println("外部类: scnt = " + scnt);
            //System.out.println("外部类: cnt = " + cnt); 错误:静态上下文中访问非静态的成员报错,此时非静态成员可能未初始化
        }

        public void show2(int scnt) {
            System.out.println("scnt = " + scnt);  //就近原则
            System.out.println("内部类中的成员scnt = " + StaticInner.scnt);
            System.out.println("外部类中的成员scnt = " + StaticOuter.scnt);
            //StaticOuter.show();
            new StaticOuter().show();
        }
    }
}

局部(方法)内部类

image.png

  • class前面没有访问修饰符 ```java package com.lagou.task10;

/**

  • @author 西风月
  • @date 2020/7/15
  • @description */ public class AreaOuter { private int cnt = 1;

    public void show() {

     //定义局部内部类,只在当前方法体的内部有效
     class  AreaInner {
         private int ia = 2;
    
         public AreaInner() {
             System.out.println("局部内部类的构造方法!");
         }
    
         public void test() {
             System.out.println("ia = " + ia);
             System.out.println("cnt = " + cnt);
         }
     }
    
     AreaInner ai = new AreaInner();
     ai.test();
    

    } } java package com.lagou.task10;

/**

  • @author 西风月
  • @date 2020/7/15
  • @description */ public class AreaOuterTest { public static void main(String[] args) {
     AreaOuter ao = new AreaOuter();
     ao.show();
    
    } }

- **局部内部类的注意事项**

![image.png](https://cdn.nlark.com/yuque/0/2020/png/1567843/1594802984308-e1fb51cc-9817-4de6-ab01-77ced9d1ff56.png#align=left&display=inline&height=286&margin=%5Bobject%20Object%5D&name=image.png&originHeight=571&originWidth=1232&size=324176&status=done&style=none&width=616)

- 若外部局部变量默认被内部类调用, 该外部变量从Java8开始默认理解为final关键字修饰的变量
- 虽然可以省略final关键字, 但建议还是加上
- 内部类用到外部的局部变量底层实现是会拷贝一份, 如果外部变量可以改变,就会导致内部类与外部类的不一致性

<br />
```java
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */
public class AreaOuter {
    private int cnt = 1;

    public void show() {
        //定义一个局部变量进行测试, 从Java8开始默认理解为final关键字修饰的变量
        //虽然可以省略final关键字, 但建议还是加上
        final int ic = 8;
        //定义局部内部类,只在当前方法体的内部有效
        class  AreaInner {  //内部类用到外部的局部变量底层实现是会拷贝一份, 如果外部变量可以改变,就会导致内部类与外部类的不一致性
            private int ia = 2;

            public AreaInner() {
                System.out.println("局部内部类的构造方法!");
            }

            public void test() {
                System.out.println("ia = " + ia);
                System.out.println("cnt = " + cnt);
                System.out.println("ic=" + ic);
                //ic = 5;  //Error:(26, 17) java: 从内部类引用的本地变量必须是最终变量或实际上的最终变量
            }
        }

        AreaInner ai = new AreaInner();
        ai.test();
    }
}

回调模式

image.png

package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */
public interface AnoymousInstance {
    //自定义抽象方法
    public abstract void show();
}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */
public class AnnoymousInstanceTest  {
    //
    public static void test(AnoymousInstance ai) {
        ai.show();
    }
    public static void main(String[] args) {
        //AnnoymousInstanceTest.test(new AnoymousInstance());  接口不能实例化
        AnnoymousInstanceTest.test(new AnnoymousInstanceImpl());
    }
}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */
public class AnnoymousInstanceImpl implements AnoymousInstance {
    @Override
    public void show() {
        System.out.println("这里是接口的实现类!");
    }
}

匿名内部类

image.png

image.png

Lambda表达式

从Java8开始提出新特性Lambda表达式可以简化上述代码,格式为: (参数列表) -> {方法体}

package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */
public interface AnoymousInstance {
    //自定义抽象方法
    public abstract void show();
}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/15
 * @description
 */
public class AnnoymousInstanceTest  {
    //
    public static void test(AnoymousInstance ai) {
        ai.show();
    }
    public static void main(String[] args) {
        //AnnoymousInstanceTest.test(new AnoymousInstance());  接口不能实例化
        AnnoymousInstanceTest.test(new AnnoymousInstanceImpl());
        System.out.println("=================================");
        //使用匿名内部类的语法格式来得到接口类型的引用,格式为:引用变量名 = new 接口/父类型 {方法的重写}
        AnoymousInstance ait = new AnoymousInstance()  {
            @Override
            public void show() {
                System.out.println("这里是匿名内部类!!");
            }
        };
        AnnoymousInstanceTest.test(ait);
        System.out.println("=================================");
        //从Java8开始提出新特性Lambda表达式可以简化上述代码,格式为: (参数列表) -> {方法体}
        AnoymousInstance ait2 = () -> System.out.println("Lambda如此便捷简单");
        AnnoymousInstanceTest.test(ait2);

    }
}

枚举类

image.png
image.png
image.png

自定义类和枚举类型在switch结构的使用

package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/16
 * @description
 * 编程实现所有方向的枚举,所有的方向:向上、向下、向左、向右
 *
 */
public class Direction {
    private final String desc;

    //声明本类类型的引用指向本类类型的对象
    public static final Direction UP = new Direction("向上");
    public static final Direction DOWN = new Direction("向下");
    public static final Direction LEFT = new Direction("向左");
    public static final Direction RIGHT = new Direction("向右");

    //通过构造方法实现成员变量的初始化,更加灵活
    //私有化构造方法,也就是只能在本类中使用
    private Direction(String desc) {
        this.desc = desc;
    }
    //通过公有的get方法在本类的外部访问成员变量
    public String getDesc() {
        return desc;
    }
}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/16
 * @description
 */
public class DirectionTest {
    public static void main(String[] args) {
//        Direction d1 = new Direction("向上");
//        System.out.println("获取到的字符串是:"+d1.getDesc());
//
//        Direction d2 = new Direction("向下");
//        System.out.println("获取到的字符串是:"+d2.getDesc());
//
//        Direction d3 = new Direction("向左");
//        System.out.println("获取到的字符串是:"+d3.getDesc());
//
//        Direction d4 = new Direction("向右");
//        System.out.println("获取到的字符串是:"+d4.getDesc());
//
//        Direction d5 = new Direction("向前");
//        System.out.println("获取到的字符串是:"+d1.getDesc());
        // Direction d1 = null;
        // Direction.UP = d1; //Error:(24, 18) java: 无法为最终变量UP分配值
        Direction d1 = Direction.UP;
        System.out.println("获取的方向:" + d1.getDesc());

        System.out.println("=======================");;
        DirectionEnum d2 = DirectionEnum.UP;
        System.out.println("获取的方向:" + d2.getDesc());
    }

}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/16
 * @description
 */
public class DirectionUseTest {
    //自定义一个静态方法实现根据参数指定的字符串内容来打印具体的方向信息
    public static void test1(String str) {
        switch (str) {
            case "向上":
                System.out.println("抬头望明月!"); break;
            case "向下":
                System.out.println("低头思故乡!"); break;
            case "向左":
                System.out.println("左牵黄!"); break;
            case "向右":
                System.out.println("右擎苍!");break;
            default:
                System.out.println("没有这样的方法!");

        }
    }

    //自定义一个静态方法实现根据参数指定的字符串内容来打印具体的方向信息
    public static void test2(DirectionEnum de) {
        switch (de) {
            case UP:
                System.out.println("抬头望明月!"); break;
            case DOWN:
                System.out.println("低头思故乡!"); break;
            case LEFT:
                System.out.println("左牵黄!"); break;
            case RIGHT:
                System.out.println("右擎苍!");break;
            default:
                System.out.println("没有这样的方法!");

        }
    }

    public static void main(String[] args) {
        DirectionUseTest.test1(DirectionEnum.UP.getDesc());
        DirectionUseTest.test1("传字符串");
        System.out.println("=======================");
        DirectionUseTest.test2(DirectionEnum.LEFT);
        //DirectionUseTest.test2("传字符串"); Error:类型不匹配,减少出错的可能性。
    }
}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/16
 * @description
 * 编程实现所有方向的枚举,所有的方向:向上、向下、向左、向右
 *
 */
public enum DirectionEnum {

    //枚举类型要所有的枚举值必须放在本类的开头
    UP("向上"), DOWN("向下"), LEFT("向左"), RIGHT("向右");
    //声明本类类型的引用指向本类类型的对象
    private final String desc;

    //通过构造方法实现成员变量的初始化,更加灵活
    //私有化构造方法,也就是只能在本类中使用
    private DirectionEnum(String desc) {
        this.desc = desc;
    }
    //通过公有的get方法在本类的外部访问成员变量
    public String getDesc() {
        return desc;
    }
}

Enum类的概念和常用方法

image.png

  • static T[] values() 返回当前枚举的所有对象 (泛型编程)
  • String toString()
  • int ordinal() 返回枚举对象在枚举类中的索引位置
  • 索引从0开始 ```java package com.lagou.task10;

/**

  • @author 西风月
  • @date 2020/7/17
  • @description
  • 编程实现方向枚举类的测试,调用从Enum继承的方法 */ public class DirectionEnumTest { public static void main(String[] args) {
     DirectionEnum de = DirectionEnum.UP;
     DirectionEnum[] arr = DirectionEnum.values();
     for(int i =0; i<arr.length; i++) {
         System.out.println("获取到的枚举名称:"+arr[i].toString());
         System.out.println("获取到的枚举索引位置:"+arr[i].ordinal());
     }
    
    } }

<a name="LUFVt"></a>
## 枚举类实现接口的方式

<a name="CDt7s"></a>
##### 枚举不支持继承


![image.png](https://cdn.nlark.com/yuque/0/2020/png/1567843/1594936160070-e7178efd-e78b-4d15-99c0-1813b8f0e830.png#align=left&display=inline&height=158&margin=%5Bobject%20Object%5D&name=image.png&originHeight=316&originWidth=1352&size=149027&status=done&style=none&width=676)

```java
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/17
 * @description
 * 编程实现方向枚举类的测试,调用从Enum继承的方法
 */
public class DirectionEnumTest {
    public static void main(String[] args) {
        DirectionEnum de = DirectionEnum.UP;
        DirectionEnum[] arr = DirectionEnum.values();
        for(int i =0; i<arr.length; i++) {
            System.out.println("获取到的枚举名称:"+arr[i].toString());
            System.out.println("获取到的枚举索引位置:"+arr[i].ordinal());
        }

        //DirectionEnum de2 = DirectionEnum.valueOf("向下"); //编译阶段ok,运行阶段报错: IllegalArgumentException: DirectionEnum.向下
        DirectionEnum de2 = DirectionEnum.valueOf("UP");
        //DirectionEnum de3 = DirectionEnum.valueOf("UP LEFT");
        //System.out.println("枚举对象的名称是:" + de2.toString());
        System.out.println("枚举对象的名称是:" + de2); //当打印引用变量时, 会自动调用toString()方法

        //CompareTo方法调用结果是索引之差
        for(int i =0; i<arr.length; i++) {
            System.out.println("调用对象在与数组中对象比较的先后顺序结果是:" + de.compareTo(arr[i]));
        }

        System.out.println("---------------------------------------------------------");

        //使用数组中每个对象都调用自定义重写的方法
        for(int i =0; i<arr.length; i++) {
            arr[i].show();
        }
    }
}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/16
 * @description
 * 编程实现所有方向的枚举,所有的方向:向上、向下、向左、向右
 *
 */
public enum DirectionEnum implements DirectionInterface {
    //枚举类型要所有的枚举值必须放在本类的开头

    //声明匿名内部类的语法格式:接口/或父类型() {方法的重写};
    //public static final Direction RIGHT = new Direction("向上") {方法的重写}
    //简写
    UP("向上") {
        @Override
        public void show() {
            System.out.println("贪吃蛇向上移动了!");
        }
    }, 
    DOWN("向下") {
        @Override
        public void show() {
            System.out.println("贪吃蛇向下移动了!");
        }
    }, LEFT("向左") {
        @Override
        public void show() {
            System.out.println("贪吃蛇向左移动了!");
        }
    }, RIGHT("向右"){
        @Override
        public void show() {
            System.out.println("贪吃蛇向右移动了!");
        }
    };
    //声明本类类型的引用指向本类类型的对象
    private final String desc;

    //通过构造方法实现成员变量的初始化,更加灵活
    //私有化构造方法,也就是只能在本类中使用
    private DirectionEnum(String desc) {
        this.desc = desc;
    }
    //通过公有的get方法在本类的外部访问成员变量
    public String getDesc() {
        return desc;
    }
    //整个枚举类型只重写一次, 所有对象都调用同一个,没有做到个性化
//    @Override
//    public void show() {
//        System.out.println("现在可以实现接口中抽象方法的重写!"/* + " " + this.toString()*/);
//    }
}

注解

  • 标注 @Overide
  • 注解可以看作是一种特殊的接口

image.png

注解的语法格式

image.pngimage.png
image.png

package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/17
 * @description
 */
@MyAnnotation(/*value = "hello",*/ value2 = "annotation")
public class Person {
    private String name;

}
package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/17
 * @description
 */
//若一个注解中没有任何的成员,则这样的注解叫做标识/标记注解, 使用注解时采用 成员参数名 = 成员参数值, ...
public @interface MyAnnotation {
    public String value() default "默认值";   //声明一个String类型的成员变量,名字value
    public String value2() default "默认值" ;
}

元注解

image.png
image.png
image.png
image.png

image.png

package com.lagou.task10;

/**
 * @author 西风月
 * @date 2020/7/17
 * @description
 */

//@Mantypes({@ManType("职工"), @ManType("超人")})
@ManType("123")
@ManType("288")
public class Man {
    public static void main(String[] args) {
        int ia = 97;
        char c1 = (@ManType char) ia;
    }
}
package com.lagou.task10;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;

/**
 * @author 西风月
 * @date 2020/7/17
 * @description
 */
@Repeatable(value = Mantypes.class)
@Target(ElementType.TYPE_USE)
public @interface ManType {
    String value() default "";
}
package com.lagou.task10;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

/**
 * @author 西风月
 * @date 2020/7/17
 * @description
 */
@Target(ElementType.TYPE_USE)
public @interface Mantypes {
    ManType[] value();
}

常见的预制注解image.png

image.png