6.3 内部类


内部类(inner class)是定义在另一个类中的类。
使用内部类的原因 :

  • 内部类可以对同一个包中的其他类隐藏。
  • 内部类方法可以访问定义在这个类的作用域中的数据,包括原本私有的数据。
    在Java中内部类的对象有一个隐式的引用,指向实例化这个类的外部对象。通过这个指针它可以访问外部类的全部状态。
    但静态内部类没有附加这个指针。

6.3.1 使用内部类访问对象状态


可以使用内部类访问外部类的字段及方法

package innerClass;  
  
  
public class Test02 {  
    private int age = 10;  
    public void h() {  
        System.out.println("haha");  
    }  
    public class Inner {  
        public void m() {  
	        // Test02.this 得到外部类的引用
            System.out.println(Test02.this.age);  
            Test02.this.h();  
        }  
    }  
    public static void main(String[] args) {  
        Test02 test02 = new Test02();  
        Inner inner = test02.new Inner();  
        inner.m();  
    }  
}

6.3.2 内部类的特殊语法规则


在内部类中使用外部类引用 : OuterClass.this

在Java中,当你创建一个外部类的对象时,内部类的对象并不会自动创建。外部类和内部类是独立的实体,它们的生命周期和创建方式是分开的。

通过外部类创建一个内部类 : new OutClass().new InnerClass()
静态内部类可以脱离外部类直接创建 : new OutClass.InnerClass()

6.3.3 内部类是否有用,必要和安全


内部类是一个编译器现象,与虚拟机无关。编译器将内部类转换为常规的类文件,用$分隔外部类名与内部类名,而虚拟机对此一无所知。

6.3.4 局部内部类


局部内部类被定义在方法的内部。
声明局部内部类时不能有访问修饰符(public或private)
局部类的作用域被限定在声明这个局部类的块中。

6.3.5 由外部方法访问变量


局部类不仅能够访问外部变量,也能访问局部变量,但那些局部变量必须是实际最终变量(effectively final)

package innerClass;  
  
public class OutClass02 {  
    public void f() {  
        String text = "hello";  
        class InnerClass02 {  
            public void m() {  
                System.out.println(text);  
            }  
        }  
        InnerClass02 class02 = new InnerClass02();  
        class02.m();  
    }  
    public static void main(String[] args) {  
        new OutClass02().f();  
    }  
}

6.3.6 匿名内部类


如果只是想创建一个类甚至不需要给这个类取名字,这种类叫匿名内部类(anonymous inner class),匿名内部类通常与接口一起使用。

由于构造器名必须和类名保持一致,但匿名内部类没有类名,所以匿名内部类没有构造器,但它当扩展一个类时还是可以调用父类的构造器。

虽然匿名内部类没有构造器,但他可以有对象初始化块

这里还有一个小技巧,用于初始化数组或列表

package anonymousInnerClass;  
  
import java.util.ArrayList;  
import java.util.Arrays;  
import java.util.List;  
  
public class Test01 {  
  
    public static void f(List<String> list) {  
        list.stream().forEach(System.out::println);  
    }  
  
    public static void main(String[] args) {  
        List<String> list = Arrays.asList("abc", "efg");  
        f(list);  
		 // 双括号初始化 (double brace initialization)
		f(new ArrayList<String>() {{  
            add("abc");  
            add("efg");
        }});  
    }  
}

在匿名内部类中获得外部类

package anonymousInnerClass;  
  
import java.util.ArrayList;  
  
public class Test02 {  
    public static void main(String[] args) {  
        System.out.println(new ArrayList() {  
        }.getClass().getEnclosingClass().getName());  
    }  
}

6.3.7 静态内部类


有时候使用内部类只是想把类隐藏在另一个类的内部,并不需要内部类有外部类的引用,此时可以将类声明成static,这样就不会产生那个引用了。

package anonymousInnerClass;  
  
import innerClass.Test02;  
  
import java.util.Arrays;  
  
public class Test03 {  
    public static class Pair {  
        private int first;  
        private int second;  
  
        public Pair(int first, int second) {  
            this.first = first;  
            this.second = second;  
        }  
  
        public int getFirst() {  
            return first;  
        }  
  
        public int getSecond() {  
            return second;  
        }  
    }  
  
    public static Pair find(int ...numbers) {  
        int max, min;  
        max = min = numbers[0];  
        for (int i = 1; i < numbers.length; i++) {  
            max = Math.max(max, numbers[i]);  
            min = Math.min(min, numbers[i]);  
        }  
        return new Pair(max, min);  
    }  
  
    public static void main(String[] args) {  
        Test03.Pair pair = find(1, 2, 4);  
        System.out.println(pair.getFirst());  
        System.out.println(pair.getSecond());  
    }  
}

只要内部类不需要访问外围对象,就应该使用静态内部类。有人也称其为嵌套类(nested class)表示静态内部类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值