Java内部类

学Java,内部类,累不累?(冷笑话)

目录

一、内部类的理解

二、四种内部类

①成员内部类

1)定义方式

2)成员内部类访问外部成员

3)成员内部类实例化对象

②局部内部类

③静态内部类

④匿名内部类(重难)

1)理解

2)匿名内部类的形式

3)匿名内部类的使用


一、内部类的理解

什么是内部类?我们对普通的类已经很理解了,比如人类(person)、动物类(animal)、书类(book),突然发现这些类似乎都比较广泛,或者说更贴近一个大的整体。如果一个整体的内部结构很复杂,比方说人类(person),你光说这个人叫什么名(name),今年几岁(age),是男是女(gender)……似乎都只是很概括性地描述人这个类,如果要把人类更细致的结构描述出来,作为人类你有五官、有五脏六腑、有骨骼、肌肉,不难发现,前面举例的这些“零件”似乎也能单独视作一个类,(比如)眼睛类->单双眼皮、眸色……

因此,为了更细致地描述一个大的类,可以用内部类去描述这个大类中可以单独“拆分”出来的“零件”,这样既贴切我们的认知,又方便代码的维护

二、四种内部类

分别是:成员内部类、局部内部类、静态内部类、匿名内部类

①成员内部类

1)定义方式

在一个类中,我们已经熟知的,可以定义:成员变量、成员方法;

如果在Outer类中定义一个Inner类,则称Inner是Outer的一个内部类相对的,可以称Outer是Inner的外部类

代码示例:

class Person {
    String name;
    int age;

    class Eye {
        String eyelid;//单双眼皮
        String Color;//眸色

    }
}

在这个示例中,Peron类拥有两个成员属性和一个成员内部类,name和age分别用来描述姓名和年龄,eyelid和Color分别用来描述单双眼皮和眸色,当然你完全可以把这两个属性直接作为Person类的成员属性,但如果采用内部类的形式书写->既贴切我们的认知,又方便代码的维护

2)成员内部类访问外部成员

成员内部类作为外部类的一个成员,自然是可以访问外部类的属性的,代码示例:

class Person {
    String name = "张三";
    int age = 18;

    class Eye {
        String eyelid;//单双眼皮
        String Color;//眸色

        void print() {//定义一个print函数,作为Eye这个内部类的成员方法
            System.out.println(name + "今年" + age + "岁");
            //访问外部类的name和age两个属性
        }

    }
}

3)成员内部类实例化对象

用成员内部类实例化对象的公式如下:

外部类名.内部类名 变量名 = new 外部类名().new 内部类名();

解释:

等号左边,用外部类名.的形式访问到内部类名;

等号右边,理解为->先用new 外部类名()实例化了一个外部类对象,然后用这个外部类对象.的形式访问到内部类名,此时再用这个内部类名去new一个内部类对象

代码示例;

public class Main {
    public static void main(String[] args) {
        //外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
        Person.Eye e1 = new Person().new Eye();
        e1.print();
    }
}

class Person {
    String name = "张三";
    int age = 18;

    class Eye {
        String eyelid;//单双眼皮
        String Color;//眸色

        void print() {//定义一个print函数,作为Eye这个内部类的成员方法
            System.out.println(name + "今年" + age + "岁");
        }
    }
}

②局部内部类

局部内部类的定义和使用——

局部内部类,也叫作方法内部类;

在一个类的成员方法中定义一个内部类,这个类就属于局部内部类,因为它的作用范围(生命周期)只局限在这个类中;

在局部内部类中,局部内部类可以访问外部类的所有成员变量和方法,而局部内部类中变量和方法却只能在所属方法中访问;

public class Main {
    public static void main(String[] args) {
        #用Person实例化对象并调用它的成员方法func
        Person p = new Person();
        p.func();
    }
}

class Person {
    String name = "张三";
    int age = 18;

    void func() {
        class Eye {
            String eyelid;//单双眼皮
            String Color;//眸色

            void print() {//定义一个print函数,作为Eye这个内部类的成员方法
                System.out.println(name + "今年" + age + "岁");
            }
        }
        //局部内部类,只能在func里访问,因此在此处实例化内部类Eye对象e并调用print方法
        Eye e = new Eye();
        e.print();
    }
}

上述代码中,定义了一个Person类,在Person类中定义了一个成员方法func,在func方法中定义了一个内部类Eye,故称Eye是Person类的局部内部类,其中——

Eye类可以访问外部类Person的所有成员,但Eye这个局部内部类的属性和方法只能在func这个方法里面访问!

③静态内部类

1)静态内部类的特点

在形式上,就只是在成员内部类的基础上加以static关键字修饰

在功能上,

㈠静态内部类只能访问外部类的静态成员;

㈡访问静态内部类的成员时,可以跳过它的外部类

2)静态内部类实例化对象

用静态内部类实例化对象的公式如下:

外部类名.内部类名 变量名 = new 外部类名.内部类名();

解释:

等号左边和成员内部类是一样的,不再赘述

等号右边,我们知道类的静态成员是可以通过类名直接访问的,因此直接用外部类名.的形式可以访问到静态内部类,然后用这个静态内部类去new一个静态内部类对象

示例用来理解以上两点:

public class Main {
    public static void main(String[] args) {
        //外部类名.内部类名 变量名 = new 外部类名.内部类名();
        Person.Eye e = new Person.Eye();
        e.print();
    }
}

class Person {
    static String name = "张三";
    int age = 18;

    static class Eye {
        String eyelid;//单双眼皮
        String Color;//眸色

        void print() {
            System.out.println("姓名是" + name);//name是外部类的静态成员,可以正常访问
            //System.out.println("年龄是" + age);错误语法!静态内部类只能访问外部类的静态成员
        }
    }
}

④匿名内部类(重难)

1)理解

所谓匿名,就是没有名字,匿名内部类,就是没有名字的内部类;

我们经常会遇到一个对象只用一次的情况,这种情况下如果用匿名内部类,就可以不必创建新的子类去继承(extends)或实现(implements),然后才能用子类去实例化对象

我个人的理解:直接把匿名类对象看作是一个具体的变量(已经被实例化好的具体对象)

2)匿名内部类的形式

匿名内部类有两种定义形式,㈠继承父类;㈡实现接口

代码示例:

interface Mouth {
    String test2 = "这是嘴类,我把它作为一个接口";

    void Mouth_print();
}

abstract class Eye {
    String test1 = "这是眼睛类,我把它作为一个父类";

    abstract void Eye_show();
}

public class Main {
    public static void main(String[] args) {
        new Eye() {//继承父类的匿名内部类
            @Override
            void Eye_show() {
                System.out.println("调用Eye父类的test成员属性:" + test1);
            }
        };

        new Mouth() {
            @Override
            public void Mouth_print() {
                System.out.println("调用Mouth接口的test成员属性" + test2);
            }
        };
    }
}

补充内容(进阶操作,可不看):

㈠找到字节码文件(.class)

㈡在当前目录打开命令行窗口(cmd)

㈢对两个字节码文件分别进行反编译

㈣得到反编译结果

分析:显然Eye是我们定义的父类,而Mouth是定义的接口,因此内部类1隐藏的是extends关键字,内部类2隐藏的是implements关键字

3)匿名内部类的使用

对于一个匿名内部类,可以直接把它视作成一个实例化的对象,因此可以完成以下操作——

㈠直接访问成员

㈡作为参数,传参给其它方法

㈣测试的完整代码:

interface Mouth {
    String test2 = "这是嘴类,我把它作为一个接口";

    void Mouth_print();
}

abstract class Eye {
    String test1 = "这是眼睛类,我把它作为一个父类";

    abstract void Eye_show();
}

public class Main {
    public static void main(String[] args) {

        test_func(

                new Eye() {//继承父类的匿名内部类
                    @Override
                    void Eye_show() {
                        System.out.println("调用Eye父类的test成员属性:" + test1);
                    }
                },//这里要注意,既然把这个匿名内部类看作一个具体对象,那么函数传多个参数的时候,显然应该用逗号隔开


                new Mouth() {
                    @Override
                    public void Mouth_print() {
                        System.out.println("调用Mouth接口的test成员属性" + test2);
                    }
                }

        );

    }

    static void test_func(Eye e, Mouth m) {//参数列表和传参一定要注意一一对应
        e.Eye_show();
        m.Mouth_print();
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值