Java基础之:OOP——内部类
在一个类A中又完整的声明了另一个类B,那么类A我们就称为外部类,类B就称为内部类。
内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
内部类的分类:
创建在外部类的方法内部:
局部内部类
匿名内部类(实际也可以看作是,匿名局部内部类)
创建在外部类的属性位置:
成员内部类
静态内部类(实际也可以看作是,静态成员内部类)
局部内部类
局部内部类是定义在外部类的方法体中的类,具体使用方法与使用细节如下:
1.可以直接访问外部类的所有成员,包含私有的
2.不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的,但是可以使用final 修饰,因为局部变量也可以使用final
3.作用域仅仅在定义它的方法或代码块中,并且遵循前向引用原则
4.外部类---访问------>局部内部类,创建对象调用
5.外部其他类---不能访问----->局部内部类 (因为 局部内部类地位是一个局部变量),这点实际上是可以访问的,不过要用到多态的性质。看下面思考题。
6.如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问
package class_inner;/** * * 1.可以直接访问外部类的所有成员,包含私有的 * 2.不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。 * 但是可以使用final 修饰,因为局部变量也可以使用final * 3.作用域仅仅在定义它的方法或代码块中,并且遵循前向引用原则 * 4.外部类---访问------>局部内部类,创建对象调用 * 5.外部其他类---不能访问----->局部内部类 (因为 局部内部类地位是一个局部变量) * 这点实际上是可以访问的,不过要用到多态的性质。看下面思考题。 * 6.如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则 * 如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问 */public class LocalInnerDetail { public static void main(String[] args) { //细节4:创建Outer对象,调用say()方法,即调用了Inner局部内部类 new Outer().say(); }}class Outer{ private int a; public void say() { //细节3:此时Inner类还没有执行到,不满足向前引用原则,所以不能创建对象// Inner inner = new Inner(); class Inner{ private int b; public void innerShow() { //细节1:可以直接访问外部类的所有成员,包含私有的 System.out.println(a); } } //细节2:可以使用fanal修饰,因为局部内部类,地位就相当于局部变量 final class InnerA{ private int a; public void innerShow() { //细节6:就近原则 ,访问到内部类的属性a System.out.println(a); //细节6:访问外部成员属性,外部类名.this.成员 System.out.println(Outer.this.a); } } Inner inner = new Inner(); inner.innerShow(); } //细节3:// Inner i = new Inner(); //报错:Inner cannot be resolved to a type }关于细节2的补充说明:
局部内部类中只能访问使用final修饰的局部变量(并且在同一个作用域内):
jdk7 final必须手动添加! jdk8 final是隐式加入,不用手动添加。
原因:防止局部变量访问范围扩大!
匿名内部类(重要!!!)
匿名内部类也可以看作是匿名局部内部类,这种内部类在实际开发中经常用到,所以比较重要。
匿名内部类的使用方式以及使用理解如下:
package class_inner.Anonymous;public class AnonymousInner { public static void main(String[] args) { new XX().m1(); //输出:AnonymousInner...... }}class XX{ public void m1() { /* * 对于a而言,编译类型为A * 运行类型为:new 后面一直到 ";" 前面这一部分代码 * 就像是一个类的声明 但这个类并没有名字,声明出来之后直接通过new产生一个对象返回给A接口的引用a * a的运行类型就是一个匿名内部类 */ A a = new A() { @Override public void show() { System.out.println("AnonymousInner......"); } }; /* * 对于show方法调用而言,它会先看编译类型A接口中有没有show方法,如果有编译器通过。 * 然后在运行时,通过动态绑定找到a的运行类型即匿名内部类中实现了的show方法,再执行。 */ a.show(); //还可以使用匿名对象来创建匿名内部类,我们之前会使用匿名对象调用方法,例如: new A().show new A() { @Override public void show() { System.out.println("Other_AnonymousInner......"); } }.show(); }}//不仅可以使用接口,也可以使用父类创建匿名内部类interface A{ public void show(); }
匿名内部类的使用细节与局部内部类,基本相同。但由于匿名内部类的使用方式让我们看起来很"奇特",所以在这里把两种调用方式列出来做一个对比:
package class_inner.Anonymous;public class AnonymousInner { public static void main(String[] args) { //可以使用匿名内部类,作为参数传入方法中,调用顺序于局部内部类相同 say(new B(){ public void show() { System.out.println("interface_B....."); } }); //打印匿名内部类的运行类型,可以看到是没有名字的。 System.out.println(new B() { @Override public void show() { } }.getClass()); System.out.println(new Father("jack").getClass()); //匿名对象 System.out.println(new Father("jack") {}.getClass());//匿名内部类 //使用匿名内部类打印输出信息 Father f = new Father("jack") { @Override public void show() { System.out.println("AnonymousExtends_Class_Father_name:" + getName()); } }; f.show(); } public static void say(B b) { b.show(); } }interface B{ public void show();}class Father{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Father(String name) { super(); this.name = name; } public void show() { System.out.println("Class_Father:" + name); }}程序输出:
interface_B.....
class class_inner.Anonymous.AnonymousInnerDetail$2
class class_inner.Anonymous.Father
class class_inner.Anonymous.AnonymousInnerDetail$3
AnonymousExtends_Class_Father_name:jack
匿名内部类的应用案例
有一个铃声接口Bell,里面有个ring方法。 有一个手机类Cellphone,具有闹钟功能alarmclock,参数是Bell类型 测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了 再传入另一个匿名内部类(对象),打印:小伙伴上课了
package class_inner.Anonymous;public class AnonymousInnerClassWork { public static void main(String[] args) { //方式一:匿名对象调用方法 new Cellphone().alarmclock(new Bell(){ @Override public void ring() { System.out.println("懒猪起床了"); } }); //方式二:实名对象调用方法 Cellphone cellphone = new Cellphone(); cellphone.alarmclock(new Bell() { @Override public void ring() { System.out.println("小伙伴上课了"); } }); }}class Cellphone { public void alarmclock(Bell b) { b.ring(); }}interface Bell{ public void ring();}
成员内部类
成员内部类是声明在外部类的成员属性位置上的类,具体使用如下:
package class_inner;import class_inner.OuterM.InnerM;public class MemberInner { public static void main(String[] args) { //外部其他类---访问---->成员内部类: //方式一:匿名对象,访问成员内部类,调用方法 new OuterM().new InnerM().show2(); //方式二: OuterM outerM = new OuterM(); //如果想要接收InnerM对象,必须要引包 //import class_inner.OuterM.InnerM; InnerM i = outerM.gerInnnerM(); i.show(); //方式三: InnerM i2 = new OuterM().gerInnnerM(); i2.show2(); }}class OuterM{ private String name = "小范"; private int age = 20; //可以使用所有的访问修饰符来修饰成员内部类 public class InnerM{ private String name = "小黄"; public void show() { //可以访问外部类所有属性与方法,因为成员内部类本质地位就是成员属性 //如果外部类和内部类的成员重名时,如果想访问外部类的成员,则可以使用(外部类名.this.成员) System.out.println("name:" + OuterM.this.name + " age: " + age); } public void show2() { System.out.println("name:" + name + " age: " + age); } } public InnerM gerInnnerM() { return new InnerM(); }}程序输出:
name:小黄 age: 20
name:小范 age: 20
name:小黄 age: 20
静态内部类
静态内部类又可能看作是静态成员内部类,因为它就是成员内部类加上了static修饰。
具体使用如下:
package class_inner;import class_inner.OuterM.InnerM;public class MemberInner { public static void main(String[] args) { //外部其他类---访问---->成员内部类: //方式一:匿名对象,访问成员内部类,调用方法 new OuterM().new InnerM().show2(); //方式二: OuterM outerM = new OuterM(); //如果想要接收InnerM对象,必须要引包 //import class_inner.OuterM.InnerM; InnerM i = outerM.gerInnnerM(); i.show(); //方式三: InnerM i2 = new OuterM().gerInnnerM(); i2.show2(); }}class OuterM{ private String name = "小范"; private int age = 20; //可以使用所有的访问修饰符来修饰成员内部类 public class InnerM{ private String name = "小黄"; public void show() { //可以访问外部类所有属性与方法,因为成员内部类本质地位就是成员属性 //如果外部类和内部类的成员重名时,如果想访问外部类的成员,则可以使用(外部类名.this.成员) System.out.println("name:" + OuterM.this.name + " age: " + age); } public void show2() { System.out.println("name:" + name + " age: " + age); } } public InnerM gerInnnerM() { return new InnerM(); }}程序输出:
name:小范
OuterS_phone:123
InnerS_Sphone:321
特别注意:
使用静态内部类,只需要使用类名调用即可,就不会生成OuterS外部类的对象
出现重名的属性时,只需要 (外部类名.属性)就可以访问
静态内部类只能访问外部静态的内容
思考题
在局部内部类的细节5中提到外部其他类不能访问局部内部类,但可以通过多态的特性将其实现。
具体方式是:
定义一个局部内部类可以访问到的接口或父类
让局部内部类继承此接口或父类
在外部其他可以使用接口或父类的类中,就可以通过多态的方式使用到局部内部类。
这种方式主要就是使用了多态的动态绑定机制
package test;public class Test { public static void main(String[] args) { A a = new A(); System.out.println("a--hashCode= " + a.hashCode()); A a2 = a.say(); a2.show(); // X x = a.say();// x.show(); }}interface X{ public void show();}class A{ public void show() { } private int n1 = 10; private int n3 = 330; public A /* X */ say() { int n2 = 20; class InnerA extends A /* implements X */{ int n3 = 30; public void show() { System.out.println("A--n3=" + A.this.n3 + "\tInnerA--n3= " + n3); System.out.println("A--hashCode=" + A.this.hashCode()); } } InnerA innerA = new InnerA(); innerA.show(); return innerA; }}
程序输出:
a--hashCode= 366712642
A--n3=330 InnerA--n3= 30
A--hashCode=366712642
A--n3=330 InnerA--n3= 30
A--hashCode=366712642
说明
在程序中可以使用接口 X 将局部内部类"接出来",也可以使用父类 A 将局部内部类"接出来"。
这种思路需要灵活应用动态绑定机制,考虑局部内部类的运行类型问题。
原文转载:http://www.shaoqun.com/a/501096.html
欧苏丹:https://www.ikjzd.com/w/1756
cicpa考试:https://www.ikjzd.com/w/1375
tinypic:https://www.ikjzd.com/w/114
Java基础之:OOP——内部类在一个类A中又完整的声明了另一个类B,那么类A我们就称为外部类,类B就称为内部类。内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。内部类的分类:创建在外部类的方法内部:局部内部类匿名内部类(实际也可以看作是,匿名局部内部类)创建在外部类的属性位置:成员内部类静态内部类(实际也可以看作是,静态成员内部类)局部内部类局部内部类是定义在外部类的
网上1号店:网上1号店
法瑞儿:法瑞儿
口述:无耻小三住隔壁监督我们房事老公变心第三者:口述:无耻小三住隔壁监督我们房事老公变心第三者
学士服颜色分类 学士服颜色分别代表什么学历:学士服颜色分类 学士服颜色分别代表什么学历
这样写亚马逊索评邮件,好评滚滚来(附英文模板):这样写亚马逊索评邮件,好评滚滚来(附英文模板)
No comments:
Post a Comment