内部类:定义在类内部的类。
分类:成员内部类(静态or非静态的)、局部内部类、匿名内部类;
为什么使用内部类?
- 内部类可以直接调用外围类的变量,而且一个类中可以包含多个内部类,实现多继承;
- 可以限制其他类访问内部类,使得内部类的细节对于其他类是隐藏的;
- 节省代码量;(匿名内部类)
1.成员内部类:作为类的成员而存在。
如下例子所示,MyInnerClass 是定义在OuterClass1的内部,以成员形式存在的。
内部类调用变量的方式:
可以调用外围类的成员变量,可以通过外围类.this.变量名直接调用(例中为OuterClass1.this.a);若直接调用变量,则首先调用内部类中的,如果内部类中没有,则调用外围类中的成员变量。
package com.javaTest;
//写在成员变量位置的内部类
public class OuterClass1 {
private int a =7;
private int c =8;
public class MyInnerClass1{
private int b = 1;
private int a;
public MyInnerClass1(int a){
this.a =a;
}
public void print(){
System.out.println("只在内部类中有b,直接在内部类中调用b,b=="+b);
System.out.println("只在外围类中有c,直接在内部类中调用c,c=="+c);
System.out.println("OuterClass1.this.a=="+OuterClass1.this.a);//成员内部类可以直接调用外部类的变量,private也可以
System.out.println("外围类和内部类中都有a,直接调用a,a=="+a);//调用内部类的局部变量
System.out.println("this.a=="+this.a);//调用内部类的局部变量
//外围类和内部类中都有时,调用内部类中的
}
}
//可以用private来修饰内部类,然后提供接口调用,则内部类就相对于其他类是隐藏的。
private class MyInnerClass2{
private int b;
private int a;
public MyInnerClass2(int a){
this.b =a ;
this.a =a;
}
public void print(){
System.out.println("b=="+b);
System.out.println("Outer.a=="+OuterClass1.this.a);//成员内部类可以直接调用外部类的变量,private也可以
System.out.println("Inner.a=="+a);//调用内部类的局部变量
System.out.println("Inner.a=="+this.a);//调用内部类的局部变量
}
}
public void getMyInnerClass2(int tmp){
MyInnerClass2 my = new MyInnerClass2(tmp);
my.print();
}
}
2.实例化内部类
两种方法:
1.实例话一个外围类 OuterClass1 myOuterClass = new OuterClass1(); 而内部类的引用是外围类名.内部类名;最后利用外围类对象再new一个内部类实例即可:OuterClass1.MyInnerClass1 myInnerClass2 = myOuterClass.new MyInnerClass1(5);
2.直接new 外围类对象.new 内部类对象;
public static void main(String[] args) {
// TODO Auto-generated method stub
//1、内部类:定义在类内部的类 1、成员内部类(静态内部类(嵌套类)or非静态的),2、局部内部类,3、匿名内部类
//为什么使用内部类
/*1、可以实现多继承,内部类可以直接访问外部类的数据
*2、可以限制其他类访问内部类,对于其他类其细节是隐藏的
*3、想写回调函数且不想写大量代码时,可使用匿名内部类
*
* */
//实例话成员内部类
//在获得外围类的对象之前不可能获得内部类的对象,因为内部类对象那个会暗暗连接到创建它的外围类上(java编程思想)
OuterClass1 myOuterClass = new OuterClass1();//调用方法1 先实例化外部类
System.out.println("****调用方法1****\n");
OuterClass1.MyInnerClass1 myInnerClass2 = myOuterClass.new MyInnerClass1(5);
myInnerClass2.print();
System.out.println("****调用方法2****\n");
OuterClass1.MyInnerClass1 myInnerClass1 = new OuterClass1().new MyInnerClass1(4);//方法2 new OutClass().new InnerClass();
myInnerClass1.print();
System.out.println(myInnerClass1);//com.javaTest.InnerClass1$MyInnerClass1@15db9742
}
3. 利用private 关键词修饰内部类,再通过其他方法调用该内部类,使得它的细节对于其他类是隐藏的,进行封装,如OuterClass1中的yInnerClass2。
静态内部类(嵌套类)
对于内部类,只有静态内部类才能拥有静态变量和静态方法。由于静态内部类不需要获取外围类的对象,所以调用时直接new 外围类.内部类名即可。调用外围类的静态变量时用外围类.变量名。
package com.javaTest;
//静态内部类
public class StaticInnerClass1 {
private static int a=4;
private static String b="I am OuterB";
//对于内部类,只有静态内部类才能拥有静态方法、静态变量和静态内部类(嵌套类)
public static class MyStaitcInnerClass1{
private int a =3;
private static int c=4;
public MyStaitcInnerClass1(int tmp){
this.a =tmp ;
}
public void print(){
System.out.println("Inner.a="+a);//引用变量时,如果前缀什么都不写,首先引用局部变量,若没有局部变量则引用外部变量
}
public void printB(){
System.out.println("b="+b);//
}
public static void printOuter(){
System.out.println("Outer.a="+StaticInnerClass1.a);//如果静态内部类的方法要调用外部类成员标量,该成员变量必须为static,不然该类加载时会报找不到该
//StaticInnerClass1.a外部变量的静态引用
//如果不是内部类的话,报错:The method printOuter cannot be declared static; static methods can only be declared in a static or top level type
}
public static void printInnerStaticC(){
System.out.println("嵌套类静态变量c=="+c);
}
}
}
package com.javaTest;
public class InnerClassTest {
public static void main(String[] args) {
System.out.println("********静态内部类*******\n");
//静态内部类(嵌套类)中可以包含静态变量、静态方法和静态内部类(嵌套类)
//内部类在创建对象时隐式地保留了一个指向创建它的外围类对象的引用,而静态内部类不需要
// new StaticInnerClass1.MyStaitcInnerClass1(1).print();//直接创建StaticInnerClass1的MyStaitcInnerClass1对象,然后调用print方法
StaticInnerClass1.MyStaitcInnerClass1 test = new StaticInnerClass1.MyStaitcInnerClass1(1);//静态类StaticInnerClass1的MyStaitcInnerClass1类的对象
test.printB();//调用静态内部类中的非静态方法,无需实例化外围类对象,只需要实例 StaticInnerClass1.MyStaitcInnerClass1的对象即可
StaticInnerClass1.MyStaitcInnerClass1.printOuter();//直接调用 StaticInnerClass1的MyStaitcInnerClass1的静态方法printOuter
StaticInnerClass1.MyStaitcInnerClass1.printInnerStaticC();
}
局部内部类:定义在方法或者作用域中的内部类
局部内部类不能添加public等修饰,而且调用方法内的局部变量时,该局部变量必须为final(jdk1.8不需要)。由于该局部内部类是属于方法(作用域的),除此之外是无法调用的,应在方法(作用域)中调用,该局部内部类。
package com.javaTest;
public class NestingInnerClass {
private int a=4;
public void printNest(final String test){//jdk1.8不需要加final
//https://blog.csdn.net/tongnuxie/article/details/50111485
//1.当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在, 直到没有被引用时才会消亡。此时就会出现一种情况,就是内部类要访问一个不存在的局部变量。
//2.解决这一问题的办法就是使用final修饰局部变量,通过将final局部变量"复制"一份,复制品直接作为方法内部类中的数据成员,这事方法内部类访问的其实是这个局部变量的复制品! 而且,由于被final修饰的变量赋值后不能再修改,所以就保证了复制品与原始变量的一致。
int b =5;
class NestingClass{ //局部内部类数据作用域的一部分,作用域外的其他地方无法调用,因此只能在作用域中调用
int c =4;
public void print(){
System.out.println(c);
System.out.println(b);
System.out.println(a);
System.out.println(test);
}
}
NestingClass nest =new NestingClass();
nest.print();
}
}
System.out.println("********局部内部类********\n");
//局部内部类
NestingInnerClass nest = new NestingInnerClass();
String str ="ddf";
nest.printNest(str);
匿名内部类:
顾名思义,没有类名的内部类。因此,匿名内部类么有构造函数,且需要继承一个类或实现一个接口,来体现它的类型。定义和实例化是放一块的,通常为接口或父类名(){方法体},可直接在定义后.方法名直接调用或者创建一个父类或接口对象只想该匿名内部类,然后再调用。
package com.javaTest;
public interface AnonymousInterface {
public void show();
}
package com.javaTest;
public class AnonymousInnerClass{
int outer;
public AnonymousInnerClass(int inParam){
outer = inParam;
}
public void testAnonymous(final int t){//jdk 8 不需要添加final
//匿名内部类,首先一个接口,因为没有名字,所以没有构造函数
AnonymousInterface a = new AnonymousInterface() {
int mm;
int kk;
@Override
public void show() {
System.out.println("\n*******匿名内部类1输出*******\n");
mm=AnonymousInnerClass.this.outer;
kk=t;
System.out.println("*********************mm="+mm);
System.out.println("*********************kk="+kk);
}
};
a.show();
new AnonymousInterface() {
int mm;
int kk;
@Override
public void show() {
System.out.println("\n*******匿名内部类2输出*******\n");
mm=AnonymousInnerClass.this.outer;
kk=t;
System.out.println("*********************mm="+mm);
System.out.println("*********************kk="+kk);
}
}.show();
}
}
System.out.println("**********匿名内部类*********");
AnonymousInnerClass anoymousInnerClass = new AnonymousInnerClass(3);
anoymousInnerClass.testAnonymous(4);
内部类的标识、内部类的继承与覆盖
内部类的标识:编译后得到的class文件一般为外围类$内部类.class,而匿名内部类则为父类或接口$+数字
一个类是可以继承内部类的,但由于内部类需要获取到外围类的对象,所以这个类再构造器中需要传入一个外围类的对象,并通过内部类的构造函数进行传递。
如果一个类OutA中有成员内部类In,类OutB继承了OutA,并没有新增一个OutB$In类,但是利用OutB的对象可以创建一个In的实例。
但如果在OutB中重新定义了内部类In,则会有一个OutB$In类,OutB的对象只能创建OutB$In类的实例,相当于In类被覆盖了。
当然还可以内部类继承内部类,首先外围类OutB要继承OutA,OutB中定义的In需要继承OutA.In.
package com.javaTest;
public class ExtendOuterClass1 extends OuterClass1 {
public ExtendOuterClass1(){
System.out.println("******ExtendsInnerClass1******");
}
public class MyInnerClass1{
public void print(){
System.out.println("***ExtendOuterClass1的MyInnerClass1****");
}
}
public class MyInnnerClass1Extemd extends OuterClass1.MyInnerClass1{
public MyInnnerClass1Extemd(int a) {
super(a);
// TODO Auto-generated constructor stub
}
//Implicit super constructor OuterClass1.MyInnerClass1() is undefined for default constructor. Must define an explicit constructor
}
}
package com.javaTest;
public class InnerClassTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//1、内部类:定义在类内部的类 1、成员内部类(静态内部类(嵌套类)or非静态的),2、局部内部类,3、匿名内部类
//为什么使用内部类
/*1、可以实现多继承,内部类可以直接访问外部类的数据
*2、可以限制其他类访问内部类,对于其他类其细节是隐藏的
*3、想写回调函数且不想写大量代码时,可使用匿名内部类
*
* */
//实例话成员内部类
//在获得外围类的对象之前不可能获得内部类的对象,因为内部类对象那个会暗暗连接到创建它的外围类上(java编程思想)
OuterClass1 myOuterClass = new OuterClass1();//调用方法1 先实例化外部类
System.out.println("****调用方法1****\n");
OuterClass1.MyInnerClass1 myInnerClass2 = myOuterClass.new MyInnerClass1(5);
myInnerClass2.print();
System.out.println("****调用方法2****\n");
OuterClass1.MyInnerClass1 myInnerClass1 = new OuterClass1().new MyInnerClass1(4);//方法2 new OutClass().new InnerClass();
myInnerClass1.print();
System.out.println(myInnerClass1);//com.javaTest.InnerClass1$MyInnerClass1@15db9742
System.out.println("********\n");
//对于已封装的内部类 可用private修饰内部类,在通过其他方法获取实例,使得该类的细节隐藏起来。
OuterClass1 myOutClass3 = new OuterClass1();
myOutClass3.getMyInnerClass2(2);
System.out.println("********静态内部类*******\n");
//静态内部类(嵌套类)中可以包含静态变量、静态方法和静态内部类(嵌套类)
//内部类在创建对象时隐式地保留了一个指向创建它的外围类对象的引用,而静态内部类不需要
// new StaticInnerClass1.MyStaitcInnerClass1(1).print();//直接创建StaticInnerClass1的MyStaitcInnerClass1对象,然后调用print方法
StaticInnerClass1.MyStaitcInnerClass1 test = new StaticInnerClass1.MyStaitcInnerClass1(1);//静态类StaticInnerClass1的MyStaitcInnerClass1类的对象
test.printB();//调用静态内部类中的非静态方法,无需实例化外围类对象,只需要实例 StaticInnerClass1.MyStaitcInnerClass1的对象即可
StaticInnerClass1.MyStaitcInnerClass1.printOuter();//直接调用 StaticInnerClass1的MyStaitcInnerClass1的静态方法printOuter
StaticInnerClass1.MyStaitcInnerClass1.printInnerStaticC();
System.out.println("********局部内部类********\n");
//局部内部类
NestingInnerClass nest = new NestingInnerClass();
String str ="ddf";
nest.printNest(str);
System.out.println("**********匿名内部类*********");
AnonymousInnerClass anoymousInnerClass = new AnonymousInnerClass(3);
anoymousInnerClass.testAnonymous(4);
//内部类的继承
ExtendsInnerClass1 extendsInnerClass1 = new ExtendsInnerClass1(myOuterClass, 2);
extendsInnerClass1.print();
ExtendOuterClass1 extend = new ExtendOuterClass1();
//extend.new MyInnerClass1(110).print(); 如果在ExtendOuterClass1中重新定义了MyInnerClass1类
extend.new MyInnerClass1().print();
}
}
****调用方法1****
只在内部类中有b,直接在内部类中调用b,b==1
只在外围类中有c,直接在内部类中调用c,c==8
OuterClass1.this.a==7
外围类和内部类中都有a,直接调用a,a==5
this.a==5
****调用方法2****
只在内部类中有b,直接在内部类中调用b,b==1
只在外围类中有c,直接在内部类中调用c,c==8
OuterClass1.this.a==7
外围类和内部类中都有a,直接调用a,a==4
this.a==4
com.javaTest.OuterClass1$MyInnerClass1@15db9742
********
b==2
Outer.a==7
Inner.a==2
Inner.a==2
********静态内部类*******
b=I am OuterB
Outer.a=4
嵌套类静态变量c==4
********局部内部类********
4
5
4
ddf
**********匿名内部类*********
*******匿名内部类1输出*******
*********************mm=3
*********************kk=4
*******匿名内部类2输出*******
*********************mm=3
*********************kk=4
*****ExtendsInnerClass1****
只在内部类中有b,直接在内部类中调用b,b==1
只在外围类中有c,直接在内部类中调用c,c==8
OuterClass1.this.a==7
外围类和内部类中都有a,直接调用a,a==2
this.a==2
******ExtendsInnerClass1******
只在内部类中有b,直接在内部类中调用b,b==1
只在外围类中有c,直接在内部类中调用c,c==8
OuterClass1.this.a==7
外围类和内部类中都有a,直接调用a,a==110
this.a==110