java基础:熟悉3种内部类的写法,重点匿名内部类的使用
一、内部类定义
内部类(nested classes),面向对象程序设计中,可以在一个类的内部定义另一个类。嵌套类分为两种,即静态嵌套类和非静态嵌套类。静态嵌套类使用很少,最重要的是非静态嵌套类,也即是被称作为内部类(inner)。内部类是JAVA语言的主要附加部分。内部类几乎可以处于一个类内部任何位置,可以与实例变量处于同一级,或处于方法之内,甚至是一个表达式的一部分。
为什么需要内部类?
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。
二、内部类分类
一、成员内部类
作为外部类的一个成员存在,与外部类的属性、方法并列。
成员内部类也是定义在另一个类中,但是定义时不用static修饰。
成员内部类和静态内部类可以类比为非静态的成员变量和静态的成员变量。
成员内部类就像一个实例变量。
它可以访问它的外部类的所有成员变量和方法,不管是静态的还是非静态的都可以。
在外部类里面创建成员内部类的实例:
this.new B();
在外部类之外创建内部类的实例:
(new Test1()).new B().go();
在内部类里访问外部类的成员:
Test1.this.member
1 package memberiner; 2 3 public class Test1 { 4 private String member="这是外部类变量"; 5 //成员内部类 6 //不对外开放,高内聚 7 class B{ 8 public B() {//当内部类的构造器为Protected、private修饰时外部类外不可以访问 9 10 } 11 public void go(){ 12 System.out.println("这是内部类B的go方法"+Test1.this.member);//内部类访问外部类变量 13 } 14 } 15 16 17 //可供成员的外部类中其他方法调用 18 public B show(){ 19 20 return this.new B();//外部类调用 21 22 } 23 24 public static void main(String[] args) { 25 26 B b = new Test1().show(); 27 } 28 29 } 30 31 32 package memberiner; 33 34 public class A { 35 36 public static void main(String[] args) { 37 38 new Test1().show(); 39 40 (new Test1()).new B().go();//外部类外访问内部类 41 } 42 43 }
二、方法内部类(局部内部类)
定义在方法中,比方法的范围还小。是内部类中最少用到的一种类型。
像局部变量一样,不能被public, protected, private和static修饰。
只能访问方法中定义的final类型的局部变量。
方法内部类在方法中定义,所以只能在方法中使用,即只能在方法当中生成方法内部类的实例并且调用其方法
1 package methodinner; 2 3 public class Test { 4 5 class Duanzanshichangzheng { 6 7 public void noProblem() { 8 System.out.println("患有急性短暂失常症,开车撞死人没事"); 9 10 } 11 12 } 13 14 private String member ="全局变量"; 15 final int n=4; 16 public void driver(){ 17 final String member2 ="局部变量";//方法内的变量只有final变量才能被方法内部类访问 18 System.out.println("我正在开车"+member); 19 20 //每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现, 21 //对于内部类都没有影响 22 //内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承” 23 //短暂,不对外,防止变成全局 24 class B extends Duanzanshichangzheng { 25 public void show(){ 26 System.out.println(member2+4); 27 } 28 } 29 new B().noProblem();//方法内部类里的方法只能在方法里调用 30 new B().show(); 31 32 System.out.println("一切恢复正常"); 33 34 } 35 36 public static void main(String[] args) { 37 new Test().driver(); 38 } 39 40 }
三、匿名内部类(Android运用最多)
匿名内部类就是没有名字的局部内部类,不使用关键字class, extends, implements, 没有构造方法。
什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:
a·只用到类的一个实例。
b·类在定义后马上用到。
c·类非常小(SUN推荐是在4行代码以下)
d·给类命名并不会导致你的代码更容易被理解。
在使用匿名内部类时,要记住以下几个原则:
a·匿名内部类不能有构造方法。
b·匿名内部类不能定义任何静态成员、方法和类。
c·匿名内部类不能是public,protected,private,static。
d·只能创建匿名内部类的一个实例。
e·一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
f·因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
以下是匿名内部类的实例:
实例背景:输出每个Doctor博士每天做的事情
1、白天大家都是“白天传授理论知识”;
2、晚上每个人都是不一样的
*用以前继承方法需要写多个实现类,而匿名内部类只需要实现“晚上做事workInNight()”这个方法就可以了
代码目录
1 package anonymousinner; 2 3 public interface Qinshou { 4 public void workInNight(); 5 }
1 package anonymousinner; 2 3 public abstract class Doctor implements Qinshou { 4 //多态,情况不定 5 public void workInDay(){ 6 System.out.println("白天传授理论知识"); 7 } 8 9 }
1 package anonymousinner; 2 3 public class Doctor1 extends Doctor { 4 5 public void workInNight(){ 6 System.out.println("晚上教弹琴"); 7 } 8 }
1 package anonymousinner; 2 3 public class Doctor2 extends Doctor{ 4 5 public void workInNight(){ 6 System.out.println("晚上学习"); 7 } 8 }
1 package anonymousinner; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 Doctor1 d1 = new Doctor1(); 7 d1.workInDay(); 8 d1.workInNight(); 9 10 Doctor2 d2 = new Doctor2(); 11 d2.workInDay(); 12 d2.workInNight(); 13 14 //语法格式 15 //1、new 抽象类或者接口 16 //2、后加大括号 17 //3、实现未实现方法 18 Doctor d3 = new Doctor(){ 19 20 //匿名内部类 21 public void workInNight() { 22 System.out.println("睡觉"); 23 } 24 25 }; 26 27 d3.workInDay(); 28 d3.workInNight(); 29 } 30 }
匿名内部类细节:
1、
1 //1 2 new Object(){ 3 void show(){ 4 System.out.println("show run"); 5 } 6 }.show();//正确 7 //2 8 Object obj = new Object(){ 9 void show(){ 10 System.out.println("show run"); 11 } 12 }; 13 obj.show();//编译错误
1和2的写法正确吗?有区别吗?说出原因。
写法是正确,1和2都是在通过匿名内部类建立一个Object类的子类对象。
区别:
第一个可是编译通过,并运行。
第二个编译失败,因为匿名内部类是一个子类对象,当用Object的obj引用指向时,就被提升为了
Object类型,而编译时检查Object类中是否有show方法,所以编译失败。
2、
1 class InnerClassDemo6 { 2 +(static)class Inner{ 3 void show(){} 4 } 5 public void method(){ 6 this.new Inner().show();//可以 7 } 8 public static void main(String[] args) {//static不允许this 9 This.new Inner().show();//错误,Inner类需要定义成static 10 } 11 }
还有很多的不懂,各位大神多多指教喔!