Java笔记之面向对象 下(十四)

一.内部类☆

1.基本介绍

一个类的内部完整的嵌套了另一个类结构,则被嵌套的类称为内部类,而嵌套内部类的类称为外部类

类的五大成员:属性、方法、构造器、代码块、内部类

内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类直接的关系

语法格式
class 类名{ //外部类
 class 类名{ //内部类
 }
}

内部类的分类

  1. 定义在外部类局部位置上(如:方法内部)
    ①局部内部类(有类名
    ②匿名内部类(没有类名)☆
  2. 定义在外部类的成员位置上
    ①成员内部类(没有static修饰
    ②静态内部类(有static修饰
class A{
    class B{ }  //成员内部类
    static class C{ }  //静态内部类

    public void test(){
        class D{ }  //局部内部类
        new p1(){};    //匿名内部类(类)
        new p2(){};    //匿名内部类(接口)
    }
}

class p1{}	
interface p2{}

2.局部内部类

局部内部类是定义在外部类的局部位置,比如方法、代码块,且有类名

语法格式

class 外部类名{
 public void 方法名(){
  class 内部类名{ }
 }
}

使用细节

  1. 可以直接访问外部类的所有成员包括私有
  2. 不能添加访问修饰符,因为它是一个局部变量,局部变量是不能使用修饰符的,但可以使用final
  3. 内部类的作用域仅仅只在它所在的方法中或代码块中
  4. 外部类访问内部类成员,直接创建外部类对象,调用内部类所在的方法或代码块
  5. 局部内部类只能被方法内部访问(因为局部内部类的本质是一个局部变量)
  6. 如果外部类和局部内部类的成员(属性或方法等)重名时,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)去访问
public class test1 {
    public static void main(String[] args) {
        //细节四
        A a = new A();
        a.test2();  //方法test2中的内部类a的值=20

        //细节五
//        new B();    //其他类不能访问局部内部类

        //细节六
        a.test3();
    }
}

class A{
    private int a = 1;
    private void p(){
        System.out.println("外部类的方法");
    }

    public void test(){
        class B{
            //细节一
            public void s(){
                System.out.println(a);
                p();
            }
        }

        //细节二
//        public class B1{}   //错误
        final class B1{}    //正确
    }

    //细节三
    public void test1(){
        class B2{ }
        B2 b2 = new B2();   //正确
    }
//    B2 b2 = new B2();   //错误

    //细节四
    public void test2(){
        class B3{ int b = 20; }
        B3 b2 = new B3();   //正确
        System.out.println("方法test2中的内部类a的值="+b2.b);
    }

    //细节五
//    new B();  //错误

    //细节六
    public void test3(){
        class B4{
            int a = 10;  //与外部类属性重名,遵守就近原则
            public void f(){
                System.out.println("内部类属性a="+a); //10
                //如果想在内部类访问外部类的属性则 外部类名.this.属性名
                System.out.println("外部类属性a="+A.this.a);
            }
        }

        B4 b4 = new B4();
        b4.f();
    }
}

3.匿名内部类☆☆☆

匿名内部类本质是内部类,该类没有名字,同时还是一个对象(在源码中和一些框架中经常用到)

说明:匿名内部类是定义在外部类的局部位置 如:方法中

语法格式
class 类名{ //外部类
 public void 方法名(){
  new 类或接口(参数列表){ } //匿名内部类
 }
}

使用场景

有时候有的内部类只需要创建一个它的对象就可以了,以后再不会用到这个类,这时候使用匿名内部类就比较合适,而且也免去了给它取名字的烦恼

也就是说当某一个对象只想使用一次时可以用匿名内部类,可以简化开发

快速入门

getClass()获取对象的运行类型

public class test1 {
    public static void main(String[] args) {
        demo demo = new demo();
        demo.p();
        //test...
        //Anonymous的匿名内部类的运行类型=class com.test.demo$1
        //name=张三
        //Anonymous1的匿名内部类的运行类型=class com.test.demo$2
    }
}

class demo{
    public void p(){
        //把这个匿名内部类赋值给A接口类型Anonymous
        //匿名内部类在赋值给你Anonymous以后,这个匿名内部类就不存在了,不能用了,因为只能使用一次
        /*
        分析:
        1.Anonymous的编译类型=A
        2.Anonymous的运行类型=demo$1
        3.其实底层代码就会创建匿名内部类
        class demo$1 extends A{
            @Override
            public void test() {
                System.out.println("test...");
            }
        }
         */
        A Anonymous = new A() {
            @Override
            public void test() {
                System.out.println("test...");
            }
        };
        Anonymous.test();   //调用匿名内部类的方法
        System.out.println("Anonymous的匿名内部类的运行类型="+Anonymous.getClass());

        /*
        分析:
        1.Anonymous1的编译类型=B
        2.Anonymous1的运行类型=demo$2
        3.其实底层代码就会创建匿名内部类
        class demo$2 extends B{ }
        4.参数列表会传给 构造器
         */
        B Anonymous1 = new B("张三"){
        };
        System.out.println("Anonymous1的匿名内部类的运行类型="+Anonymous1.getClass()); //getClass()获取对象的运行类型

    }
}

interface A{
    void test();
}

class B{
    String name;
    public B(String name) {
        System.out.println("name="+name);
    }
    public void test(){ };
}

使用细节

  1. 匿名内部类既是一个类的定义,也是一个对象,所以它既有定义类的特征,也有创建对象的特征
  2. 可以直接访问外部类的所有成员,包括私有
  3. 不能添加访问修饰符,因为它是一个局部变量
  4. 作用域只能在定义它的方法或代码块中
  5. 外部其他类不能访问匿名内部类成员,因为他是一个局部变量
  6. 如果外部类和匿名内部类的成员(属性或方法等)重名时,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)去访问
public class test1 {
    public static void main(String[] args) {
        demo demo = new demo();
        demo.p();
        System.out.println("============");
        demo.p1();

    }
}

class demo{
    private int a = 1;
    private void demo1(){
        System.out.println("外部类的方法!");
    }

    public void p1(){
        //细节2
        A b = new A() {
            @Override
            public void test() {
                System.out.println("外部类属性a=" + a);  //外部类属性
                demo1();    //外部类方法
            }
        };
        b.test();
    }

    public void p(){
        //细节1,当匿名内部类是一个类的定义
        A a = new A() {
            @Override
            public void test() {
                System.out.println("匿名内部类是一个类的定义的test方法!");
            }
        };
        a.test();   //动态绑定,运行类型则是demo$1
        //细节1,当匿名内部类是一个对象
        new A() {
            @Override
            public void test() {
                System.out.println("匿名内部类是一个对象的test方法!");
            }
        }.test();   //也可以直接调用,匿名内部类本身也是返回对象


        //细节6,如果匿名内部类属性与外部类属性重名时
        new A() {
            int a = 20;
            @Override
            public void test() {
                System.out.println("匿名内部类属性a="+a);  //就近原则 a=20
                System.out.println("外部类属性a="+demo.this.a);  //a=1
            }
        }.test();
    }
}

class A{
    public void test(){
        System.out.println("A类的test方法!");
    };
}

最佳实践

把匿名内部类当作实参直接传递,简洁高效

public class test1 {
    public static void main(String[] args) {
        //匿名内部类的方式,
        Person person = new Person();
        person.exercise(new motion() {
            @Override
            public void method() {
                System.out.println("匿名内部类:跑步中...");
            }
        });
        person.exercise(new motion() {
            @Override
            public void method() {
                System.out.println("匿名内部类:跳绳中...");
            }
        });


        //普通方法-硬代码的方式
        Person1 person1 = new Person1();
        person1.method();
        Person2 person2 = new Person2();
        person2.method();


    }
}

interface motion{
    void method();
}
class Person{
    public void exercise(motion motion){    //接口类型
        motion.method();
    }
}

class Person1 implements motion{
    @Override
    public void method() {
        System.out.println("普通方法:跑步中!!!");
    }
}

class Person2 implements motion{
    @Override
    public void method() {
        System.out.println("普通方法:跳绳中!!!");
    }
}

4.成员内部类

语法格式
class 外部类名{
 class 成员类名{
 }
}

使用细节

  1. 可以直接访问外部类成员,包括私有的
  2. 可以添加访问修饰符(public、protected、默认、private),因为它就是外部类的一个成员
  3. 作用域跟外部类的其它成员一样,为整个类体
  4. 外部类访问成员内部类 访问方式:先创建对象,再访问
  5. 如果外部类和成员内部类的成员(属性或方法等)重名时,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)去访问
public class test1 {
    public static void main(String[] args) {
        A a = new A();
        a.test();
    }
}
class A{
    private int a = 1;

    //细节二
    public class B{
        int a = 20;
        //细节一
        public void say(){
            System.out.println("a="+a);
            //细节五
            System.out.println("成员内部类a="+a);
            System.out.println("外部类成员a="+A.this.a);
        }

    }

    public void test(){
        //细节四 使用成员内部类
        B b = new B();
        b.say();
    };
}

5.静态内部类

语法格式
class 外部类名{
 static class 成员类名{
 }
}

使用细节

  1. 可以直接访问外部类的所有静态成员,包含私有的(注意:不能访问非静态成员)
  2. 可以添加访问修饰符(public、protected、默认、private),因为它就是外部类的一个成员
  3. 作用域跟外部类的其它成员一样,为整个类体
  4. 外部其他类使用静态内部类,可以通过类名直接访问,前提满足访问权限
  5. 外部类访问静态内部类访问方式:
    方法一:先创建对象,再访问
    方法二:编写一个方法返回静态内部类的对象实例,再访问
    方法三:编写一个静态方法返回静态内部类的对象实例,再访问
  6. 如果外部类和静态内部类的成员(属性或方法等)重名时,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.成员)去访问
public class test1 {
    public static void main(String[] args) {
        //细节四 方法一
        System.out.println("细节四 方法一");
        A.B b = new A.B();
        b.say();

        //细节四 方法二
        System.out.println("细节四 方法二");
        A a = new A();
        A.B b1 = a.getB();
        b1.say();

        //细节四 方法三
        System.out.println("细节四 方法三");
        A.B b11 = A.getB1();
        b11.say();
    }
}
class A{
    private int a = 1;
    private static int b = 1;

    //细节二
    public static class B{
        int b = 20;

        //细节一
        public void say(){
//            System.out.println(a);//错误,必须是静态成员
            System.out.println("成员静态属性b="+b);

            //细节五
            System.out.println("静态内部类b="+b);
            System.out.println("外部类成员b="+A.b);
        }
    }

    //细节四 方法一
    public void test(){
        B b = new B();
        b.say();
    };
    //细节四 方法二
    public B getB(){
        return new B();
    }

    //细节四 方法三
    public static B getB1(){
        return new B();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王博1999

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

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

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

打赏作者

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

抵扣说明:

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

余额充值