javase(2023/11/18)

1、内部类

匿名内部类

简单介绍

  • 类只是使用一次,后面再不使用,可以简化开发
  • (1)本质是(实现接口/继承父类的)类(2)内部类(3)该类没有名字(4)同时还是一个对象
  • 匿名内部类的基本语法:  new类或接口(参数列表){类体}
  • 可以在方法体中还可以在参数中

注意事项

  • 匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义,
  • 同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法
  • 可以直接访问外部类的所有成员,包含私有的
  • 不能添加访问修饰符,因为它的地位就是一个局部变量。
  • 作用域:仅仅在定义它的方法或代码块中。
  • 匿名内部类---访问---->外部类成员[访问方式:直接访问]
  • 外部其他类---不能访问----->匿名内部类(因为匿名内部类地位是一个局部变量)
  • 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
  • 使用时遵循动态绑定


 

package zhh.chapter09.innerclass;

import java.awt.print.Printable;

public class AnonymousInnerClass {
    public static void main(String[] args) {
        new outer02().method();
//        输出是:
//        基于接口的匿名内部类 对象调用print1:1
//        ia的运行类型: class zhh.chapter09.innerclass.outer02$1
//        基于接口的匿名内部类 直接调用print1:11
//        访问外部类私有成员n1: 10
//        内部n2: 100外部n2: 10
//        基于接口的匿名内部类 对象调用print1:1
//
//        基于类的匿名内部类 对象调用print2:2
//        ib的运行类型: class zhh.chapter09.innerclass.outer02$3
//        基于类的匿名内部类 直接调用print2:22
//
//        基于抽象类的匿名内部类 对象调用print3:3
//        ic的运行类型: class zhh.chapter09.innerclass.outer02$5
//        基于抽象类的匿名内部类 对象调用print3:33
    }
}

class outer02{
    private int n1=10;
    private int n2=10;
    public void method(){
        //基于接口的匿名内部类
        //5. ia 的编译类型 ? IA
        //6. ia 的运行类型 ? 就是匿名内部类 Outer02$1
        /*
        底层会分配 类名 Outer02$1,类似于
        class Outer02$1 implements IA {
           @Override
            public void print1() {
                System.out.println("基于接口的匿名内部类 对象调用print1:"+"1");
            }
        }
        */
        //7. jdk 底层在创建匿名内部类 Outer02$1,立即马上就创建了 Outer02$1 实例,并且把地址
        // 返回给 ia
        //下面ib ic同理
        IA ia = new IA(){
            private int n2=100;
            @Override
            public void print1() {
                System.out.println("基于接口的匿名内部类 对象调用print1:"+"1");
            }
        };
        ia.print1();
        System.out.println("ia的运行类型: "+ia.getClass());

        new IA(){
            @Override
            public void print1() {
                System.out.println("基于接口的匿名内部类 直接调用print1:"+"11");
                //内部类直接访问外部成员
                System.out.println("访问外部类私有成员n1: "+n1);
                //成员重名,就近原则
                System.out.println("内部n2: "+n2+"外部n2: "+outer02.this.n2);
            }
        }.print1();
        ia.print1();


        //基于类的匿名内部类
        IB ib = new IB(){
            @Override
            public void print2() {
                System.out.println("\n基于类的匿名内部类 对象调用print2:"+"2");
            }
        };
        ib.print2();
        System.out.println("ib的运行类型: "+ib.getClass());

        new IB(){
            @Override
            public void print2() {
                System.out.println("基于类的匿名内部类 直接调用print2:"+"22");
            }
        }.print2();


        //基于抽象类的匿名内部类
        IC ic = new IC(){
            @Override
            void print3() {
                System.out.println("\n基于抽象类的匿名内部类 对象调用print3:"+"3");
            }
        };
        ic.print3();
        System.out.println("ic的运行类型: "+ic.getClass());

        new IC(){
            @Override
            void print3() {
                System.out.println("基于抽象类的匿名内部类 对象调用print3:"+"33");
            }
        }.print3();


    }

}

interface IA{
    public void print1();
}

class IB{
    public void print2(){
        System.out.println("print2:"+"2");
    }
}

abstract class IC{
    abstract void print3();
}

匿名内部类最佳实践

package zhh.chapter09.innerclass;

public class AnonymousInnerClassBestExer {

    public static void main(String[] args) {
        f(new IE(){
            @Override
            public void print4() {
                System.out.println("内部类当做实参,直接传递!");
            }
        });

        //当“System.out.println("内部类当做实参,直接传递!");”
        //使用多次时,可以用传统方法
        //创建类实现接口,创建此类对象作为实参
        f(new IF());

//        print
//        内部类当做实参,直接传递!
//        创建对象当做实参,直接传递!

    }

    //参数为类也ok!
    //到时传递一个内部类继承此类就行
    public static void f(IE ie){
        ie.print4();
    }
}

interface IE{
    public void print4();
}

class IF implements IE{
    @Override
    public void print4() {
        System.out.println("创建对象当做实参,直接传递!");
    }
}

成员内部类

没有static修饰

注意事项

  1. 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
  2. 作用域和外部类的其他成员一样,为整个类体
  3. 成员内部类---访问---->外部类成员(比如:属性) 【访问方式:直接访问】
  4. 外部类---访问------>成员内部类 【访问方式:创建对象,再访问】
  5. 外部其他类---访问---->成员内部类(如代码)
  6. 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
     

package zhh.chapter09.innerclass;

public class MemberInnerClass {
    public static void main(String[] args) {
        Outer3 outer3 = new Outer3();
        outer3.t1();

        //外部其他类,使用成员内部类的2种方式
        // 第一种方式
        // outer08.new Inner08(); 相当于把 new Inner08()当做是 outer08 成员
        // 通过外部类对象去new
        Outer3.Inner3 inner08 = outer3.new Inner3();
        inner08.say();

        // 第二方式 在外部类中,编写一个方法,可以返回 Inner08 对象
        Outer3.Inner3 Inner3Instance = outer3.getInner3Instance();
        Inner3Instance.say();
        
//        print
//        n1 = 66 name = 张三 外部类的 n1=10
//        hi()方法...
//        99.8
//        n1 = 66 name = 张三 外部类的 n1=10
//        hi()方法...
//        n1 = 66 name = 张三 外部类的 n1=10
//        hi()方法...
    }
}
class Outer3 { //外部类
    private int n1 = 10;
    public String name = "张三";
    private void hi() {
        System.out.println("hi()方法...");
    }

    //1.注意: 成员内部类,是定义在外部内的成员位置上
    //2.可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
    public class Inner3 {//成员内部类
        private double sal = 99.8;
        private int n1 = 66;
        public void say() {
        //可以直接访问外部类的所有成员,包含私有的
        //如果成员内部类的成员和外部类的成员重名,会遵守就近原则.
        // ,可以通过 外部类名.this.属性 来访问外部类的成员
        System.out.println("n1 = " + n1 + " name = " + name + " 外部类的 n1=" + Outer3.this.n1);
        hi();
        }
    }

    //方法,返回一个 Inner08 实例
    public Inner3 getInner3Instance(){
        return new Inner3();
    }

    //写方法
    public void t1() {
    //使用成员内部类
    //创建成员内部类的对象,然后使用相关的方法
        Inner3 inner3 = new Inner3();
        inner3.say();
        System.out.println(inner3.sal);
    }
}

静态内部类

静态内部类是定义在外部类的成员位置,并且有static修饰

注意事项

  1. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
  2. 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
  3. 作用域:同其他的成员,为整个类体
  4. 静态内部类---访问---->外部类(比如:静态属性)[访问方式:直接访问所有静态成员]
  5. 外部类---访问------>静态内部类访问方式:创建对象,再访问
  6. 外部其他类---访问----->静态内部类(代码)
  7. 如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
package zhh.chapter09.innerclass;

public class StaticInnerClass {
    public static void main(String[] args) {
        Outer4 outer4 = new Outer4();
        outer4.m1();

        //外部其他类 使用静态内部类
        //方式 1
        //因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
        Outer4.Inner4 inner10 = new Outer4.Inner4();
        inner10.say();

        //方式 2
        //编写一个方法,可以返回静态内部类的对象实例.
        //普通方法用外部类对象名调用
        Outer4.Inner4 inner101 = outer4.getInner4();
        System.out.println("============");
        inner101.say();

        //静态方法用外部类名调用
        Outer4.Inner4 inner10_ = Outer4.getInner4_();
        System.out.println("************");
        inner10_.say();

//        print
//        李四 外部类 name= 张三
//        李四 外部类 name= 张三
//                ============
//        李四 外部类 name= 张三
//                ************
//        李四 外部类 name= 张三

    }
}

class Outer4 { //外部类
    private int n1 = 10;
    private static String name = "张三";
    private static void cry() {}

    //Inner4 就是静态内部类
    //1. 放在外部类的成员位置
    //2. 使用 static 修饰
    //3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
    //4. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
    //5. 作用域 :同其他的成员,为整个类体
    static class Inner4 {
        private static String name = "李四";
        public void say() {
        //如果外部类和静态内部类的成员重名时,静态内部类访问时,
        //默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.成员)
            System.out.println(name + " 外部类 name= " + Outer4.name);
            cry();
        }
    }
    public void m1() { //外部类---访问------>静态内部类 访问方式:创建对象,再访问
        Inner4 inner4 = new Inner4();
        inner4.say();
    }
    public Inner4 getInner4() {
        return new Inner4();
    }
    public static Inner4 getInner4_() {
        return new Inner4();
    }
}

2、枚举

枚举对应英文(enumeration, 简写 enum),一组常量的集合,属于一种特殊的类,里面只包含一组有限的特定的对象。

二种实现方式

  • 自定义类实现枚举 
  • 使用 enum 关键字实现枚举
     

注意事项

  • 当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类, 而且是一个 final 类,所以不能再继承其它类,Java 是单继承机制。但可以实现接口。
  • 传统的 public static final Season2 SPRING = new Season2("春天", "温暖"); 简化成 SPRING("春天", "温暖"), 这里必 须知道,它调用的是哪个构造器.
  • 如果使用无参构造器 创建 枚举对象,则实参列表和小括号都可以省略
  • 当有多个枚举对象时,使用,间隔,最后有一个分号结尾
  • 枚举对象必须放在枚举类的行首

enum常用方法

1) toString:Enum 类已经重写过了,返回的是当前对象 名,子类可以重写该方法,用于返回对象的属性信息

2) name:返回当前对象名(常量名),子类中不能重写

3) ordinal:返回当前对象的位置号,默认从 0 开始

4) values:返回当前枚举类中所有的常量

5) valueOf:将字符串转换成枚举对象,要求字符串必须 为已有的常量名,否则报异常!

6) compareTo:比较两个枚举常量,比较的就是编号!

package zhh.chapter10;

import javax.crypto.SealedObject;

/**
 * @author longbownice
 * @version 1.0
 *
 * enum实现枚举
 */
public class Enumeration02 {

    public static void main(String[] args) {
        //返回当前枚举类中所有的常量
        Season2[] season = Season2.values();
        for(Season2 s:season){
            System.out.println(s);
        }

        Season2 summer = Season2.SUMMER;
        //name:返回当前对象名(常量名),子类中不能重写
        System.out.println(summer.name());

        //ordinal:返回当前对象的位置号,默认从 0 开始
        System.out.println(summer.ordinal());

        //valueOf:将字符串转换成枚举对象,要求字符串必须 为已有的常量名,否则报异常!
        //感觉没啥用,以后再看
        Season2 summer1=Season2.valueOf("SUMMER");

        //compareTo:比较两个枚举常量,比较的就是编号!
        //return 前面编号 - 后边编号
        System.out.println(summer1.compareTo(Season2.WINNER));


    }

//    print
//    Season2{name='春天'}
//    Season2{name='夏天'}
//    Season2{name='秋天'}
//    Season2{name='冬天'}
//    Season2{name='null'}
//    SUMMER
//    1
//    -2

}

//1. 使用关键字 enum 替代 class
enum Season2{

    //2. public static final Season SPRING = new Season("春天", "温暖") 直接使用
    // SPRING("春天", "温暖") 解读 常量名(实参列表)
    //3. 如果有多个常量(对象), 使用 ,号间隔即可
    //4. 如果使用 enum 来实现枚举,要求将定义常量对象,写在行首
    //5. 如果我们使用的是无参构造器,创建常量对象,则可以省略 ()
    SPRING("春天"),SUMMER("夏天"),
    AUTUMN("秋天"),WINNER("冬天"),
    WHAT;
    private String name;

    private Season2(){}
    private Season2(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Season2{" +
                "name='" + name + '\'' +
                '}';
    }

}

3、注解的理解

  • 注解(Annotation)也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息。
  • 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
  • 在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE 中注解占据了更重要的角 色,例如用来配置应用程序的任何切面,代替 java EE 旧版中所遗留的繁冗代码和 XML 配置等。
  • 使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元素

三个基本的 Annotation:

  • @Override: 限定某个方法,是重写父类方法, 该注解只能用于方法
  • @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
  • @SuppressWarnings: 抑制编译器警告
//1. 如果写了@Override 注解,编译器就会去检查该方法是否真的重写了父类的
    // 方法,如果的确重写了,则编译通过,如果没有构成重写,则编译错误
    //2. 看看 @Override 的定义
    // 解读: 如果发现 @interface 表示一个 注解类
    /*
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    */
    @Override


//1. @Deprecated 修饰某个元素, 表示该元素已经过时
    //2. 即不在推荐使用,但是仍然可以使用
    //3. 查看 @Deprecated 注解类的源码
    //4. 可以修饰方法,类,字段, 包, 参数 等等
    //5. @Deprecated 可以做版本升级过渡使用
    /*
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
    public @interface Deprecated {
    }
    */
    @Deprecated


//1. 当我们不希望看到这些警告的时候,可以使用 SuppressWarnings 注解来抑制警告信息
    //2. 在{""} 中,可以写入你希望抑制(不显示)警告信息
    //3. 可以指定的警告类型有
    //      all,抑制所有警告
    //      boxing,抑制与封装/拆装作业相关的警告
    //      cast,抑制与强制转型作业相关的警告
    //      dep-ann,抑制与淘汰注释相关的警告
    //      deprecation,抑制与淘汰的相关警告
    //      fallthrough,抑制与 switch 陈述式中遗漏 break 相关的警告
    //      finally,抑制与未传回 finally 区块相关的警告
    //      hiding,抑制与隐藏变数的区域变数相关的警告
    //      incomplete-switch,抑制与 switch 陈述式(enum case)中遗漏项目相关的警告
    //      javadoc,抑制与 javadoc 相关的警告
    //      nls,抑制与非 nls 字串文字相关的警告
    //      null,抑制与空值分析相关的警告
    //      rawtypes,抑制与使用 raw 类型相关的警告
    //      resource,抑制与使用 Closeable 类型的资源相关的警告
    //      restriction,抑制与使用不建议或禁止参照相关的警告
    //      serial,抑制与可序列化的类别遗漏 serialVersionUID 栏位相关的警告
    //      static-access,抑制与静态存取不正确相关的警告
    //      static-method,抑制与可能宣告为 static 的方法相关的警告
    //      super,抑制与置换方法相关但不含 super 呼叫的警告
    //      synthetic-access,抑制与内部类别的存取未最佳化相关的警告
    //      sync-override,抑制因为置换同步方法而遗漏同步化的警告
    //      unchecked,抑制与未检查的作业相关的警告
    //      unqualified-field-access,抑制与栏位存取不合格相关的警告
    //      unused,抑制与未用的程式码及停用的程式码相关的警告
    
    //4. 关于 SuppressWarnings 作用范围是和你放置的位置相关
    // 比如 @SuppressWarnings 放置在 main 方法,那么抑制警告的范围就是 main
    // 通常我们可以放置具体的语句, 方法, 类. 
    
    //5. 看看 @SuppressWarnings 源码
    //(1) 放置的位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE
    //(2) 该注解类有数组 String[] values() 设置一个数组比如 {"rawtypes", "unchecked", "unused"}
    /*
    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
    String[] value();
    }
    */
    @SuppressWarnings

4、元注解了解

JDK 的元 Annotation 用于修饰其他 Annotation

修饰注解的注解

1) Retention //指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME

2) Target // 指定注解可以在哪些地方使用

3) Documented //指定该注解是否会在 javadoc 体现

4) Inherited //子类会继承父类注解,被它修饰的Annotation将具有继承性.即如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解
 

@Retention 注解

说明 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值: @Retention 的三种值

  • RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注释(javac前)
  • RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解。 这是默认值 (javac后)
  • RetentionPolicy.RUNTIME:编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以 通过反射获取该注解(java后)

 

/*
    //表明只对方法有用
    @Target(ElementType.METHOD)
    
    //说明: Override的作用域在SOURCE,当编译器编译时生效,不会写入到.class文件,也不会再runtime(运行时)生效

    @Retention(RetentionPolicy.SOURCE) 
    public @interface Override {
    }
    */
    @Override
/*
    //表明可以留在javadoc形成的文档中
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
    public @interface Deprecated {
    }
    */
    @Deprecated
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值