原文出处:Java基础之内部类 关注码农爱刷题,看更多技术文章!!
【基本内容】
内部类就是在一个类内部再定义一个类,内部类是外部类的组成部分之一,也是外部类封装特性的体现。一般把内部类分为以下四种:成员内部类、静态内部类、局部内部类、匿名内部类。
1.成员内部类
成员内部类就是作为外部类的一个成员变量被被声明的内部类,作为外部类的成员变量,它可以被public、protected、private或默认访问修饰符修饰。成员内部类可以定义自己的成员变量和成员方法,通常不能定义静态方法和静态变量,但是加上final可以定义静态常量。
因为是外部类的一个成员变量,成员内部类依赖外部类实例生命周期而存活,外部类访问它之前需要先实例化它;它可以访问外部类的所有成员变量和方法,包括私有成员和静态方法。
其他类访问成员内部类,需要通过外部类的实例才能访问,能否访问,还取决于成员内部类的权限访问修饰符是否允许。
public class Outer {
private String parent = "I am Outer Class !";
public static String city = "I am beijing !";
//修饰符可以是 private、protected、public或缺省
private class Inner {
public String name = "Hello,I am inner class!";// 没有final修饰,通常修饰符不能带static
public void innerMethod(){// 修饰符不能带static
System.out.println(parent + city); //访问外部类成员变量
}
}
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); //注意此处的创建书写方式
inner.innerMethod();
System.out.println(inner.name);
}
}
2.静态内部类
静态内部类就是作为外部类的一个静态变量被被声明的内部类,作为外部类的静态变量,它同样可以被public、protected、private或默认访问修饰符修饰。静态内部类可以像正常类一样,定义自己的静态变量和方法、成员变量和方法。
因为静态内部类是外部类的一个静态变量,所以它无须依赖外部类实例而存活,同时它也不能访问外部类的成员变量和成员方法,但是可以访问外部类的静态变量和静态方法。
其他类访问静态内部类,只需要通过外部类类名就能访问;如果要访问静态内部类的成员变量和方法,则需要先实例化静态内部类。
public class Outer {
private String parent = "I am Outer Class !";
public static String city = "I am beijing !";
//修饰符可以是 private、protected、public或缺省
public static class Inner {
public static String nickname = "I am static inner class!";
public String name = "Hello,I am inner class!";
public void innerMethod(){//
System.out.println( city); //访问外部类静态变量,不能访问外部类的成员变量
}
public static void staticMethod(){
}
}
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner(); //注意此处和成员内部类的区别
inner.innerMethod();//调用静态内部类的实例方法
System.out.println(inner.name); //调用静态内部类的实例变量
Outer.Inner.staticMethod(); //通过类名调用静态内部类的静态方法
System.out.println(Outer.Inner.nickname); //通过类名调用静态内部类的静态变量
}
}
3.局部内部类
局部内部类就是在外部类的方法中或代码块中声明的内部类,作为外部类方法或代码块中的局部变量,不能被外部访问,不能被public、protected、private或默认访问修饰符修饰。局部内部类可以定义自己的成员变量和方法,但是不能定义静态方法和静态变量,也不能包含静态代码块,不过加上final则可以定义静态常量。
局部内部类如果定义在外部类的成员方法和初始化代码块中,则可以访问外部类所有方法和变量;但是如果被定义在外部类的静态方法和静态代码块中,则只能访问外部类的静态变量和静态方法。局部内部类如果访问方法或代码块中的局部变量,则需要局部变量加上final修饰或确保该局部变量初始化后不会再被修改。
public class Outer {
private String name = "I am Outer Class !";
public static String area = "I am beijing !";
public void outerMethod(){
final String localName = "local";
class localClass {
public void out(){
System.out.println(name + area );//可以访问外部类所有变量和方法
System.out.println(localName ); //可以访问局部变量final
}
}
}
static {
class localClass {
public void out(){
System.out.println( area);//定义在外部类静态块或静态方法中只可以访问外部类静态变量和方法
}
}
}
}
4.匿名内部类
匿名内部类同局部内部类很相似,一样是在外部类的方法中或代码块中声明的内部类,同样不能被外部访问,不能被public、protected、private或默认访问修饰符修饰,不能定义静态变量和静态方法。但是又有它的特殊之处,如下图表:
至于对外部类和局部变量的访问权限,则和局部内部类一样。
// interface file
public interface Record{
public void record();
}
// abstract class file
public abstract Runner{
public void run();
}
// outer class file
public class Outer {
private String name = "I am Outer Class !";
public static String area = "I am beijing !";
public void outerMethod(){
final String localName = "local";
Record record= new Record(){ // implement interface
@override
public void record(){
System.out.println("record:" + area + name );//可以访问外部类所有变量和方法
System.out.println("record:" + localName ); //可以访问局部变量final
}
};
record.record();
}
static {
Runner runner = new Runner() { // extend class
public void run(){
System.out.println( "run:" + area);//定义在外部类静态块或静态方法中只可以访问外部类静态变量和方法
}
}
runner.run();
}
// param pass
private void testRunner(Runner runner){
runner.run();
}
public void test(){
this.testRunner(new Runner(){
public void run(){
System.out.println( "run:" + name);
}
});
}
}
【注意事项】
1.常量定义带来的困惑:在非静态内部类中都提到不能定义静态变量和静态方法,因为JDK从设计上已经提供了静态内部类来满足开发者这种需求,而非静态内部类作为外部类的成员或局部变量,不允许定义类层面的静态变量和方法,理解起来也没有问题,但是JDK又开了一个小后门,允许加上final关键字后可以定义static变量,这让人有些困惑,但是后来细想,把final static作为常量定义的方式,而不是类变量的定义,这样理解起来就通畅了。
2.内外部类同名方法或变量的处理:在Java中,内部类可以访问外部类的同名方法,但需要通过外部类的引用进行访问。如果内部类中没有与外部类同名的变量或方法,可以直接引用外部类的变量或方法。但如果存在同名的变量或方法,就需要在内部类中先取得外部类的引用,通过这个引用来访问外部类的同名变量或方法。有两种方法可以取得外部类的引用:一种是通过外部类的类名来取得外部类当前的引用,即使用OuterClass.this.methodName()格式调用,其中OuterClass与methodName换成实际外部类名及其方法名;this为关键字,表示对外部类的引用。另一种是将外部类的引用显式传递给内部类的构造方法。
public class Outer {
private String name= "I am Outer Class !";
//修饰符可以是 private、protected、public或缺省
private class Inner {
public String name = "Hello,I am inner class!";
public void innerMethod(){
System.out.println(Outer.this.name); //访问外部类同名成员变量
}
}
}
原文出处:Java基础之内部类 关注码农爱刷题,看更多技术文章!!