- 什么是内部类
内部类是指在一个外部类的内部再定义一个类。
内部类可以是静态static的,也可用public,default,protected和private修饰。(而外部顶级类即类名和文件名相同的只能使用public和default)。
注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为Outer的外部类和其内部定义的名为Inner的内部类。编译完成后出现Outer.class和Outer$Inner.class两类。所以内部类的成员变量/方法名可以和外部类的相同。
java内部类分为: 成员内部类、静态嵌套类、局部内部类、匿名内部类 。
- 内部类的共性
(1)、内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。
(2)、内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 。
(3)、内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。
- 成员内部类
public class Outer {
private int a = 10;
private int b = 15;
public void print() {
System.out.println("Outer.a="+this.a);
}
public int add(int i,int j) {
return i+j;
}
class Inner {
private int a = 20;
private int c = b;
public void print() {
//内部类访问外部类中的同名成员变量
System.out.println("Outer.a="+Outer.this.a);
System.out.println("Inner.a="+this.a);
System.out.println("a="+a);
//内部类中可以直接访问外部类的成员变量和方法(内部类对象持有指向外部类对象的引用。)
System.out.println("c="+c);
System.out.println("c+1="+add(c,1));
}
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.print();
//内部类对象的创建依赖于外部类对象;
outer.new Inner().print();
}
}
这个类编译后出现Outer.class和Outer$Inner.class两个class文件。编译后成为两个独立的类,
因此,内部类中可以定义与外部类中同名的属性和方法。
成员内部类,就是作为外部类的成员,与外部类的属性、方法并列。可以直接使用外部类的所有成员和方法,即使是private的。
同时外部类要访问内部类的所有成员变量和方法,则需要通过内部类的对象来获取。
要注意的是,成员内部类不能含有static的变量和方法。因为成员内部类需要先创建了外部类,才能创建它自己的
- 局部内部类
局部内部类,是指内部类定义在方法和作用域内。
(1)、定义在方法内
public class Teacher {
private String name;
private int age;
public void teach() {
final String str = "I'm a teacher!";
class EnglishTeacher {
public void teachEnglish() {
System.out.println("My name is "+name);
System.out.println("I'm "+age);
System.out.println(str);
System.out.println("I teach English");
}
}
EnglishTeacher englishTeacher = new EnglishTeacher();
englishTeacher.teachEnglish();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Teacher teacher = new Teacher();
teacher.name = "张三";
teacher.age = 35;
teacher.teach();
}
}
(2)、定义在作用域内
public class Teacher1 {
private String name;
private int age;
public void teach(String course) {
final String str = "I'm a teacher!";
System.out.println(str);
if("English".equals(course)) {
class EnglishTeacher {
public void teachEnglish() {
System.out.println("My name is "+name);
System.out.println("I'm "+age);
System.out.println("I teach English");
}
}
EnglishTeacher englishTeacher = new EnglishTeacher();
englishTeacher.teachEnglish();
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Teacher1 teacher = new Teacher1();
teacher.name = "张三";
teacher.age = 35;
teacher.teach("English");
}
}
(1)、局部内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。
(2)、局部内部类对象不能使用该内部类所在方法的非final局部变量。
(3)、局部内部类的地位和方法内的局部变量的位置类似,因此不能修饰局部变量的修饰符也不能修饰局部内部类,
譬如public、private、protected、static、transient等
因为方法的局部变量位于栈上,只存在于该方法的生命期内。当一个方法结束,其栈结构被删除,局部变量成为历史。但是该方法结束之后,在方法内创建的内部类对象可能仍然存在于堆中!例如,如果对它的引用被传递到其他某些代码,并存储在一个成员变量内。正因为不能保证局部变量的存活期和方法内部类对象的一样长,所以内部类对象不能使用它们。
- 静态嵌套类
public class StaticOuter {
private int a = 10;
private static int b = 15;
static class StaticInner {
public static void print() {
System.out.println("b="+b);
}
void print1() {
System.out.println("b="+b);
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
StaticOuter.StaticInner.print();
new StaticOuter.StaticInner().print1();
}
}
嵌套类和普通的内部类还有一个区别:普通内部类不能有static数据和static属性,也不能包含嵌套类,但嵌套类可以。
而嵌套类不能声明为private,一般声明为public,方便调用。
在静态方法中定义的内部类也是StaticNested Class,这时候不能在类前面加static关键字,静态方法中的StaticNested Class与
普通方法中的内部类的应用方式很相似,它除了可以直接访问外部类中的static的成员变量,还可以访问静态方法中的局部变量,
但是,该局部变量前必须加final修饰符。
- 匿名内部类
匿名内部类就是没有名字的内部类。什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:
·只用到类的一个实例 。
·类在定义后马上用到。
·类非常小(SUN推荐是在4行代码以下)
·给类命名并不会导致你的代码更容易被理解。
在使用匿名内部类时,要记住以下几个原则:
·匿名内部类不能有构造方法。
·匿名内部类不能定义任何静态成员、静态方法。
·匿名内部类不能是public,protected,private,static。
·只能创建匿名内部类的一个实例。
·一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
·因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
(1)、继承式的匿名内部类
public class Singer {
public void sing() {
System.out.println("Sing a song");
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Singer singer = new Singer() {
@Override
public void sing() {
// TODO Auto-generated method stub
System.out.println("Sing a popular song");
}
};
singer.sing();
}
}
输出结果:Sing a popular song
(2)、接口式的匿名内部类
public interface Programmer {
public void code();
}
public class TestProgrammer {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Programmer javaProgrammer = new Programmer() {
@Override
public void code() {
// TODO Auto-generated method stub
System.out.println("Java programmer");
}
};
javaProgrammer.code();
Programmer phpProgrammer = new Programmer() {
@Override
public void code() {
// TODO Auto-generated method stub
System.out.println("Php programmer");
}
};
phpProgrammer.code();
}
}
(3)、参数式的匿名内部类
public interface Programmer {
public void code();
}
public class TestProgrammer1 {
public void testCode(Programmer p) {
p.code();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
TestProgrammer1 testProgrammer1 = new TestProgrammer1();
testProgrammer1.testCode(new Programmer() {
@Override
public void code() {
// TODO Auto-generated method stub
System.out.println("testing code");
}
});
}
}
- 为什么需要内部类
典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。
使用内部类最吸引人的原因是:
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。