Java自学笔记 — 面向对象4

内部类

1. 概念:

当一个类的定义,出现在另外一个类中时。那么这个类就是内部类。包含了 内部类 的类,叫做 外部类

2. 使用场景:

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

3. 分类:

  • 普通内部类: 直接将一个类的定义放在另外一个类的类体中。

  • 静态内部类:使用static关键字修饰的内部类,隶属于类层级。

  • 局部内部类: 直接将一个类的定义放在方法体的内部时。

  • 匿名内部类: 就是指没有名字的内部类。

4. 定义和使用:

  • 普通内部类:

    普通内部类,属于外部类中的一个属性,并且是对象层级

    // Outer类是外部类
    public class Outer{
    	private int cnt = 1;
       
      	// 定义普通内部类:Inner
        public class Inner{
            private int innerNum = 10;
            private int cnt = 3;// 和外部类中的属性同名
            
            // 内部类可以直接调用外部类的私有方法
            innerNum += cnt;
            // 
            System.out.println("内部类中的 cnt =  "+ this.cnt);
            System.out.println("外部类中的 cnt =  "+ Outer.this.cnt);
        }
    }
    /* 内部类的调用 */
    // 因为普通内部类,属于对象层级,需要外部类的引用,才可以访问
    Outer outer = new Outer();
    Outer.Inner in = outer.new inner();
    // 调用内部类的方法和属性,是需要先创建内部类中的对象的
    System.out.println(in.innerNum);
    
    
  • 静态内部类:

    静态,static,指提升到类层级,直接用类名. 就可访问。

    :要访问普通成员变量和方法,要通过引用来访问。而静态类,随着类的加载而加载,是先于引用和对象的创建。所以,static修饰的成员,不能访问非静态的成员变量或方法

    public class Outer{
        private int cnt = 1;
        private staitc int snt = 2;
        
        // 定义静态内部类
        public static class StaticInner{
            // 不能访问外部类的非静态方法
            private innerNum = snt;
            private snt = 10;
            // private innerNum = cnt; // 不能访问cnt
            
             System.out.println("内部类中的 snt =  "+ StaticInner.snt);
            System.out.println("外部类中的 snt =  "+ Outer.snt);
        }
    }
    /* 静态内部类的调用 */
    Outer.StaticInner os = new Outer.StaticInner();
    System.out.println(os.innerNum);
    
  • 局部内部类:

    • 局部内部类,定义在方法内部
    • 局部内部类中,不能使用访问控制符static修饰符。
    • 局部内部类可以使用外部方法的局部变量,但是必须是final的
    public class Outer{
        private int cnt = 1;
        public static final snt = 12;
        
        public void show(){
            // 定依局部内部类
            class Inner{
                int num = snt;
                ...
            }
        }
    }
    
  • 匿名内部类(重点):

    1. 语法格式

      接口 引用名 = new 接口(){
          方法的重写;
      }; 
      
      ---------------------------
      // 举例
      public interface A{
          void show();
      }
      
      public class b{
          // 使用匿名内部类
          A a = new A(){
            @Override
            public void show(){
                System.out.println("这是接口的实现类!不过是匿名");
            }
          };
      }
      
    2. 为什么叫做匿名内部类?

      ​ 接口是不能直接去new(实例化)的,要实例化就要有实现类。所以,用接口类型的引用指向 匿名的实现类对象。运用了多态,这样就能正常使用该接口。

    3. 从 Java8 ,推出了新特性:lamda表达式,来简化匿名内部类的代码

      • 格式:

        (参数列表) -> 方法体;
        
      • 根据上面的例子,简化匿名内部类的代码

        // 重写的show方法,没有形参,所以()内也不写
        A a =()-> System.out.println("lamda 如此简单");
        

总结一下,类中有哪些东西:

  • 成员变量(属性),成员方法,构造方法,静态成员 (static修饰的属性、方法),静态代码块,代码块,内部类

  • 为什么要使用匿名内部类?

    因为,当类或接口作为参数时,并且只用一次,那么为其单独写一个实现类,得不偿失。它会加载进内存一直占用内存 (方法区),直到程序结束,才会被释放,所以消耗内存空间


枚举

1. 基本概念:

  1. 生活中,常见的枚举:

    • 性别:男、女
    • 每周的:周一到周日
    • 一年的:春、夏、秋、冬
    • LOL 默认键位: Q、W、E、R
    • 开发中:描述一些状态信息,比如错误码等。
  2. 什么是枚举?

    ​ 生活中某些事物是有序且固定的。我们把这些事物一一列出,列出的类型就叫枚举类型。

  3. 注意事项:

    • 枚举,Java5开始增加的一种引用数据类型,用enum关键字来定

    • 枚举类中存储的值,默认使用 public static final 关键字共同修饰,所以是类级别的,直接用 枚举类型. 的方式调用

    • 枚举中常量的类型,就是 枚举类类型

    • 枚举类可以自定义构造方法,但是构造方法的修饰符必须是private,默认也是私有的。


2. 枚举的用法:

1)常量

Java5之前,常量是用 public static final 表示,常量一多,描述就较为繁琐。Java5之后,使用 enum关键字来定义枚举类型取代常量

// 定义一个枚举类Season,用来描述季节
public enum Season {  
  SPRING, SUMMER, AUTUMN, WINTER
}
2)switch
public Class enum SeasonTest{
    // switch结构
    public void test(Season se) {
        switch (se) {
            case SPRING:
                System.out.println("春天到了");
                break;
            case SUMMER:
                System.out.println("夏天到了");
                break;
            case AUTUMN:
                System.out.println("秋天到了");
                break;
            case WINTER:
                System.out.println("冬天到了");
                break;
        }
    }
}
// 调用
SeasonTest.test(Season.AUTUMN);
------------------------ " 结果 "
秋天到了  
3)实现接口

枚举默认继承了 java.lang.Enum , 所以枚举类不能用于继承 (单继承)

// 接口
interface GetSeason {
	// 得到季节信息
    String getInfo();
}

// GetSeason 接口的实现类
enum Season implements GetSeason {
    private String name;
    private String time;
    // 对象
    SPRING("春","3-5"),
    SUMMER("夏",""),
    AUTUMN("秋","9-11"), 
    WINTER("冬","12-2")
    // 构造方法必须是 private
    private Season(String name,String time){
        this.name = name;
        this.time = time;
    }
    
    // 方法的重写
    @Override
    public String getInfo() {
        return "每年的"+ this.time +"月为"+ this.name +"季";
    }
}

// 调用 (main方法中)
String str = Season.SUMMER.getInfo();
System.out.println(str)
------------------------------- " 结果 "
每年的6-8月为夏季
4) 常用方法 (继承与 Enum)
  • 获取枚举类中的所有对象: 静态方法values( )

    public enum Season {  
      SPRING, SUMMER, AUTUMN, WINTER
    }
    
    Season[] arr = Season.values()
    
  • 打印枚举类种的 对象名 toString() 、索引位置 ordinal()

    for(int i = 0; i < arr.length; i++){
        System.out.println("对象名:" + arr[i].toString());
        System.out.println("索引:" + arr[i].ordinal());
    }
    
    ------------------- " 结果 "
    对象名:SPRING
    索引:0
    对象名:SUMMER
    索引:1
    对象名:AUTUMN
    索引:2
    对象名:WINTER
    索引:3
    
  • 将参数指定的 字符串 ,转换为当前的 枚举类对象:静态方法valueOf( String str )

    注意:

    字符串必须在枚举名之中,才能转换,否者会出现参数非法异常:IllegaLargumentException

    // valueOf为静态方法,直接用枚举类型调用
    Season s = Season.valueOf("SUMMER");
    System.out.println("转换过来的枚举名是:" + s.toString());  
    
  • 比较 枚举中的枚举值(对象),在定义时的顺序:compareTo( E object )

    int num = A.compareTo(B);

    num 的正负可以看成,索引的比较,Index(A) - Index(B):

    1. if (num > 0),说明 A在B之后
    2. if (num < 0),说明 A 再B之前
    3. if (num = 0),说明 A,B 在相同位置
    // 比较 SUMMER、WINTER,在Season枚举中定义的先后顺序
    int num = Season.SUMMER.compareTo(Season.WINTER);
    

注解

  1. 概念:从 Java5开始增加的 一种 引用数据类型

  2. 语法格式:

    // 注解就是一个特殊的接口
    访问修饰符 @interface 注解名{
        注解成员;
    }
    
  3. 注解,默认继承了 java.lang.annotation.Annotation 接口

  4. 自定义注解,举例

    ​ 注解中成员属性的定义,看着像是抽象方法的定义,其实这就是成员变量的定义

    // 自定义 MyAnnotation注解
    public @interface MyAnnotation{
        // 声明一个String类型的成员变量,名字为value
        String value();	
        // 加了 default, 在使用注解的时候,就可以使用默认值而不给value2赋值
        String value2() default "18岁";
        
        
    }
    // 注解的使用
    @MyAnnotation(value = "小明" )
    public class Person{
        
    }
    

    注意:

    • 注解中,只有成员变量,无方法
    • 只有一个成员时,建议使用成员变量 value
    • 成员变量的类型,只能是:基本数据类型、String、Class、enum、Annotation类型

元注解

注解上的注解,或者说是:一种最基本的注解。

@Retention

描述的有效范围,或者生命周期, 取值为:

  • RetentionPolicy.SOURCE :注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
  • RetentionPolicy.CLASS :注解只被保留到编译进行的时候,它并不会被加载到JVM 中( 默认方式 )。
  • RetentionPolicy.RUNTIME :注解可以保留到程序运行的时候,它会被加载进入到JVM 中,所以在程序运行时可以获取到它们
@Retention(RetentionPolicy.SOURCE)// 下面的注解,只在源码中有效
@Retention(RetentionPolicy.CLASS )// 下面的注解,到编译阶段(字节码中)有效
@Retention(RetentionPolicy.RUNTIME )// 下面的注解,在解释执行阶段有效
public @interface MyAnnotation{
    ...;
}

RetentionPolicy 其实是一个 枚举类,作为 Retention注解的参数:

public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}

@Documented

被该注解标注的注解,在 javadoc 的时候就会把@Documented 标注的注解在文档中显示出来。(在生成文档时,默认是不包含注解的信息的)

@Target

@Target 标注的注解,可以修饰那些内容, 比如:

// 说明 @MyAnnotation,可以再注解上使用,也可以在构造方法上使用
@Target(ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR)
public @interface MyAnnotation{
    ...;
}
  • @Target (ElementType.TYPE)——接口、类、枚举、注解
  • @Target (ElementType.FIELD)——字段、枚举的常量
  • @Target (ElementType.METHOD)——方法
  • @Target (ElementType.PARAMETER)——方法参数
  • @Target (ElementType.CONSTRUCTOR) ——构造函数
  • @Target (ElementType.LOCAL_VARIABLE)——局部变量
  • @Target (ElementType.ANNOTATION_TYPE)——注解
  • @Target (ElementType.PACKAGE)——包

@Inherited

@Inherited 标注的注解,是否可以使用继承 (在被注解标记的那个类中)。举例:

@Inherited
public @interface MyAnnotation{
    ...;
}

@MyAnnotation
public class Person{
    ...
}

从上面的代码可以看到,MyAnnotation注解中,使用了 @Inherited ,所以被MyAnnotation注解 标注的 Person类 是可以做父类用于继承的。不然,不可以继承

@Repeatable

Java8新特性, @Repeatable标注的注解,在一个类上可以重复使用

预制注解

常见的有:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯子的模样

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值