java基础笔记-类与对象(特殊类)

内部类:

  •   仅仅为外部类服务
  •   可以隐藏该类的实现细节
  •   可以方便的访问外部类的私有成员而不需要提供公有的get ,set方法

内部类分类:  

  普通内部类: 直接将类定义在另一个类的类体内

  静态内部类: 使用static 修饰的内部类,属于类层级别

  局部内部类:定义在方法体中的类

  匿名内部类:没有名字的内部类(用的最多)

普通内部类:

  又称成员内部类。

 普通内部类的定义和使用例子:

package com.lagou.task10;

/**
 * 编程实现普通内部类的定义和使用       -  文档注释
 */
public class NormalOuter {
    private int cnt = 1;

    // 定义普通内部类,隶属于外部类的成员,并且是对象层级
    /*private*/public /*final*/ class NormalInner {
        private int ia = 2;
        private int cnt = 3;
        public NormalInner() {
            System.out.println("普通内部类的构造方法体执行到了!");
        }

        public void show() {
            System.out.println("外部类中变量cnt的数值为:" + cnt); // 1
            System.out.println("ia = " + ia); // 2
        }

        public void show2(int cnt) {
            System.out.println("形参变量cnt = " + cnt);  // 局部优先原则  4
            System.out.println("内部类中cnt = " + this.cnt); // 3
            System.out.println("外部类中cnt = " + NormalOuter.this.cnt); // 1
        }
    }
}
package com.lagou.task10;

public class NormalOuterTest {

    public static void main(String[] args) {

        // 1.声明NormalOuter类型的引用指向该类型的对象
        NormalOuter no = new NormalOuter();
        // 2.声明NormalOuter类中内部类的引用指向内部类的对象
        NormalOuter.NormalInner ni = no.new NormalInner();
        // 调用内部类中的show方法
        ni.show();

        System.out.println("---------------------------------------------");
        ni.show2(4);
    }
}

内部类 方法形参cnt ,内部类成员变量cnt,外部类成员变量cnt的区分:

  内部类 方法形参cnt  -> cnt

  内部类成员变量cnt  -> this.cnt

  外部类成员变量cnt  ->  NormalOuter.this.cnt

静态内部类:

语法格式:

  

 

静态内部类定义例子:

package com.lagou.task10;

/**
 * 实现静态内部类的定义和使用
 */
public class StaticOuter {
    private int cnt = 1;        // 隶属于对象层级
    private static int snt = 2; // 隶属于类层级

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

    /**
     * 定义静态内部类   有static关键字修饰隶属于类层级
     */
    public static class StaticInner {
        private int ia = 3;
        private static int snt = 4;

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

        public void show() {
            System.out.println("ia = " + ia); // 3
            System.out.println("外部类中的snt = " + snt); // 2
            //System.out.println("外部类的cnt = " + cnt); // Error:静态上下文中不能访问非静态的成员,因此此时可能还没有创建对象
        }

        public void show2(int snt) {  // 就近原则
            System.out.println("snt = " + snt); // 5
            System.out.println("内部类中的成员snt = " + StaticInner.snt); // 4
            System.out.println("外部类中的成员snt = " + StaticOuter.snt); // 2
            //StaticOuter.show();
            new StaticOuter().show();
        }
    }
}
package com.lagou.task10;

public class StaticOuterTest {

    public static void main(String[] args) {

        // 1.声明StaticInner类型的引用指向该类型的对象
        StaticOuter.StaticInner si = new StaticOuter.StaticInner();
        // 2.调用show方法进行测试
        si.show();

        System.out.println("---------------------------------------------");
        si.show2(5);
    }
}

 

静态内部类 方法形参snt ,静态内部类成员变量snt,静态外部类成员变量snt的区分:

  静态内部类 方法形参snt  -> snt

  静态内部类成员变量snt  ->StaticInner.snt

  静态外部类成员变量snt  -> StaticOuter.snt

静态 context 中 不能访问this,this 指当前类的对象

局部内部类:

  

  局部内部类不能使用访问修饰符 和 static 关键字

   局部内部类只在当前方法内部有效

  局部内部类可以在方法体内部创建对象

  局部内部类可以使用外部方法的局部变量,但是必须是理解为 final,这是因为局部内部类 和局部变量的声明周期不同所致

    局部内部类使用的局部变量必须理解为final,虽然final 关键字可以省略,但是建议加上,提高可读性。

    默认会拷贝一份局部变量到局部内部类使用,因此该局部变量不能改变。

局部内部类例子:

package com.lagou.task10;

/**
 * 编程实现局部内部类的定义和使用
 */
public class AreaOuter {
    private int cnt = 1;

    public void show() {

        // 定义一个局部变量进行测试,从Java8开始默认理解为final关键字修饰的变量
        // 虽然可以省略final关键字,但建议还是加上
        final int ic = 4;

        // 定义局部内部类,只在当前方法体的内部好使    拷贝一份
        class AreaInner {
            private int ia = 2;

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

            public void test() {
                int ib = 3;
                System.out.println("ia = " + ia); // 2
                System.out.println("cnt = " + cnt); // 1
                //ic = 5;  Error
                System.out.println("ic = " + ic); // 4
            }
        }

        // 声明局部内部类的引用指向局部内部类的对象
        AreaInner ai = new AreaInner();
        ai.test();
    }

}
package com.lagou.task10;

public class AreaOuterTest {

    public static void main(String[] args) {

        // 1.声明外部类类型的引用指向外部类的对象
        AreaOuter ao = new AreaOuter();
        // 2.通过show方法的调用实现局部内容类的定义和使用
        ao.show();
    }
}

 

 回调模式:

  回调模式是指——如果一个方法的参数是接口类型,则在调用该方法时, 需要创建并传递一个实现此接口类型的对象;

而该方法在运行时会调用 到参数对象中所实现的方法(接口中定义的)。

匿名内部类:

  语法格式:• 接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 }

例子:

package com.lagou.task10;

public interface AnonymousInterface {
    // 自定义抽象方法
    public abstract void show();
}
package com.lagou.task10;

public class AnonymousInterfaceTest {

    // 假设已有下面的方法,请问如何调用下面的方法?
    // AnonymousInterface ai = new AnonymousInterfaceImpl();
    // 接口类型的引用指向实现类型的对象,形成了多态
    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 ait = new AnonymousInterface() {
            @Override
            public void show() {
                System.out.println("匿名内部类就是这么玩的,虽然你很抽象!");
            }
        };

        // 从Java8开始提出新特性lamda表达式可以简化上述代码,格式为:(参数列表) -> {方法体}
        AnonymousInterface ait2 = () -> System.out.println("lamda表达式原来是如此简单!");
        AnonymousInterfaceTest.test(ait2);
    }
}

lambda 表达式:

格式为:(参数列表) -> {方法体} //需要重写的方法参数列表 ,需要重写的方法体


枚举类:

package com.lagou.task10;

public interface DirectionInterface {
    // 自定义抽象方法
    public abstract void show();
}
package com.lagou.task10;

/**
 * 编程实现所有方向的枚举,所有的方向:向上、向下、向左、向右   枚举类型要求所有枚举值必须放在枚举类型的最前面
 */
public enum DirectionEnum implements DirectionInterface {
    // 2.声明本类类型的引用指向本类类型的对象
    // 匿名内部类的语法格式:接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
    // public static final Direction UP = 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; // 用于描述方向字符串的成员变量

    // 通过构造方法实现成员变量的初始化,更加灵活
    // 1.私有化构造方法,此时该构造方法只能在本类的内部使用
    private DirectionEnum(String desc) { this.desc = desc; }

    // 通过公有的get方法可以在本类的外部访问该类成员变量的数值
    public String getDesc() {
        return desc;
    }

    // 整个枚举类型只重写一次,所有对象调用同一个
    /*@Override
    public void show() {
        System.out.println("现在可以实现接口中抽象方法的重写了!");
    }*/
}
package com.lagou.task10;

/**
 * 编程实现方向枚举类的测试,调用从Enum类中继承下来的方法
 */
public class DirectionEnumTest {

    public static void main(String[] args) {

        // 1.获取DirectionEnum类型中所有的枚举对象
        DirectionEnum[] arr = DirectionEnum.values();
        // 2.打印每个枚举对象在枚举类型中的名称和索引位置
        for (int i = 0; i < arr.length; i++) {
            System.out.println("获取到的枚举对象名称是:" + arr[i].toString());
            System.out.println("获取到的枚举对象对应的索引位置是:" + arr[i].ordinal()); // 和数组一样下标从0开始
        }

        System.out.println("---------------------------------------------------------------");
        // 3.根据参数指定的字符串得到枚举类型的对象,也就是将字符串转换为对象
        //DirectionEnum de = DirectionEnum.valueOf("向下"); // 编译ok,运行发生IllegalArgumentException非法参数异常
        DirectionEnum de = DirectionEnum.valueOf("DOWN");
        //DirectionEnum de = DirectionEnum.valueOf("UP LEFT"); // 要求字符串名称必须在枚举对象中存在
        //System.out.println("转换出来的枚举对象名称是:" + de.toString());
        System.out.println("转换出来的枚举对象名称是:" + de); // 当打印引用变量时,会自动调用toString方法

        System.out.println("---------------------------------------------------------------");
        // 4.使用获取到的枚举对象与枚举类中已有的对象比较先后顺序
        for(int i = 0; i < arr.length; i++) {
            // 当调用对象在参数对象之后时,获取到的比较结果为 正数
            // 当调用对象在参数对象相同位置时,则获取到的比较结果为 零
            // 当调用对象在参数对象之前时,则获取到的比较结果为 负数
            System.out.println("调用对象与数组中对象比较的先后顺序结果是:" + de.compareTo(arr[i]));
        }

        System.out.println("---------------------------------------------------------------");
        // 5.使用数组中每个DirectionEnum对象都去调用show方法测试
        for (int i = 0; i < arr.length; i++) {
            arr[i].show();
        }
    }
}

 注解:

   Annotation ,引用数据类型,可以看作特殊接口

  是一种标记,通过这些标记可以在编译、类加载、运行时做指定的处理。

 

  注解继承 java.lang.annotation.Annotation 接口

  没有成员的注解,叫标记或标识注解

  注解成员变量: public String value();// 声明一个String类型的成员变量

  注解只有成员变量,没有成员方法

  注解的成员变量用无形参的方式来声明,方法名是成员变量的名字,返回值是成员变量的类型

  注解只有一个成员的时候,一般使用value命名

  注解的类型 可以是String ,8种基本数据类型,class,enum,Annotation类型

  注解名称后,使用小括号 value = "hello"

  注解成员变量给默认值: public String value() default “123”;

 

元注解:

  可以对注解进行注解

  @Retention     保持,生命周期,有效范围

  @Documented  是否在文档注释中体现

  @Target        表示注解可以修饰哪些内容

  @Inherited     是否可继承

  @Repeatable   可重复

 

@Retention :

取值:

  RetentionPolicy.SOURCE //只在源码阶段保留,在编译时丢弃

  RetentionPolicy.CLASS  // 保留到class文件中,不被加载到JVM

       RetentionPolicy.RUNTIME // 可以保留到运行时

使用示例:@Retention(RetentionPolicy.SOURCE)

 

@Documented:

   javadoc 工具可以抽取类,方法,成员的注释,默认不包括注解内容

  idea: Tools -》Generate JavaDoc   命令行参数指定编码 -encoding utf-8

  @Documented 要求 @Retention(RetentionPolicy.RUNTIME)

  用来表示注解能否被 javadoc工具提取

使用示例:

  @Retention(RetentionPolicy.RUNTIME)

  @Documented

 

@Target:

  指定被修饰的注解可以修饰哪些元素

  取值:枚举类型

 

使用示例:

 @Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})

 

@Inherited :

  表示注解所修饰的类中的注解 可以被子类继承

package com.lagou.task10;

import java.lang.annotation.*;

//@Retention(RetentionPolicy.SOURCE)     // 表示下面的注解在源代码中有效
//@Retention(RetentionPolicy.CLASS)      // 表示下面的注解在字节码文件中有效,默认方式
@Retention(RetentionPolicy.RUNTIME)      // 表示下面的注解在运行时有效
@Documented                              // 表示下面的注解信息可以被javadoc工具提取到API文档中,很少使用
// 表示下面的注解可以用于类型、构造方法、成员变量、成员方法、参数 的修饰
@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Inherited  // 表示下面的注解所修饰的类中的注解使用可以被子类继承
// 若一个注解中没有任何的成员,则这样的注解叫做标记注解/标识注解
public @interface MyAnnotation {
    //public Direction value(); // 声明一个String类型的成员变量,名字为value   类型有要求
    public String value() default "123"; // 声明一个String类型的成员变量,名字为value
    public String value2();
}
package com.lagou.task10;

// 表示将标签MyAnnotation贴在Person类的代码中,使用注解时采用 成员参数名 = 成员参数值, ...
//@MyAnnotation(value = "hello", value2 = "world")
@MyAnnotation(value2 = "world")
public class Person {
    /**
     * name是用于描述姓名的成员变量
     */
    @MyAnnotation(value2 = "1")
    private String name;
    /**
     * age是用于描述年龄的成员变量
     */
    private int age;

    /**
     * 编程实现无参构造方法
     */
    @MyAnnotation(value2 = "2")
    public Person() {
    }

    /**
     * 编程实现有参构造方法
     * @param name
     * @param age
     */
    public Person(@MyAnnotation(value2 = "4") String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 自定义成员方法实现特征的获取和修改
     * @return
     */
    @MyAnnotation(value2 = "3")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

 

@Repeatable:

  表示注解可以被重复使用

  需要声明 成员变量是数组的注解

  

package com.lagou.task10;

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

/**
 * 自定义注解里面可以描述多种角色
 */
@Target(ElementType.TYPE_USE)
public @interface ManTypes {
    ManType[] value();
}
package com.lagou.task10;

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

/**
 * 自定义注解用于描述任务的角色
 */
@Repeatable(value = ManTypes.class)
@Target(ElementType.TYPE_USE)
public @interface ManType {
    String value() default "";
}
package com.lagou.task10;

@ManType(value = "职工")
@ManType(value = "超人")
//@ManTypes({@ManType(value = "职工"), @ManType(value = "超人")})  // 在Java8以前处理多个注解的方式
public class Man {

    @Deprecated // 表示该方法已经过时,不建议使用
    public void show() {
        System.out.println("这个方法马上过时了!");
    }

    public static void main(String[] args) {
        int ia = 97;
        char c1 = (@ManType char) ia;
    }
}

 预制注解:

  @Override 重写

  @Deprecated 过时

  @SuppressWarings 抑制编译器警告

 

 

文章来自拉勾教育 大数据开发

 

  

  

 

 

 

 

  

  

 

posted @ 2021-03-25 21:04  wangheng1409  阅读(73)  评论(0编辑  收藏  举报