Java内部类学习笔记

这是我学习Java内部类的笔记

1.为什么使用内部类?
使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,
对于内部类都没有影响
1.1.使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,使用内部类还能够为我们带来如下特性:
(1)、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独。
(2)、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
(3)、创建内部类对象的时刻并不依赖于外围类对象的创建。
(4)、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
(5)、内部类提供了更好的封装,除了该外围类,其他类都不能访问。
2.内部类分类:
(一).成员内部类:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public class Outer{

        private int age = 99;

        String name = "Coco";

        public class Inner{

            String name = "Jayden";

            public void show(){

                System.out.println(Outer.this.name);

                System.out.println(name);

                System.out.println(age);

            }

        }

        public Inner getInnerClass(){

            return new Inner();

        }

        public static void main(String[] args){

            Outer o = new Outer();

            Inner in = o.new Inner();

            in.show();

        }

    }

1.Inner 类定义在 Outer 类的内部,相当于 Outer 类的一个成员变量的位置,Inner 类可以使用任意访问控制符,
如 public 、 protected 、 private 等
2.Inner 类中定义的 show() 方法可以直接访问 Outer 类中的数据,而不受访问控制符的影响,
如直接访问 Outer 类中的私有属性age
3.定义了成员内部类后,必须使用外部类对象来创建内部类对象,而不能直接去 new 一个内部类对象,
即:内部类 对象名 = 外部类对象.new 内部类( );
4.编译上面的程序后,会发现产生了两个 .class 文件: Outer.class,Outer$Inner.class{}
5.成员内部类中不能存在任何 static 的变量和方法,可以定义常量:
(1).因为非静态内部类是要依赖于外部类的实例,而静态变量和方法是不依赖于对象的,仅与类相关,
简而言之:在加载静态域时,根本没有外部类,所在在非静态内部类中不能定义静态域或方法,编译不通过;
非静态内部类的作用域是实例级别
(2).常量是在编译器就确定的,放到所谓的常量池了
★★友情提示:
1.外部类是不能直接使用内部类的成员和方法的,可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法;
2.如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,
可以使用 this 关键字,如:Outer.this.name
(二).静态内部类: 是 static 修饰的内部类,
1.静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问 
2.如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;
如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员
3.创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名 = new 内部类();


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public class Outer{

            private int age = 99;

            static String name = "Coco";

            public static class Inner{

                String name = "Jayden";

                public void show(){

                    System.out.println(Outer.name);

                    System.out.println(name);                  

                }

            }

            public static void main(String[] args){

                Inner i = new Inner();

                i.show();

            }

        }

(三).方法内部类:访问仅限于方法内或者该作用域内 
(1).局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的
(2).只能访问方法中定义的 final 类型的局部变量,因为:
当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在,
直到没有被引用时才会消亡。此时就会出现一种情况,就是内部类要访问一个不存在的局部变量;
==>使用final修饰符不仅会保持对象的引用不会改变,而且编译器还会持续维护这个对象在回调方法中的生命周期.
局部内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,
自己内部的方法调用的实际是自己的属性而不是外部类方法的参数;
防止被篡改数据,而导致内部类得到的值不一致


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

   /*

        使用的形参为何要为 final???

         在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,

         也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,

         毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变这是难以理解

         和不可接受的,所以为了保持参数的一致性,就规定使用 final 来避免形参的不改变

         */

        public class Outer{

            public void Show(){

                final int a = 25;

                int b = 13;

                class Inner{

                    int c = 2;

                    public void print(){

                        System.out.println("访问外部类:" + a);

                        System.out.println("访问内部类:" + c);

                    }

                }

                Inner i = new Inner();

                i.print();

            }

            public static void main(String[] args){

                Outer o = new Outer();

                o.show();

            }

        }    

(四).匿名内部类:
(1).匿名内部类是直接使用 new 来生成一个对象的引用;
(2).对于匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,
该类的定义会立即消失,所以匿名内部类是不能够被重复使用;
(3).使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口;
(4).匿名内部类中是不能定义构造函数的,匿名内部类中不能存在任何的静态成员变量和静态方法;
(5).匿名内部类中不能存在任何的静态成员变量和静态方法,匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法
(6).匿名内部类初始化:使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

  public class OuterClass {

            public InnerClass getInnerClass(final int   num,String str2){

                return new InnerClass(){

                    int number = num + 3;

                    public int getNumber(){

                        return number;

                    }

                };        /* 注意:分号不能省 */

            }

            public static void main(String[] args) {

                OuterClass out = new OuterClass();

                InnerClass inner = out.getInnerClass(2"chenssy");

                System.out.println(inner.getNumber());

            }

        }

        interface InnerClass {

            int getNumber();

        }         

 

时间: 2024-10-12 15:45:31

Java内部类学习笔记的相关文章

内部类学习笔记(三)匿名内部类

这篇不转载了,自己来写,因为匿名内部类是内部类系列里我认为最难理解的. A.继承式的匿名内部类. 引用转载代码: 结果输出了:Driving another car! Car引用变量不是引用Car对象,而是Car匿名子类的对象. 建立匿名内部类的关键点是重写父类的一个或多个方法.再强调一下,是重写父类的方法,而不是创建新的方法.因为用父类的引用不可能调用父类本身没有的方法!创建新的方法是多余的.简言之,参考多态. 这里可能大家看的比较迷糊,尤其是 Car car = new Car(){ pub

java nio学习笔记(一)

位置保留,待用 java nio学习笔记(一),布布扣,bubuko.com

JAVA基础学习笔记(2)

看了几天的视频了,都没时间来写下学习笔记,今天来写下第二次的学习笔记,前几天看的给忘记了,就写最新看到的吧 主要内容:1.类的变量与函数(方法) 2.对象的存储方式 3.新建一个对象及对象的赋值与调用 4.空对象 5.匿名对象 1.类的变量与函数(方法) class Dog      //类名 { String name;  //变量的声明 int age; String color; void bark()   //方法的定义(返回值为空,不带参数) { System.out.println(

java排序学习笔记

前面写了js的排序实现,总得玩玩java的哈. 同样,冒泡.选择.快速(这三个之前实现过也写过文章).堆排序,然后做比较. 主要遇到的难点: - -||想轻松点写个封装计时的逻辑,不想每调用一个排序就要写一个计时代码.想想,还是javascript写起来方便: java的话,我想到的方法是写一个抽象类:抽象出排序方法,实现一个排序计时方法(该方法调用了抽象排序,但在先后排序时加入计时代码[感觉像是aop操作]): 接着所有排序类都继承这个抽象类,并实现排序方法,调用的时候直接调用继承的排序计时方

《深入Java虚拟机学习笔记》- 第4章 网络移动性

Java虚拟机学习笔记(四)网络移动性 <深入Java虚拟机学习笔记>- 第4章 网络移动性,布布扣,bubuko.com

《深入Java虚拟机学习笔记》- 第7章 类型的生命周期

一.类型生命周期的开始 如图所示 初始化时机 所有Java虚拟机实现必须在每个类或接口首次主动使用时初始化: 以下几种情形符合主动使用的要求: 当创建某个类的新实例时(或者通过在字节码中执行new指令,或者通过不明确的创建.反射.克隆和反序列化): 当调用某个类的静态方法时(即在字节码中执行invokestatic指令): 当使用某个类或接口的静态字段,或者对该字段赋值时(用final修饰的静态字段除外,它被初始化为一个编译时常量表达式): 当调用Java API中的某些反射方法: 当初始化某个

《深入Java虚拟机学习笔记》- 第13章 逻辑运算

<深入Java虚拟机学习笔记>- 第13章 浮点运算 <深入Java虚拟机学习笔记>- 第13章 逻辑运算,布布扣,bubuko.com

《深入Java虚拟机学习笔记》- 第12章 整数运算

Java虚拟机提供几种进行整数算术运算的操作码,他们执行基于int和long类型的运算.当byte.short和char类型值参与算术运算时,首先会将它们转换为int类型.这些操作码都不会抛出异常,溢出在这里通常可以被忽略. 整数加法 操作码 操作数 说明 iadd (无) 从栈中弹出两个int类型数,相加,然后将所得int类型结果压回栈 ladd (无) 从栈中弹出两个long类型数,相加,然后将所得long类型结果压回栈 将一个常量与局部变量相加 操作码 操作数 说明 iinc vindex

《深入Java虚拟机学习笔记》- 第2章 平台无关

Java虚拟机学习笔记(二)平台无关 <深入Java虚拟机学习笔记>- 第2章 平台无关,布布扣,bubuko.com