1. 定义
内部类的定义十分简单,当我们将一个类的定义放在另一个类的定义内部时,这个类就是内部类。
2. 为什么要使用内部类?
利用内部类提供的继承多个具体的或者抽象的类的能力来解决使用接口无法解决的程序设计问题。
注意:内部类是个编译时的概念,编译成功后,它就与外围类属于两个完全不同的类(当然它们之间还是有联系的)。对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现两个class文件:OuterClass.class和OuterClass$InnerClass.class。
3. 四种内部类
一、成员内部类
成员内部类是外围类的一个成员,可以无限制的访问外围类的所有成员属性和方法(即使是private),但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。
注意:
- 成员内部类中不能存在任何static的变量和方法。
- 要先创建外围类才能够创建成员内部类。
public class OuterClass {
private String str;
public void outerDisplay(){
System.out.println("Hello world!");
}
public class InnerClass{
public void innerDisplay(){
//使用外围内的属性
str = "skr";
System.out.println(str);
//使用外围内的方法
outerDisplay();
}
}
/*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */
public InnerClass getInnerClass(){
return new InnerClass();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.getInnerClass();
inner.innerDisplay();
}
}
//输出
skr
Hello world!
二、局部内部类
局部内部类主要是应用与解决比较复杂的问题,创建一个类来辅助我们的解决方案,但同时又不希望这个类是公共的。
//略
三、3.匿名内部类
匿名内部类创建方式:
new 父类构造器(参数列表)|实现接口()
{
//匿名内部类的类体部分
}
public class OuterClass {
public InnerClass getInnerClass(final int num, String str) {
return new InnerClass() {
int number = num + 3;
@Override
public int getNumber() {
return number;
}
}; /* 注意:分号不能省 */
}
public static void main(String[] args) {
OuterClass out = new OuterClass();
InnerClass inner = out.getInnerClass(2, "skr");
System.out.println(inner.getNumber());
}
}
interface InnerClass {
int getNumber();
}
//输出
5
public class Outer {
public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = outer.getInner("Inner", "hangzhou");
System.out.println(inner.getName());
}
public Inner getInner(final String name, String city) {
return new Inner(name, city) {
private String nameStr = name;
@Override
public String getName() {
return nameStr;
}
};
}
}
abstract class Inner {
Inner(String name, String city) {
System.out.println(city);
}
abstract String getName();
}
//输出
hangzhou
Inner
注意点:
- 使用匿名内部类时,我们必须是继承一个类或者实现一个接口。
- 匿名内部类中不能定义构造函数。
- 匿名内部类中不能存在任何的静态成员变量和静态方法。
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
- 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
当所在方法的形参要在内部类被使用时,该形参必须要是final。(java 8可以不写,默认会加上final)
内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器进行备份,内部类方法调用的实际是自己的属性而不是外部类方法的参数。简单而言,是为避免引用值发生改变,如果内部类修改该值不会影响到原参数。
四、静态内部类
使用static修饰的内部类我们称之为静态内部类。
public class OuterClass {
private String sex;
public static String name = "qlq";
/**
* 静态内部类
*/
static class InnerClass1 {
/* 在静态内部类中可以存在静态成员 */
public static String _name1 = "qlq_static";
public void display() {
/*
* 静态内部类只能访问外围类的静态成员变量和方法
* 不能访问外围类的非静态成员变量和方法
*/
System.out.println("OutClass name :" + name);
}
}
/**
* 非静态内部类
*/
class InnerClass2 {
/* 非静态内部类中不能存在静态成员 */
public String _name2 = "qlq_inner";
/* 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的 */
public void display() {
System.out.println("OuterClass name:" + name);
}
}
public void display() {
/* 外围类访问静态内部类:内部类. */
System.out.println(InnerClass1._name1);
/* 静态内部类 可以直接创建实例不需要依赖于外围类 */
new InnerClass1().display();
/* 非静态内部的创建需要依赖于外围类 */
OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
/* 方位非静态内部类的成员需要使用非静态内部类的实例 */
System.out.println(inner2._name2);
inner2.display();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display();
}
}
注意点:
- 静态内部类的创建是不依赖外围类。
- 静态内部类不能使用任何外围类的非static成员变量和方法。
讲的比较浅显,最好能够自己动手敲下代码,会对内部类有更好的理解。