一、外部类
只能用public、default修饰的类,外部顶级类的类名需和文件名相同,且一个文件中只能有一个public类。
如存在文件A.java
public class A{//顶级外部类
//methods。。。
}
public class B{}//编译报错
class C{}//外部类
二、内部类
内部类,即嵌套类(Nested Classes)。嵌套类包括静态内部类(Static Nested Classes)和内部类(Inner Classes)。而内部类分为成员内部类,局部内部类(Local Classes)和匿名内部类(Anonymous Classes)。
内部类是一个编译是的概念,一旦编译成功,就会成为完全不同的两个类,分别为Outer.class和Outer$Inner.class类。所以内部类的成员变量/方法名可以和外部类的相同。
内部类实现多重继承 (让多个内部类分别继承多个其他类,使外部类可以同时获取多个其他类的属性)。
1、静态内部类
static 修饰的内部类。
1)静态内部类可以使用public、protected、private、static修饰符修饰
2)静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问
3)如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员
4)创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名 = new 内部类();
public class Outer{
private int age = 1;
static String name = "A";
public static class Inner{
String name = "B";//外部类的静态成员与内部类的成员名称可以相同
public void show(){
System.out.println(Outer.name); //通过“类名.静态成员”访问外部类的静态成员
System.out.println(name);
}
}
public static void main(String[] args){
Inner i = new Inner(); //创建静态内部类的对象时,不需要外部类的对象
i.show();
}
}
2、非静态内部类
非静态内部类能访问外部类的一切成员, 包括私有成员。外部类虽然不能直接访问内部类的成员, 但是可以通过内部类的实例访问内部类的私有成员。
(1)成员内部类
定义在外部类里的非static类。
1)成员内部类可以使用可以使用任意访问控制符 ,如public 、 protected 、 private 等
2)成员内部类可以直接使用外部类的所有成员和方法,即使是private修饰的。而外部类要访问内部类的所有成员变量和方法,则需要通过内部类的对象来获取。(可理解为你父母(外部类)的所有东西你(内部类)可以随意使用,而父母想要使用你的东西必须经过你的同意。)
3)成员内部类不能含有static的变量和方法。因为成员内部类需要先创建了外部类,才能创建它自己的。
4)成员内部类可以有常量
原因:①在加载静态域时,根本没有外部类,所在在非静态内部类中不能定义静态域或方法,编译不通过;非静态内部类的作用域是实例级别②常量是在编译期就确定的,放在常量池
public class Outer {
private int age = 1;
String name = "A";
public class Inner {
String name = "B";
public void show() {
System.out.println(Outer.this.name);//访问外部类的同名成员要使用this关键字
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();
}
}
(2)局部内部类
定义在方法中的内部类,只能在该方法的作用域中使用,与局部变量类似。
1)和局部变量一样,不能有 public、protected、private 以及 static 修饰符
2)在jdk1.8之前,只能访问方法中定义的 final 类型的局部变量
原因:当方法被调用运行完毕之后,局部变量失效。但内部类对象可能还存在,直到没有被引用时才会失效。此时内部类要访问一个不存在的局部变量,是不允许的;对于final变量,Java中采用copy local variable的实现,将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);//局部内部类可以访问方法中的final变量
System.out.println("访问内部类:" + c);
}
}
Inner i = new Inner();
i.print();
}
public static void main(String[] args){
Outer o = new Outer();
o.Show();
}
}
注意:在JDK8版本之中,方法内部类中调用方法中的局部变量,可以不需要修饰为 final,匿名内部类也是一样的,主要是JDK8之后增加了 Effectively final 功能 反编译jdk8编译之后的class文件,发现内部类引用外部的局部变量都是 final 修饰的 (在网上看到别的牛人分析的)
(3)匿名内部类
是直接使用 new 来生成一个对象的引用,常用于GUI事件处理。
1)仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,不能够被重复使用;
2)匿名内部类必须是继承一个类或实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口,必须要实现继承的类或者实现的接口的所有抽象方法
3)匿名内部类中不能定义构造函数,不能存在任何的静态成员变量和静态方法
4)使用构造代码块初始化匿名内部类
public class Outer {
public Inner getInner(int num) {//匿名内部类构造代码块
return new Inner() {//匿名内部类
int number = num + 3;
public int getNumber() {
return number;
}
}; /* 注意:分号不能省略 */
}
public static void main(String[] args) {
Outer out = new Outer();
Inner inner = out.getInner(2);
System.out.println(inner.getNumber());
}
}
interface Inner {//实现的接口
int getNumber();
}


网友评论