Java笔记:内部类——简介

内部类本身就是类的一个属性,与其他属性定义方式一致。

1 成员内部类

定义在类内部的非静态类,就是成员内部类。成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公有。成员内部类依赖于外部类的实例,所以成员内部类不能定义静态方法和变量(final 修饰的除外)。

(1)获取成员内部类的对象?
外部类类名.内部类类名 变量 = 外部类对象的引用.new 内部类()

 OuterClass outerClass = new OuterClass();
 OuterClass.InnerClass innerClass = 
                             outerClass.new InnerClass();

或者采用:

OuterClass.InnerClass innerClass = 
                          new outerClass().new InnerClass();

new outerClass()相当于一个匿名类,即这个外部类没有名字。

(2)在实例内部类当中,不能定义static的属性或者方法
static属于类,不依赖于对象,而内部类相当于外部类的实例成员,要想对内部类进行初始化,必须依赖对象,所以这是矛盾的。 如果非要定义,那么这个属性必须是static final的,被static final 修饰的属性相当于常量,在编译期间就确定了

(3)实例内部类有没有额外的内存开销?
有,因为实例内部类,包含外部类的this引用
实例内部类至少有两个this。

实例内部类代码举例

内用外,随便访问;外用内,需要内部类对象

class OuterClass {
    public int data1 = 1;
    private int data2 = 2;
    int data3 = 3;
    public static int size = 10;

    public OuterClass() {
        System.out.println("OuterClass()");
    }
    //通过外部类方法,访问内部类
    public void outerMethod(){
        InnerClass inner = new InnerClass();
        inner.test();
    }

    class InnerClass {
        public int data4 = 4;
        //public static final int size = 10;
        public int data1 = 11;

        public InnerClass() {
            System.out.println("InnerClass()");
        }
        public void test() {
            System.out.println("data1:"+data1);
            System.out.println("data1:"+this.data1);
            //在内部类中访问外部类成员变量
            System.out.println("out::data1:"+
                    OuterClass.this.data1);
            System.out.println("InnerClass::test()");
        }
    }
}

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

        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass =
                outerClass.new InnerClass();
                
//以上两行代码可以使用匿名类替换为一行代码
//OuterClass.InnerClass outerClass =
//new OuterClass().new InnerClass();

//通过直接创建内部类对象,访问内部类
        innerClass.test();
        
//通过访问外部类方法,间接访问内部类
        outerClass.outerMethod();
    }
}

结果:
OuterClass()
InnerClass()
data1:11
data1:11
out::data1:1
InnerClass::test()
InnerClass()
data1:11
data1:11
out::data1:1
InnerClass::test()

注意:
在内部类中访问外部类的同名变量OuterClass.this.data1

2 静态内部类

定义在类内部的静态类,就是静态内部类。

public class Outer {
    private static int a = 1;
    static class StaticInner {
        public void visit() {
            System.out.println("static");
        }
    }
}
  • 静态内部类可以访问外部类所有的静态变量和方法,即使是private 的也可以。
  • 静态内部类和一般类一致,可以定义静态变量、方法,构造方法等。
  • Java集合类HashMap 内部就有一个静态内部类Entry。HashMap 内部维护Entry 数组用于存放元素,但是Entry 对使用者是透明的。像这种和外部类关系密切的,且不依赖外部类实例的,都可以使用静态内部类。

(1)如何拿到静态内部类的对象?
外部类类名.内部类类名 变量 = new 外部类名.内部类();

Outer.StaticInner staticInner  = 
                  new Outer.StaticInner();

(2)静态内部类当中,不能够访问外部类的非静态数据成员
外部类的非静态数据成员依赖于外部类对象,而静态内部类相当于外部类的一个静态成员,它是不依赖于对象的,所以在静态内部类中,不能够访问外部类的非静态数据成员。如果说,非要进行访问非静态数据成员,那么就要传入外部类对象的引用。 同理,在静态内部类中,也不包含外部类的this。

静态内部类代码实例:

class OuterClass {
    public int data1 = 1;
    private int data2 = 2;
    int data3 = 3;
    public static int data5 = 10;

    public OuterClass() {
        System.out.println("OuterClass()");
    }

    static class InnerClass {
        public int data1 = 4;
        public static  int data5 = 5;
        //outerClass记录传入外部类对象的引用
        OuterClass outerClass;

        public InnerClass() {
            System.out.println("static::InnerClass()");
        }
        //定义一个内部类的有参构造,来接收外部类的对象
        public InnerClass(OuterClass o) {
            this.outerClass = o;
            System.out.println("static::InnerClass(OuterClass o)");
        }

        public void test() {
            System.out.println("data1:" +
                    this.outerClass.data1);

            System.out.println(data1);
            //若没有传入外部类的对象引用,
            //是不能在静态内部类中调用外部类的成员变量的
            //System.out.println(data3)
            System.out.println("data5:"+data5);
            System.out.println("data5:" + OuterClass.data5);
            System.out.println("InnerClass::test()");
        }

    }
}

    public class Main{
    public static void main(String[] args) {
        //此句是为了向静态内部类中传入外部类对象创建的
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass  = new
        OuterClass.InnerClass(outerClass);
        // OuterClass.InnerClass innerClass = new
        //OuterClass.InnerClass();
        innerClass.test();
        }
        }

结果:
OuterClass()
static::InnerClass(OuterClass o)
data1:1
4
data5:5
data5:10
InnerClass::test()

3 匿名内部类
  • 本质:匿名内部类会隐式的继承一个类或者实现一个接口,或者说,匿名内部类是一个继承了该类或者实现了该接口的子类匿名对象。
  • 接口的实现类或父类的子类只需使用一次,那么即可省去该实现类或子类的定义,匿名内部类主要应用于线程中。
  • 使用匿名内部类,就不必再单独定义一个外部实现类了。

格式:

new 类名/接口/抽象类(){

}

不使用匿名内部类:

class OuterClass{
    public int data1 = 10;
    public void test() {
        System.out.println("OuterClass3::test()");
    }
}

class Inner extends OuterClass {
    public void test() {
        System.out.println("do something");
    }
}
public static void main(String[] args) {
      OuterClass inner = new OuterClass();
      inner.test();
}

如果Inner类只使用一次,那么将其编写为独立的一个类就会变得很麻烦,因此我们引入了匿名内部类。匿名内部类就是没有名字的内部类:

class OuterClass{
    public int data1 = 10;
    public void test() {
        System.out.println("OuterClass3::test()");
    }
}

public static void main(String[] args) {
    new OuterClass(){
    	//重写test方法
        public void test() {
            System.out.println("TestDemo1::test()");
        }
    }.test();//TestDemo1::test()
}

匿名内部类可以省略一个类的书写,并且,匿名内部类还能用于接口上。

最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是实现Runnable接口:

(1)Thread类的匿名内部类实现
public class Main {
    private static class A extends Thread {
        @Override
        public void run() {
            for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
             }
        }
    }

    public static void main(String[] args) {
        A a = new A();
        a.start();
    }
}

匿名内部类:

public class Demo {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        t.start();
    }
}
(2)Runnable接口的匿名内部类实现:
public class Main {
    private static class A implements Runnable {
        @Override
        public void run() {
             for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
              }
        }
    }

    public static void main(String[] args) {
        A a = new A();
       Thread t = new Thread(a);
        t.start();
    }
}

匿名内部类:

public class Demo {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        Thread t = new Thread(r);
        t.start();
    }
}

注意事项:

  • 匿名内部类不能定义任何静态成员和静态方法。
  • 只针对重写一个方法时使用,需要重写多个方法时不建议使用
4 局部内部类

定义在方法内部的类,只能在方法内部使用。

局部内部类如果希望访问所在方法的局部变量,那么这个局部变量必须是有效final的?

new出来的对象在堆内存中,直到垃圾回收才消失。局部变量和方法一起在栈内存中,方法结束后,局部变量就会消失。 为了保证new出来的对象,继续使用局部变量,故需要该局部变量是有效不变的。

局部内部类的创建方式,在对应方法内: new 内部类()

public class Outer{
	public void methodOuter{
		int num = 10;//此处必须保证是实际不变的
		//int final num = 10;
		class Inner{
			public void methodInner(){
				System.out.println(num);
			}
		}
		Inner inner = new Inner();
	}
}

定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值