Java内部类
①内部类是在一个java类体内,再定义一个类,即外部类的内部再定义一个类(相对的)。
②内部类分为四类:
成员内部类、局部内部类、静态内部类、匿名内部类
③内部类作为外部类的一个成员,并依附于外部类而存在。包括:成员内部类、局部内部类、匿名内部类
④内部类可以由private、public、protected、default访问修饰符和static修饰;
⑤而外部类,即和public类平行的,只能有default修饰(空白修饰符),总之,由public和default访问修饰符修饰。
⑥ 内部类和外部类的实例变量可以共存,
内部类中访问实例变量:this.属性。eg: this.age
内部类中访问外部类的实例变量:外部类名.this.属性。InnerClass.this.id
⑦内部类是一个编译时的概念,编译成功,就会成为完全不同的两个类 eg:InnerClass.class和InnerClass$Classx1.class
⑧内部类里不能定义静态的属性和方法;
注:此处内部类(除静态内部类外);
加载类时,静态默认在内存中实例化的并存放。即可以直接调用不用手动实例化使用。内部类的实例化依赖于外部类,内部类不能直接被实例化,必须在外部类实例化后再实例化。
外部类public class或class是不能默认加载的,只有调用new关键字手动实例化时才分配内存。
所以内部类不能定义静态的属性和方法。
所有代码编译图为:
成员内部类:
package com.classx.inner; public class InnerClass { //外部类private属性 private int id=4466; private static String name ="shasha"; //外部类getter和setter方法 public int getId() { return id; } public void setId(int id) { this.id = id; } public static String getName() { return name; } public static void setName(String name) { InnerClass.name = name; } //************************成员内部类***********************************// //成员内部类,作为外部类的成员,可以访问外部所有 //内部类中的定义的private属性,比外部的private还小的访问权限 //作为一个外部类的成员存在,和外部类的属性、方法并列 //可以有private、public、protected、default修饰 class Classx1{ private int age=5555; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void getN1(){ System.out.println("inner1"); System.out.println("成员内部类:"+InnerClass.this.id+"*"+this.age); } } //外部类内部调用成员内部类 public void getC1(){ Classx1 c1 = new Classx1(); c1.getN1(); System.out.println("外部类内部调用成员内部类:完毕!"); } }
测试类:
package com.classx.inner; public class Test { public static void main(String[] args) { //*****外部类调用成员内部类********// //外部类对象ic InnerClass ic = new InnerClass(); /***成员内部类***/ //内部调用 ic.getC1(); //外部调用 // InnerClass.Classx1 icc1 = new InnerClass().new Classx1(); InnerClass.Classx1 icc1 = ic.new Classx1(); icc1.getN1(); } }
输出结果:
inner1
成员内部类:4466*5555
外部类内部调用成员内部类:完毕!
inner1
成员内部类:4466*5555
编译后的class字节码反编译为:
InnerClass类:
package com.classx.inner; import java.io.PrintStream; public class InnerClass { private int id = 4466; private static String name = "shasha"; public int getId() { return this.id; } public void setId(int id) { this.id = id; } public static String getName() { return name; } public static void setName(String name) { name = name; } public void getC1() { Classx1 c1 = new Classx1(); c1.getN1(); System.out.println("外部类内部调用成员内部类:完毕!"); } class Classx1 { private int age = 5555; Classx1() { } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } public void getN1() { System.out.println("inner1"); System.out.println("成员内部类:" + InnerClass.this.id + "*" + this.age); } } }
成员内部类Classx1:
package com.classx.inner; import java.io.PrintStream; class InnerClass$Classx1 { private int age = 5555; InnerClass$Classx1(InnerClass paramInnerClass) { } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } public void getN1() { System.out.println("inner1"); System.out.println("成员内部类:" + InnerClass.access$0(this.this$0) + "*" + this.age); } }
局部内部类:
此后外部类代码,不变,替换内部类:
//************************局部内部类***********************************// public void drawIC(){ //在外部类方法体中定义的类叫局部内部类,不能有修饰符(包括static),能访问外部类实例变量,且只能访问方法体中的final类型的局部变量 final String fstr = "lalala"; System.out.println("inner2"); //局部内部类 //外部类外不可直接生成局部内部类,对外不可见 class Classx2{ private int width = 333; public Classx2(){ super(); System.out.println("局部内部类默认构造方法在drawIC中new时候执行"); } public void getN2(){ System.out.println("局部内部类:"+fstr+"&"+id+"$"+width); } } //使用局部内部类,要生成对象,对象调用方法,在方法中才能调用其局部内部类 //局部内部类使用new,方法调用 Classx2 icmc = new Classx2(); System.out.println("局部内部类对象调用getN2开始"); icmc.getN2(); }
测试代码:
此后,main中的代码,其他省略:
//*****外部类调用成员内部类********// //外部类对象ic InnerClass ic = new InnerClass(); /***局部内部类***/ //调用局部内部类 ic.drawIC();
代码输出为:
inner2
局部内部类默认构造方法在drawIC中new时候执行
局部内部类对象调用getN2开始
局部内部类:lalala&4466$333
编译后的InnerClass类:
此后,只替换变化代码,其他不变:
public void drawIC() { String fstr = "lalala"; System.out.println("inner2"); Object icmc = new Object() { private int width = 333; public void getN2() { System.out.println("局部内部类:lalala&" + InnerClass.this.id + "$" + this.width); } }; System.out.println("局部内部类对象调用getN2开始"); icmc.getN2(); }
编译后的Classx2类:
package com.classx.inner; import java.io.PrintStream; class InnerClass$1Classx2 { private int width = 333; public InnerClass$1Classx2(InnerClass paramInnerClass) { System.out.println("局部内部类默认构造方法在drawIC中new时候执行"); } public void getN2() { System.out.println("局部内部类:lalala&" + InnerClass.access$0(this.this$0) + "$" + this.width); } }
静态内部类
//************************静态内部类***********************************// //静态内部类 //外部类只能有public和default修饰符,而成员内部类可以有private、public、protected、default和static修饰 //只能访问外部类静态成员 public static class Class3{ private static int length = 169; public void getN3(){ System.out.println("inner3"); System.out.println("静态内部类:"+length+InnerClass.name); } }
测试代码:
/***静态内部类***/ //调用静态内部类 //不需要通过生成外部类的对象来生成,实际上,成为了顶级类 // Class3 c3 = new InnerClass.Class3(); InnerClass.Class3 c3 = new InnerClass.Class3(); c3.getN3();
输出为:
inner3
静态内部类:169shasha
编译后:
InnerClass类:
public static class Class3 { private static int length = 169; public void getN3() { System.out.println("inner3"); System.out.println("静态内部类:" + length + InnerClass.name); } }
Class3类:
package com.classx.inner; import java.io.PrintStream; public class InnerClass$Class3 { private static int length = 169; public void getN3() { System.out.println("inner3"); System.out.println("静态内部类:" + length + InnerClass.access$0()); } }
匿名内部类:
In接口:
package com.classx.inner; public interface In { public abstract int extend(); }
Ac抽象类:
package com.classx.inner; public abstract class Ac { public abstract int extend(); }
InnerClass类:
//************************匿名内部类***********************************// //匿名内部类 //①是特殊的局部内部类,所以局部内部类的限制对它生效,不能有访问修饰符和static修饰 //②唯一一个无构造方法的类(使用范围很有限),不能定义任何静态成员、方法、类 //③一个匿名内部类一定是在new后面,用它隐含的实现一个接口或实现一个类 //④没有类名(不能有),所以不能引用它。根据多态,可使用它的父类(接口)名 //⑤没办法引用它,必须在创建时,作为new语句的一部分来声明它(特殊形式new语句),形式:new 类名或接口名(){类的主体} //通过上new语句声明形式,声明一个新的匿名类,它对一个给定类进行扩展,或实现一个给定的接口 //并且还创建给定类或给定接口的新实例(只能创建匿名内部类的一个实例),并把它作为语句的结果返回 //⑥内部匿名类,就是建立一个内部的类,但没有给你命名,也就是没有引用实例的变量。 //⑦匿名类扩展了给定类,可以访问该被扩展类的成员、覆盖它的方法等(标准类一致) //⑧匿名类实现了接口,它的主体必须实现接口的方法 //⑨如果一个对象编译时类型为接口,那么运行时类型为实现这个接口的类 //10编译时系统自动起名:InnerClass$1.class //*匿名内部类实现一个接口,可以解决多继承出现方法冲突问题*/ //可以直接返回return,也可作为方法返回值(给定接口或类的实例)返回 public In getExtendI(){ return new In() { @Override public int extend() { System.out.println("inner4"); System.out.println("匿名内部类:我实现了接口In的方法"); return 0; } }; } //一般new对象,InnerClass ic = new InnerClass(); //小括号后为;分号,结束,即new出了对象语句结束 //匿名内部类,new In() {...} //小括号后为{}大括号,大括号中是该new出对象的具体实现方法 //一个抽象类不能直接使用(new对象),不能生成对象,必须继承使用,后进行new出对象使用 //*匿名内部类,可以对抽象类进行实现(实现类为匿名内部类),和extends继承父类,实现抽象是一样的 */ public Ac getExtendC(){ return new Ac() { @Override public int extend() { System.out.println("inner5"); System.out.println("匿名内部类:我扩展了抽象类AC的方法"+(InnerClass.this.id)); return 0; } }; } //*匿名内部类不能对InnerClass类扩展,方法不可用"unused"*/
测试类:
/***匿名内部类***/ //匿名内部类实现接口的调用 In in = ic.getExtendI(); in.extend(); //匿名内部类作为抽象类的实现类 Ac ac = ic.getExtendC(); ac.extend();
输出结果:
inner4
匿名内部类:我实现了接口In的方法
inner5
匿名内部类:我扩展了抽象类AC的方法4466
编译后:
InnerClass类:
public In getExtendI() { return new In() { public int extend() { System.out.println("inner4"); System.out.println("匿名内部类:我实现了接口In的方法"); return 0; } }; } public Ac getExtendC() { return new Ac() { public int extend() { System.out.println("inner5"); System.out.println("匿名内部类:我扩展了抽象类AC的方法" + InnerClass.this.id); return 0; } };
接口实现匿名内部类:
package com.classx.inner; import java.io.PrintStream; class InnerClass$1 implements In { InnerClass$1(InnerClass paramInnerClass) { } public int extend() { System.out.println("inner4"); System.out.println("匿名内部类:我实现了接口In的方法"); return 0; } }
抽象类实现类(匿名内部类)
package com.classx.inner; import java.io.PrintStream; class InnerClass$2 extends Ac { InnerClass$2(InnerClass paramInnerClass) { } public int extend() { System.out.println("inner5"); System.out.println("匿名内部类:我扩展了抽象类AC的方法" + InnerClass.access$0(this.this$0)); return 0; } }
注:最尾提供全部代码
Java多继承方法(名)冲突
当类或接口或(抽象)父类,三个不同组合,发生方法(名)冲突的时候,此时必须使用内部类来解决。
匿名内部类、成员内部类
接口配合内部类,可以实现真正完全的多继承。
接口In:
package com.classx.inner; public interface In { public abstract int extend(int id); }
抽象类Ac:
package com.classx.inner; public abstract class Ac { public abstract int extend(int id); }
实现类InnerClassSolveMultipleForAcOrIn:
package com.classx.inner; //当类或接口或(抽象)父类,三个不同组合,发生方法(名)冲突的时候,此时必须使用内部类来解决 //接口配合内部类,可以实现真正完全的多继承 public class InnerClassSolveMultipleForAcOrIn implements In{ public int id = 3355; @Override public int extend(int id) { System.out.println("外部类实现接口In中的extend()方法"+id); return 1; } //内部类作为外部类的成员(非静态) //内部类可以对外部类状态完全进行修改,和直接调用(使用)InnerClassSolveMultipleForAcOrIn是一样的 private class InnerC extends Ac{ @Override public int extend(int id) { System.out.println("成员内部类实现抽象父类Ac中的extend()方法"+id); return 2; } } //内部类为private的,除了当前外部类,其他类都是不可见的 //而此方法,返回值为直接向上转型(实现了抽象父类)的抽象父类的引用,对外暴露抽象父类,隐藏了InnerC的存在 public Ac getInnerCInstance(){ return new InnerC(); } //匿名内部类解决冲突 public Ac getgetInnerNoInstance(){ return new Ac() { @Override public int extend(int id) { System.out.println("匿名内部类实现抽象父类Ac中的extend()方法"+id); return 3; } }; } }
测试类:
package com.classx.inner; public class TestAcIn { public static void main(String[] args) { //外部类对象 InnerClassSolveMultipleForAcOrIn iaci = new InnerClassSolveMultipleForAcOrIn(); In in = iaci; //外部类实现接口方法 in.extend(1); //用"成员内部类"解决(实现)抽象类和接口同名方法 Ac ac = iaci.getInnerCInstance(); ac.extend(2); //用"匿名内部类"解决(实现)抽象类和接口同名方法 Ac acn = iaci.getgetInnerNoInstance(); acn.extend(3); } }
输出结果:
外部类实现接口In中的extend()方法1
成员内部类实现抽象父类Ac中的extend()方法2
匿名内部类实现抽象父类Ac中的extend()方法3
实现内部类,全部代码:
内部类InnerClass代码:
package com.classx.inner; public class InnerClass { //外部类private属性 private int id=4466; private static String name ="shasha"; //外部类getter和setter方法 public int getId() { return id; } public void setId(int id) { this.id = id; } public static String getName() { return name; } public static void setName(String name) { InnerClass.name = name; } //************************成员内部类***********************************// //成员内部类,作为外部类的成员,可以访问外部所有 //内部类中的定义的private属性,比外部的private还小的访问权限 //作为一个外部类的成员存在,和外部类的属性、方法并列 //可以有private、public、protected、default修饰 class Classx1{ private int age=5555; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void getN1(){ System.out.println("inner1"); System.out.println("成员内部类:"+InnerClass.this.id+"*"+this.age); } } //外部类内部调用成员内部类 public void getC1(){ Classx1 c1 = new Classx1(); c1.getN1(); System.out.println("外部类内部调用成员内部类:完毕!"); } //************************局部内部类***********************************// public void drawIC(){ //在外部类方法体中定义的类叫局部内部类,不能有修饰符(包括static),能访问外部类实例变量,且只能访问方法体中的final类型的局部变量 final String fstr = "lalala"; System.out.println("inner2"); //局部内部类 //外部类外不可直接生成局部内部类,对外不可见 class Classx2{ private int width = 333; public Classx2(){ super(); System.out.println("局部内部类默认构造方法在drawIC中new时候执行"); } public void getN2(){ System.out.println("局部内部类:"+fstr+"&"+id+"$"+width); } } //使用局部内部类,要生成对象,对象调用方法,在方法中才能调用其局部内部类 //局部内部类使用new,方法调用 Classx2 icmc = new Classx2(); System.out.println("局部内部类对象调用getN2开始"); icmc.getN2(); } //************************静态内部类***********************************// //静态内部类 //外部类只能有public和default修饰符,而成员内部类可以有private、public、protected、default和static修饰 //只能访问外部类静态成员 public static class Class3{ private static int length = 169; public void getN3(){ System.out.println("inner3"); System.out.println("静态内部类:"+length+InnerClass.name); } } //************************匿名内部类***********************************// //匿名内部类 //①是特殊的局部内部类,所以局部内部类的限制对它生效,不能有访问修饰符和static修饰 //②唯一一个无构造方法的类(使用范围很有限),不能定义任何静态成员、方法、类 //③一个匿名内部类一定是在new后面,用它隐含的实现一个接口或实现一个类 //④没有类名(不能有),所以不能引用它。根据多态,可使用它的父类(接口)名 //⑤没办法引用它,必须在创建时,作为new语句的一部分来声明它(特殊形式new语句),形式:new 类名或接口名(){类的主体} //通过上new语句声明形式,声明一个新的匿名类,它对一个给定类进行扩展,或实现一个给定的接口 //并且还创建给定类或给定接口的新实例(只能创建匿名内部类的一个实例),并把它作为语句的结果返回 //⑥内部匿名类,就是建立一个内部的类,但没有给你命名,也就是没有引用实例的变量。 //⑦匿名类扩展了给定类,可以访问该被扩展类的成员、覆盖它的方法等(标准类一致) //⑧匿名类实现了接口,它的主体必须实现接口的方法 //⑨如果一个对象编译时类型为接口,那么运行时类型为实现这个接口的类 //10编译时系统自动起名:InnerClass$1.class //*匿名内部类实现一个接口,可以解决多继承出现方法冲突问题*/ //可以直接返回return,也可作为方法返回值(给定接口或类的实例)返回 public In getExtendI(){ return new In() { @Override public int extend() { System.out.println("inner4"); System.out.println("匿名内部类:我实现了接口In的方法"); return 0; } }; } //一般new对象,InnerClass ic = new InnerClass(); //小括号后为;分号,结束,即new出了对象语句结束 //匿名内部类,new In() {...} //小括号后为{}大括号,大括号中是该new出对象的具体实现方法 //一个抽象类不能直接使用(new对象),不能生成对象,必须继承使用,后进行new出对象使用 //*匿名内部类,可以对抽象类进行实现(实现类为匿名内部类),和extends继承父类,实现抽象是一样的 */ public Ac getExtendC(){ return new Ac() { @Override public int extend() { System.out.println("inner5"); System.out.println("匿名内部类:我扩展了抽象类AC的方法"+(InnerClass.this.id)); return 0; } }; } //*匿名内部类不能对InnerClass类扩展,方法不可用"unused"*/ }
测试Test代码:
package com.classx.inner; public class Test { public static void main(String[] args) { //*****外部类调用成员内部类********// //外部类对象ic InnerClass ic = new InnerClass(); /***成员内部类***/ //内部调用 ic.getC1(); //外部调用 // InnerClass.Classx1 icc1 = new InnerClass().new Classx1(); InnerClass.Classx1 icc1 = ic.new Classx1(); icc1.getN1(); /***局部内部类***/ //调用局部内部类 ic.drawIC(); /***静态内部类***/ //调用静态内部类 //不需要通过生成外部类的对象来生成,实际上,成为了顶级类 // Class3 c3 = new InnerClass.Class3(); InnerClass.Class3 c3 = new InnerClass.Class3(); c3.getN3(); /***匿名内部类***/ //匿名内部类实现接口的调用 In in = ic.getExtendI(); in.extend(); //匿名内部类作为抽象类的实现类 Ac ac = ic.getExtendC(); ac.extend(); } }
输出结果:
inner1
成员内部类:4466*5555
外部类内部调用成员内部类:完毕!
inner1
成员内部类:4466*5555
inner2
局部内部类默认构造方法在drawIC中new时候执行
局部内部类对象调用getN2开始
局部内部类:lalala&4466$333
inner3
静态内部类:169shasha
inner4
匿名内部类:我实现了接口In的方法
inner5
匿名内部类:我扩展了抽象类AC的方法4466
package com.classx.inner; public class Test { public static void main(String[] args) { //*****外部类调用成员内部类********// //外部类对象ic InnerClass ic = new InnerClass(); /***成员内部类***/ //内部调用 ic.getC1(); //外部调用 // InnerClass.Classx1 icc1 = new InnerClass().new Classx1(); InnerClass.Classx1 icc1 = ic.new Classx1(); icc1.getN1(); /***局部内部类***/ //调用局部内部类 ic.drawIC(); /***静态内部类***/ //调用静态内部类 //不需要通过生成外部类的对象来生成,实际上,成为了顶级类 // Class3 c3 = new InnerClass.Class3(); InnerClass.Class3 c3 = new InnerClass.Class3(); c3.getN3(); /***匿名内部类***/ //匿名内部类实现接口的调用 In in = ic.getExtendI(); in.extend(); //匿名内部类作为抽象类的实现类 Ac ac = ic.getExtendC(); ac.extend(); } }