内部类
-
内部类就是在一个类的内部再定义一个类,比如A类中定义一个B类,那么B类相对A类来说就称为内部类(镶嵌类),而A类相对于B类来说就是外部类(宿主类)
-
内部类可以很好地实现隐藏,一般的非内部类是不允许有 private 与 protected 权限的,但内部类可以。内部类拥有外部类的所有元素的访问权限。
-
内部类的特点如下:
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的
.class
文件,但是前面冠以外部类的类名和$
符号。 - 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
- 内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的
-
内部类可以分为:实例(成员)内部类、静态内部类,局部内部类,匿名内部类
-
内部类及调用内部类的格式
public class Outer { private int id=10; public void out(){ System.out.println("这是外部类的方法!"); } public class Inner{ public void out(){ System.out.println("这是内部类的方法!"); } } public static void main(String[] args) { Outer outer = new Outer(); outer.out(); outer.new Inner().out(); } } /* 这是外部类的方法! 这是内部类的方法! */
public class Application {//外部类1 public void Inner(){ System.out.println("外部类1"); } public class Outter1 { String o1="外部类2"; public class Inner1 { String o1="外部类21"; public void Run1(){ System.out.println(this.o1); } } public class Inner2{ String o1="外部类22"; public void Run1() { System.out.println(this.o1); } } } public static void main(String[] args) { Application application = new Application(); application.Inner(); application.new Outter1().new Inner1().Run1(); application.new Outter1().new Inner2().Run1(); } } /* 外部类1 外部类21 外部类22 */
-
实例(成员)内部类:非静态内部类(没有用static修饰)
-
在外部类的静态方法和外部类以外的其他类中,必须通过外部类的实例创建内部类的实例。
-
public class Application { class Inner1{ } Inner1 inner1=new Inner1();//不需要通过外部类来实例化 //new Application().报错 class Inner2{ Inner1 inner2=new Inner1();//不需要通过外部类来实例化 //new Application().报错 public void Method1(){ Inner1 inner1 = new Inner1();//两种方式都可以 new Application().new Inner1(); } } public void Method1(){ Inner1 inner = new Inner1();//两种方式都可以 new Application().new Inner1(); } public static void Method2(String[] args) { //new Inner1();报错 new Application().new Inner1();//需要通过外部类来实例化 } }
-
在实例内部类中,可以访问外部类的所有成员。
public class Application { public int a1 = 1; static int a2 = 2; final int a3 = 3; private int a4 =4; public String Method1(){ return "非静态方法"; } public static String Method2(){ return "静态方法"; } class Inner{ int b1=a1+1; int b2=a2+1; int b3=a3+1; int b4=a4+1; String str1=Method1();//访问外部类的方法 String str2=Method2(); } public static void main(String[] args) { System.out.println(new Application().new Inner().b1); System.out.println(new Application().new Inner().b2); System.out.println(new Application().new Inner().b3); System.out.println(new Application().new Inner().b4); System.out.println(new Application().new Inner().str1); System.out.println(new Application().new Inner().str2); } }
-
在外部类中不能直接访问内部类的成员,而必须通过内部类的实例去访问。如果类 A 包含内部类 B,类 B 中包含内部类 C,则在类 A 中不能直接访问类 C,而应该通过类 B 的实例去访问类 C。
public class Application { int a1=new Inner1().b1; int a2=new Inner1().b2; int a3=new Inner1().b3; String str=new Inner1().str1; class Inner1{ int b1=new Inner2().a1; int b2=new Inner2().a2; int b3=new Inner2().a3; String str1=new Inner2().Method1(); class Inner2{ public int a1 = 1; final int a2 = 2; private int a3 =3; public String Method1(){ return "非静态方法!"; } } } public static void main(String[] args) { System.out.println(new Application().a1); System.out.println(new Application().a2); System.out.println(new Application().a3); System.out.println(new Application().str); } }
-
外部类实例与内部类实例是一对多的关系,也就是说一个内部类实例只对应一个外部类实例,而一个外部类实例则可以对应多个内部类实例。
public class Application { int a1=10; String a2="我爱你!"; class Inner1{ int a1=12; int a2=Application.this .a1; String a3="我不爱你!"; String a4=Application.this.a2; } public static void main(String[] args) { System.out.println(new Application().new Inner1().a1); System.out.println(new Application().new Inner1().a2); System.out.println(new Application().new Inner1().a3); System.out.println(new Application().new Inner1().a4); } }
-
在实例内部类中不能定义 static 成员,除非同时使用 final 和 static 修饰。
静态内部类:使用 static 修饰的内部类
-
在创建静态内部类的实例时,不需要创建外部类的实例。
public class Application { static class Inner{ } class OtherClass1{ Application.Inner i1= new Application.Inner(); } } class OtherClass2{ Application.Inner i2=new Application.Inner(); }
-
静态内部类中可以定义静态成员和实例成员。外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类的实例。
public class Application { static class Inner{ int a1=1;//实例变量 static int a2=3;//静态变量 } class OtherClass1{ public void print(){ Application.Inner b1=new Application.Inner(); int c1=b1.a1;//访问实例变量 int c2= Inner.a2;//访问静态变量 } } public static void main(String[] args) { } } class OtherClass2{ public void print(){ Application.Inner b2=new Application.Inner(); int c3=b2.a1; int c4=Application.Inner.a2; } }
-
静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问。
public class Application { int a1=1;//实例变量 static int a2=3;//静态变量 static class Inner{ Application i=new Application; int b1=i.a1;//访问实例变量 int b2=a2;//访问静态变量 }}
局部内部类:定义在方法里面的内部类
public class Application { public void run(){ class Inner{//局部内部类 public void in(){ } } }}
-
局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。
-
局部内部类只在当前方法中有效。
public class Test { Inner i = new Inner(); // 编译出错 Test.Inner ti = new Test.Inner(); // 编译出错 Test.Inner ti2 = new Test().new Inner(); // 编译出错 public void method() { class Inner{ } Inner i = new Inner(); }}
-
局部内部类中不能定义 static 成员。
-
局部内部类中还可以包含内部类,但是这些内部类也不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。
-
在局部内部类中可以访问外部类的所有成员。
-
在局部内部类中只可以访问当前方法中 final 类型的参数与变量。如果方法中的成员与外部类中的成员同名,则可以使用 .this. 的形式访问外部类中的成员。
public class Test { int a = 0; int d = 0; public void method() { int b = 0; final int c = 0; final int d = 10; class Inner { int a2 = a; // 访问外部类中的成员 // int b2 = b; // 编译出错 int c2 = c; // 访问方法中的成员 int d2 = d; // 访问方法中的成员 int d3 = Test.this.d; //访问外部类中的成员 } Inner i = new Inner(); System.out.println(i.d2); // 输出10 System.out.println(i.d3); // 输出0 } public static void main(String[] args) { Test t = new Test(); t.method(); } }
匿名内部类:没有类名的内部类,必须在创建时使用 new 语句来声明类
-
这种形式的 new 语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。使用匿名类可使代码更加简洁、紧凑,模块化程度更高。
-
匿名类有两种实现方式:
- 继承一个类,重写其方法。
- 实现一个接口(可以是多个),实现其方法。
public class Application { public static void main(String[] args){ //没有名字初始化类,不用将实例保存到变量中、 new Apple().eat(); UseService useService=new UseService(){ public void hello(){ } }; } } class Apple{ public void eat(){ Syetem.out.println("1"); } } interface UserService{ void hello(); }
-
匿名类有如下特点:
- 匿名类和局部内部类一样,可以访问外部类的所有成员。如果匿名类位于一个方法中,则匿名类只能访问方法中 final 类型的局部变量和参数。
- 匿名类中允许使用非静态代码块进行成员初始化操作。
- 匿名类中允许使用非静态代码块进行成员初始化操作。