1.2.5特殊类

内部类

实际作用

当一个类存在的价值仅仅是为某一个类单独服务时,那么就可以将这个类定义为所服务类中的内部类,这样可以隐藏该类的实现细节并且可以方便的访问外部类的私有成员而不再需要提供公有的get和set方法。

内部类的分类

普通内部类 - 直接将一个类的定义放在另外一个类的类体中。
静态内部类 - 使用static关键字修饰的内部类,隶属于类层级。
局部内部类 - 直接将一个类的定义放在方法体的内部时。
匿名内部类 - 就是指没有名字的内部类。

普通(成员)内部类的格式

访问修饰符 class 外部类的类名 {
访问修饰符 class 内部类的类名 {
内部类的类体;
}
}

普通内部类的使用方式

普通内部类和普通类一样可以定义成员变量、成员方法以及构造方法等。
普通内部类和普通类一样可以使用final或者abstract关键字修饰。
普通内部类还可以使用private或protected关键字进行修饰。
普通内部类需要使用外部类对象来创建对象。
如果内部类访问外部类中与本类内部同名的成员变量或方法时,需要使用this关键字。
NormalOuter类

package cn.cyh.demo1_2.d5;

import cn.cyh.demo1_2.d4.Rect;

public class NormalOuter {
    private int cnt = 1;

    //定义普通内部类,灵属于外部类的成员,并且是对象层级
    public 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);
        }
    }
}

NormalOuter测试类

package cn.cyh.demo1_2.d5;

public class NormalOuterTest {
    public static void main(String[] args) {
        //1.声NormalOuter类型的引用指向该类型的对象
        NormalOuter no = new NormalOuter();
        //声明NormaLouter类中内部类的引用指向内部类的对象
        NormalOuter.NormalInner ni  = no.new NormalInner();
        //调用内部类中的show方法
        ni.show();
        ni.show2(4);
    }
}

静态内部类的格式

访问修饰符 class 外部类的类名 {
访问修饰符 static class 内部类的类名 {
内部类的类体;
}
}

静态内部类的使用方式

静态内部类不能直接访问外部类的非静态成员。
静态内部类可以直接创建对象。
如果静态内部类访问外部类中与本类内同名的成员变量或方法时,需要使用类名.的方式访问。
StaticOuter类

package cn.cyh.demo1_2.d5;

import cn.cyh.demo1_2.d3.StaticTest;

public class StaticOuter {
    private int cnt = 1;    //隶属于对象层级
    private static int snt = 2;//隶属于类层级
    public void show(){
        System.out.println("外部类的show()方法");
    }
    public static class StaticInner{
        private int ia = 3;
        private static int snt = 3;//隶属于类层级
        public StaticInner(){
            System.out.println("静态内部类的构造方法哦");
        }
        public void show(){
            System.out.println("ia = " + ia);
            System.out.println("外部类中的snt = " + snt);
            //System.out.println("外部类中的cnt = " + cnt);//error静态上下文中不能访问非静态的成员,因此时可能还没有创建对刻
        }
        public void show2(int snt){
            System.out.println("形参变量snt = " + snt);
            System.out.println("内部类中变量snt = " + StaticInner.snt);
            System.out.println("外部类中变量snt = " + StaticOuter.snt);
//            StaticOuter.show();
            new StaticOuter().show();
        }
    }
}

StaticOuter测试类

package cn.cyh.demo1_2.d5;

public class StaticOuterTest {
    public static void main(String[] args) {
        StaticOuter.StaticInner si =new StaticOuter.StaticInner();
        si.show();
        si.show2(4);
    }
}

局部(方法)内部类的格式

访问修饰符 class 外部类的类名 {
访问修饰符 返回值类型 成员方法名(形参列表) {
class 内部类的类名 {
内部类的类体;
}
}
}

局部内部类的使用方式

局部内部类只能在该方法的内部可以使用。
局部内部类可以在方法体内部直接创建对象。
局部内部类不能使用访问控制符和static关键字修饰符。
局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
AreaOuter类

package cn.cyh.demo1_2.d5;

public class AreaOuter {
    private int cnt = 1;
    public void show(){

        final int ic = 4;
        //定义局部内部类,只在当前方法体的内部好使
        class AreaInner{
            private  int ia = 1;
            public AreaInner(){
                System.out.println("局部内部类的构造方法!");
            }
            public void test(){
                System.out.println("ia = " + ia);
                System.out.println("cnt = " + cnt);
                //ic = 5;//Error
                System.out.println("ic = " + ic);
            }
        }
        //声明局部内部类的引用指向局部内部类的对象
        AreaInner ai = new AreaInner();
        ai.test();
    }

}

AreaOuter测试

package cn.cyh.demo1_2.d5;

public class AreaOuterTest {
    public static void main(String[] args) {
        //1.声明外部类的引用指向外部类的对象
        AreaOuter ao = new AreaOuter();
        //2.通过show方法的调用实现局部内容类的定义和使用
        ao.show();
    }
}

回调模式的概念

回调模式是指——如果一个方法的参数是接口类型,则在调用该方法时,需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中所实现的方法(接口中定义的)。

开发经验分享

当接口/类类型的引用作为方法的形参时,实参的传递方式有两种:
自定义类实现接口/继承类并重写方法,然后创建该类对象作为实参传递;
使用上述匿名内部类的语法格式得到接口/类类型的引用即可;

匿名内部类的语法格式(重点)

接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
AnonymousInterface 接口

package cn.cyh.demo1_2.d5;

public interface AnonymousInterface {
    //自定义抽象方法
    public abstract void show();
}

AnonymousInterface 接口实现类
package cn.cyh.demo1_2.d5;

public class AnonymousInterfaceImpl implements AnonymousInterface{

    @Override
    public void show() {
        System.out.println("这是接口的实现类");
    }
}

AnonymousInterface 测试类

package cn.cyh.demo1_2.d5;

public class AnonymousInterfaceTest {
    //假设已有下面的方法,请问如何调用下面的方法引
    public static void test(AnonymousInterface ai){
        ai.show();
    }
    public static void main(String[] args) {
        //AnonymousInterfaceTest.test(new AnonymousInterface());//Error:接口不能实例化
        AnonymousInterfaceTest.test(new AnonymousInterfaceImpl());
        System.out.println("---------------------------------------------");
        //使用匿名内部类的语举格式来得到接口类型的引用,格式为:接口/父类类型引用变量名=new接口/父类类()(方法的重写};
        AnonymousInterface ait1 =new AnonymousInterface() {
            @Override
            public void show() {
                System.out.println("匿名内部类");
            }
        };
        //从Java8开始提出新特性Lamda表达式可以简化上述代码,格式为:(参数列表)一>(方法的
        AnonymousInterface ait2 = () -> System.out.println("1amda表达式原来是如此简单!");
        AnonymousInterfaceTest.test(ait1);
        AnonymousInterfaceTest.test(ait2);
    }
}

枚举(熟悉)

枚举的基本概念

一年中的所有季节:春季、夏季、秋季、冬季。
所有的性别:男、女。
键盘上的所有方向按键:向上、向下、向左、向右。
在日常生活中这些事物的取值只有明确的几个固定值,此时描述这些事物的所有值都可以一一列举出来,而这个列举出来的类型就叫做枚举类型。

枚举的定义

使用public staticfinal表示的常量描述较为繁琐,使用enum关键字来定义枚举类型取代常量,枚举类型是从Java5开始增加的一种引用数据类型。
枚举值就是当前类的类型,也就是指向本类的对象,默认使用publicstaticfinal关键字共同修饰,因此采用枚举类型.的方式调用。
枚举类可以自定义构造方法,但是构造方法的修饰符必须是private,默认也是私有的。

枚举类实现接口的方式

枚举类实现接口后需要重写抽象方法,而重写方法的方式有两种:重写一个,或者每个对象都重写。

注解

注解的基本概念

注解(Annotation)又叫标注,是从Java5开始增加的一种引用数据类型。
注解本质上就是代码中的特殊标记,通过这些标记可以在编译、类加载、以及运行时执行指定的处理。

注解的语法格式

访问修饰符@interface注解名称{注解成员;
}
自定义注解自动继承java.lang.annotation.Annotation接口。
通过@注解名称的方式可以修饰包、类、成员方法、成员变量、构造方法、参数、局部变量的声明等。

注解的使用方式

注解体中只有成员变量没有成员方法,而注解的成员变量以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
如果注解只有一个参数成员,建议使用参数名为value,而类型只能是八种基本数据类型、String类型、Class类型、enum类型及Annotation类型。

元注解的概念

元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。
元注解主要有@Retention、@Documented、@Target、@Inherited、@Repeatable。

元注解@Retention

@Retention应用到一个注解上用于说明该注解的的生命周期,取值如下:
RetentionPolicy.SOURCE注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
RetentionPolicy.CLASS注解只被保留到编译进行的时候,它并不会被加载到JVM中,默认方式。
RetentionPolicy.RUNTIME注解可以保留到程序运行的时候,它会被加载进入到JVM中,所以在程序运行时可以获取到它们。

元注解@Documented

使用javadoc工具可以从程序源代码中抽取类、方法、成员等注释形成一个和源代码配套的API帮助文档,而该工具抽取时默认不包括注解内容。
@Documented用于指定被该注解将被javadoc工具提取成文档。
定义为@Documented的注解必须设置Retention值为RUNTIME。

元注解@Target

@Target用于指定被修饰的注解能用于哪些元素的修饰,取值如下:
在这里插入图片描述

元注解@Inherited

@Inherited并不是说注解本身可以继承,而是说如果一个超类被该注解标记过的注解进行注解时,如果子类没有被任何注解应用时,则子类就继承超类的注解。

元注解@Repeatable

@Repeatable表示自然可重复的含义,从Java8开始增加的新特性。
从Java8开始对元注解@Target的参数类型ElementType枚举值增加了两个:
其中ElementType.TYPE_PARAMETER表示该注解能写在类型变量的声明语句中,如:泛型。
其中ElementType.TYPE_USE表示该注解能写在使用类型的任何语句中。

常见的预制注解

在这里插入图片描述在这里插入图片描述

总结

  1. 内部类
    概念、普通内部类、静态内部类、局部内部类、匿名内部类、回调模式等
  2. 枚举类型
    概念、自定义枚举类、enum关键字、继承Enum类、实现接口等
  3. 注解
    概念、自定义注解、使用、元注解、预制注解等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值