Java基础13

内部类

将一个类A定义在另一个类B里面,里面的那个类A就称为 内部类 ,类B则称为 外部类。 

内部类的声明理由:

当一个事物A的内部,有一部分需要一个完整的结构B进行描述,而这个内部结构B只为外部事物A提供服务,并不会在其他地方用到,那么整个内部的完整结构B最好使用内部类。

遵循 高内聚、低耦合 的面向对象开发原则。

举例: Thread类内部声明了State类,表示线程的生命周期。

      HashMap类中声明了Node类,表示封装的key和Value

分类:(参考变量的分类)

> 成员内部类:直接声明在外部类的里面

  > 使用static修饰的: 静态的成员内部类

  > 不使用static修饰的:非静态的成员内部类

> 局部内部类:声明在方法内、构造器内、代码块内的内部类

  > 匿名的局部内部类

  > 非匿名的局部内部类

复制代码
class Person{ // 外部类
    // 静态的成员内部类
    static  class Dog{

    }

    // 非静态的成员内部类
    class Bird{

    }

    public void method(){
        // 局部内部类
        class InnerClass1{

        }
    }

    public Person(){
        // 局部内部类
        class InnerClass1{

        }
    }

    {
        // 局部内部类
        class InnerClass1{
            
        }
    }
}
复制代码

成员内部类的理解

> 从类的角度看:

  - 内部可以声明属性、方法、构造器、代码块、内部类等结构

  - 此内部类可以声明父类,可以实现接口

  - 可以使用final修饰

  - 可以使用abstract修饰

> 从外部类的成员的角度看:

  - 在内部可以调用外部类的结构。比如:属性、方法等

  - 除了使用public、缺省权限修饰之外,还可以用private、protected修饰

  - 可以使用static修饰

创建成员内部类的实例

复制代码
public class OuterClassTest {
    public static void main(String[] args) {
        //1.创建Person的静态的成员内部类的实例
        Person.Dog dog = new Person.Dog();
        dog.eat();
        //2.创建Person的非静态的成员内部类的实例
//    Person.Bird bird = new Person.Bird();  错误写法
        Person p1 = new Person();
        Person.Bird bird = p1.new Bird();
        bird.eat();

    }
}

class Person{ // 外部类
    // 静态的成员内部类
    static  class Dog{
        public void eat(){
            System.out.println("吃骨头!");
        }
    }

    // 非静态的成员内部类
    class Bird{
        public void eat(){
            System.out.println("鸟吃虫!");
        }
    }
}
复制代码

在成员内部类中调用外部类的结构

复制代码
public class OuterClassTest {
    public static void main(String[] args) {
        //1.创建Person的静态的成员内部类的实例
        Person.Dog dog = new Person.Dog();
        dog.eat();
        //2.创建Person的非静态的成员内部类的实例
//    Person.Bird bird = new Person.Bird();  错误写法
        Person p1 = new Person();
        Person.Bird bird = p1.new Bird();
        bird.eat();
        bird.show("黄鹂");
        bird.show1();
    }
}

class Person{ // 外部类
    String name = "Tom";
    int age = 20;
    // 静态的成员内部类
    static  class Dog{
        public void eat(){
            System.out.println("吃骨头!");
        }
    }

    // 非静态的成员内部类
    class Bird{
        String name = "啄木鸟";
        public void eat(){
            System.out.println("鸟吃虫!");
        }
        public void show(String name){
            System.out.println("age = " + age);  // 20
            System.out.println("name = " +name);  // 黄鹂  show 方法的形参
            System.out.println("name = " + this.name);  // 啄木鸟 (谁调用这个方法就是谁)
            System.out.println("name = " + Person.this.name);  // Tom
        }
        public void show1 (){
            eat();  // 鸟吃虫!
            this.eat();  // 鸟吃虫!
            Person.this.eat();  // 人吃饭!
        }
    }
    public void eat(){
        System.out.println("人吃饭!");
    }
}
复制代码

局部内部类的使用

复制代码
public class OuterClassTest {
    // 说明:局部内部类的使用
    public void method1(){
        // 局部内部类
        class A{
            // 可以声明属性、方法等
        }
    }

    //开发中的场景
    public Comparable getInstance(){  //返回一个实现了Comparable的对象
        // 提供了实现Comparable接口的类
        // 方式1: 提供了接口的实现类的匿名对象
        class MyComparable implements Comparable{
            @Override
            public int compareTo(Object o) {
                return 0;
            }
        }
        return  new MyComparable();
    }

    public Comparable getInstance1(){
        // 方式2:提供了接口的匿名实现类的对象
        Comparable c = new Comparable() {
            @Override
            public int compareTo(Object o) {
                return 0;
            }
        };
        return c;
    }

    public Comparable getInstance2(){
        // 方式3:提供了接口的匿名实现类的匿名对象
        return new Comparable() {
            @Override
            public int compareTo(Object o) {
                return 0;
            }
        };
    }

}
复制代码

 练习

编写一个匿名内部类,它继承Object,并在匿名内部类中声明一个方法public void test( )打印尚硅谷。

复制代码
public class InnerTest {
    public static void main(String[] args) {
        new Object(){  // 这里实际上是一个继承了Object类匿名实现类的匿名对象
            public void test(){
                System.out.println("你好!");
            }
        }.test(); // 在这里直接调用了匿名对象的方法
    }
}
复制代码

匿名对象实现的几种举例

复制代码
public class OuterClassTest {
    public static void main(String[] args) {
        // 传统方法
        SubA a = new SubA();
        a.method();
        // 举例1
        A a1 = new A() {  // 提供接口匿名实现类的对象
            @Override
            public void method() {
                System.out.println("匿名实现类重写的方法");
            }
        };
        a1.method();
        // 举例2
        new A(){  // 提供接口匿名实现类的匿名对象
            @Override
            public void method() {
                System.out.println("匿名实现类重写的方法");
            }
        }.method();

        //传统方法
        SubB b = new SubB();
        b.method1();
        //方法1:
        B b1 = new B() {
            @Override
            public void method1() {
                System.out.println("继承于抽象类的子类调用的方法");
            }
        };
        b1.method1();
        // 方法2
        new B(){
            @Override
            public void method1() {
                System.out.println("继承于抽象类的子类调用的方法");
            }
        }.method1();

        //传统方法
        C c = new C();
        c.method2();
        //方法1:
        C c1 = new C(){};  // 提供了一个继承于C的匿名子类的对象  这里花括号里面没写 因为不是继承的抽象类 所以没有必须要重写的方法
        c1.method2();
    }
}

interface A{
    public void method();
}
// 传统做法
class SubA implements A{
    @Override
    public void method() {
        System.out.println("SubA!");
    }
}
abstract class B{
    public abstract void method1();
}

class SubB extends B{
    @Override
    public void method1() {
        System.out.println("SubB!");
    }
}

class C{
    public void method2(){
        System.out.println("C");
    }
}
复制代码

 枚举类

枚举类的理解:

枚举类本质上也是一种类,只不过这个类的对象是有限的、固定的几个,不能让用户随意创建。

举例:

- ‘星期’ : Monday、......、Sunday

- '性别':Man、Woman

可以直接用类调用对象

开发中的建议:

> 开发中,如果针对于某种类,其实例是确定个数的。则推荐将此类声明为枚举类。

> 如果枚举类的实例只有一个,则可以看作是单例的实现方式。

jdk5.0之前定义枚举类(了解)

复制代码
public class SeasonTest {
    public static void main(String[] args) {
        System.out.println(Season.SPRING);
        System.out.println(Season.SUMMER.getSeasonDesc());
    }

}

// jdk5.0之前的定义枚举类的方式
class Season{
    // 2.声明当前类的对象的实例变量 需要使用private final修饰
    private final String seasonName; // 季节的名称
    private final String seasonDesc; // 季节的描述
    // 1. 私有化类的构造器
    private Season(String seasonName, String seasonDesc) {  // final修饰的必须在构造器、代码块等地方初始化
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    // 3. 提供实例变量的get方法
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }

    //4. 创建当前类的实例 需要使用public static final修饰
    public static final Season SPRING = new Season("春天","春暖花开");
    public static final Season SUMMER = new Season("夏天","夏日炎炎");
    public static final Season AUTUMN = new Season("秋天","秋高气爽");
    public static final Season WINTER = new Season("冬天","白雪皑皑");

    @Override
    public String toString() {
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
}
复制代码

jdk5.0中使用enum定义枚举类

复制代码
public class SeasonTest1 {
    public static void main(String[] args) {
        System.out.println(Season1.AUTUMN);
        System.out.println(Season1.SPRING.getSeasonDesc());
    }
}

// jdk5.0中使用enum关键字定义枚举类
enum Season1{
    //1. 必须在枚举类的开头声明多个对象。对象之间使用,隔开
    SPRING("春天","春暖花开"),
    SUMMER("夏天","夏日炎炎"),
    AUTUMN("秋天","秋高气爽"),
    WINTER("冬天","白雪皑皑");

    // 2.声明当前类的对象的实例变量 需要使用private final修饰
    private final String seasonName; // 季节的名称
    private final String seasonDesc; // 季节的描述
    // 1. 私有化类的构造器
    private Season1(String seasonName, String seasonDesc) {  // final修饰的必须在构造器、代码块等地方初始化
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    // 3. 提供实例变量的get方法
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }
}
复制代码

Enum中的常用方法

使用enum关键字定义的枚举类,默认其父类是java.lang.Enum

使用enum关键字定义的枚举类,不要再显示的定义其父类,否则报错。

常用方法

String toString():默认返回的是常量名(对象名),可以继续手动重写该方法。

(重点)static 枚举类型[] values():返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值,是一个静态方法。

(重点)static 枚举类型 valueOf(String name):可以把一个字符串转为对应的枚举类对象,要求字符串必须是枚举类对象的实例。

String name():得到当前枚举常量的名字。建议优先使用toString()。

int ordinal():返回当前枚举常量的次序号,默认从0开始。

复制代码
public class SeasonTest1 {
    public static void main(String[] args) {
        //测试方法
        // 1. toString()
        System.out.println(Season1.SPRING);  //如果没有重写toString方法,默认打印名称(SPRING),可以重写toString方法更改

        // 2. values()  可以查看枚举类的对象有哪些
         Season1[] values = Season1.values();
         for(int i = 0; i < values.length; i ++){
             System.out.println(values[i]);
         }

        // 3. valueOf(String objName): 返回当前枚举类中名称为objName的枚举类对象
        // 如果枚举类中不存在为objName名称的对象,则报错!
        String objName = "WINTER";
        Season1 season1 = Season1.valueOf(objName);
        System.out.println(season1);

        // 4. name()
        System.out.println(Season1.SPRING.name());  // 默认打印对象的名字 SPRING

        // 5. ordinal()  打印对象所在的列表的位置
        System.out.println(Season1.AUTUMN.ordinal());
    }
}

// jdk5.0中使用enum关键字定义枚举类
enum Season1{
    //1. 必须在枚举类的开头声明多个对象。对象之间使用,隔开
    SPRING("春天","春暖花开"),
    SUMMER("夏天","夏日炎炎"),
    AUTUMN("秋天","秋高气爽"),
    WINTER("冬天","白雪皑皑");

    // 2.声明当前类的对象的实例变量 需要使用private final修饰
    private final String seasonName; // 季节的名称
    private final String seasonDesc; // 季节的描述
    // 3. 私有化类的构造器
    private Season1(String seasonName, String seasonDesc) {  // final修饰的必须在构造器、代码块等地方初始化
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    // 4. 提供实例变量的get方法
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }
}
复制代码

枚举类实现接口的操作

情况1: 枚举类实现接口,在枚举类中重写接口的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是同一个方法

情况2: 让枚举类的每一个对象重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是不同的实现的方法。

  • 情况1
复制代码
public class SeasonTest1 {
    public static void main(String[] args) {
        // 通过枚举类的对象调用接口中重写的方法
        Season1.AUTUMN.show();
    }
}

interface Info{
    void show();
}

// jdk5.0中使用enum关键字定义枚举类
enum Season1 implements Info{
    //1. 必须在枚举类的开头声明多个对象。对象之间使用,隔开
    SPRING("春天","春暖花开"),
    SUMMER("夏天","夏日炎炎"),
    AUTUMN("秋天","秋高气爽"),
    WINTER("冬天","白雪皑皑");

    // 2.声明当前类的对象的实例变量 需要使用private final修饰
    private final String seasonName; // 季节的名称
    private final String seasonDesc; // 季节的描述
    // 3. 私有化类的构造器
    private Season1(String seasonName, String seasonDesc) {  // final修饰的必须在构造器、代码块等地方初始化
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    // 4. 提供实例变量的get方法
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }

    @Override // 重写接口中的方法
    public void show() {
        System.out.println("这是一个季节");
    }
}
复制代码
  • 情况2
复制代码
public class SeasonTest2 {
    public static void main(String[] args) {
        Season2[] season2 = Season2.values();
        for (int i = 0; i < season2.length; i ++){
            season2[i].show();
        }
    }
}

interface Info1{
    void show();
}

// jdk5.0中使用enum关键字定义枚举类
enum Season2 implements Info{
    //1. 必须在枚举类的开头声明多个对象。对象之间使用,隔开
    SPRING("春天","春暖花开"){
        @Override
        public void show() {
            System.out.println("春天在哪里?");
        }
    },
    SUMMER("夏天","夏日炎炎"){
        @Override
        public void show() {
            System.out.println("宁静的夏天!");
        }
    },
    AUTUMN("秋天","秋高气爽"){
        @Override
        public void show() {
            System.out.println("秋意浓!");
        }
    },
    WINTER("冬天","白雪皑皑"){
        @Override
        public void show() {
            System.out.println("大约在冬季");
        }
    };

    // 2.声明当前类的对象的实例变量 需要使用private final修饰
    private final String seasonName; // 季节的名称
    private final String seasonDesc; // 季节的描述
    // 3. 私有化类的构造器
    private Season2(String seasonName, String seasonDesc) {  // final修饰的必须在构造器、代码块等地方初始化
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    // 4. 提供实例变量的get方法
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }
}
复制代码

使用枚举类实现单例模式

复制代码
public class BankTest1 {
    public static void main(String[] args) {
        System.out.println(Bank2.CPB);
    }
}
// jdk5.0之前的使用枚举类定义单例模式
class Bank1{
    private Bank1() {
    }
    private static final Bank1 instance = new Bank1();

}
// jdk5.0中使用enum关键字定义枚举类的方式定义单例模式
enum Bank{
    CPB; // 没有具体对象的实例变量
}
//上面类 有具体对象的实例变量
enum Bank2{
    CPB("BeiJing"); // 传统的写法是:public static final Bank2 CPB = new Bank2("BeiJing");
    private final String site;
    private Bank2(String site){
        this.site = site;
    }
}
复制代码

 练习

声明final修饰的int类型的属性red,green,blue
声明final修饰的String类型的属性description
声明有参构造器Color(int red,int green,int blue,String description)
创建7个常量对象:红、橙、黄、绿、青、蓝、紫
重写toString方法,例如:RED(255,0,0)->红色
(2)在测试类中,使用枚举类,获取绿色对象,并打印对象
提示:
-7个常量对象的RGB值如下
红:(255,0 0)
橙:(255,128,0)
黄:(255,255,0)
绿:(0,255,0)
青:(0,255,255)
蓝:(0,0,255)
紫:(128,0,255)
7个常量对象名如下:
RED, ORANGE, YELLOW, GREEN, CYAN, BLUE,PURPLE

复制代码
public class ColorTest {
    public static void main(String[] args) {
        Color[] colors = Color.values();
        for (int i = 0; i < colors.length; i++){
            System.out.println(colors[i]);
        }
        System.out.println(Color.YELLOW.name());
    }
}

enum Color{
    RED(255,0,0,"红色"),ORANGE(255,128,0,"橙色"),YELLOW(255,255,0,"黄色"),GREEN(0,255,0,"绿色"),
    CYAN(0,255,255,"青色"),BLUE(0,0,255,"蓝色"),PURPLE(128,0,255,"紫色");

    private final int red;
    private final int blue;
    private final int green;
    private final String description;

    Color(int red,int blue,int green,String description) {
        this.red = red;
        this.blue = blue;
        this.green = green;
        this.description = description;
    }

    @Override
    public String toString() {
        return name() + "(" + this.red + "," + this.blue + "," + this.green + ") ->" + this.description;
        // 或者写return super.toString() + "(" + this.red + "," + this.blue + "," + this.green + ") ->" + this.description;
    }
}
复制代码

 

posted on   gjwqz  阅读(8)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示