Java内部类
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,但是如果我们不需要解决多重继承问题,那么我们自然可以使用其它的编码方式,但是使用内部类还能够为我们带来如下特性:
- 内部类可以使用多个实例,每个实例都有自己的状态信息,并且与其它外围对象的信息相互独立
- 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口或者继承同一个类
- 创建内部类对象的时刻并不依赖于外围类对象的创建
- 内部类并没有令人迷惑的“is-a”关系,它就是一个独立的实体
- 内部类提供了更好的封装,除了该外围类,其它类都不能访问
内部类包括四种:成员内部类,静态内部类,局部内部类和匿名内部类。
成员内部类
成员内部类是最普通的内部类,它的定义为位于另一个类的内部,例如:
public class Example {
//外部类费静态方法
public void exampleMethod() {
System.out.println("外部类方法");
//外部类调用内部类方法 必须先创建内部类对象
Inner inner = new Inner();
inner.innerMethod();
}
//内部类
class Inner {
//内部类非静态方法
public void innerMethod() {
//内部类调用外部类费静态方法
// Example.this.exampleMethod();
//如果没有相同的方法 可以省略前缀
exampleMethod();
}
}
}
观看例子:可以知道,内部类可以直接访问外部类的成员,包括私有(外部类民.this.成员),外部类调用内部类方法,必须先创建对象(内部类 对象名 = new 内部类())。
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方法:
public class Operation {
public static void main(String[] args) {
//创建内部类对象,必须先创建外部类对象
Example.Inner inner = new Example().new Inner();
//调用内部类的方法
inner.innerMethod();
}
}
内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上面的例子,如果成员内部类 Inner用private修饰,则只能在外部类的内部访问,如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。这也点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。由于成员内部类看起来像是一个外部类的一个成员,所以可以像类的成员一样有用多种权限修饰。
public class Example {
//外部类费静态方法
public void exampleMethod() {
//私有的内部类只能在外部类中使用
Inner inner = new Inner();
inner.innerMethod();
}
//只能在内部使用
private class Inner {
//内部类非静态方法
public void innerMethod() {
System.out.println("静态内部类的非静态方法");
}
}
public static void main(String[] args) {
Example.Inner inner = new Example().new Inner();
}
}
静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
静态内部类的使用
-调用静态内部类内部的非静态方法
//外部类名.内部类名 对象名 = new 外部类名.内部类名()
public class Example {
//静态内部类
public static class Inner {
//静态内部类的非静态方法
public void innerMethod() {
System.out.println("调用内部类的非静态成员方法");
}
}
}
public static void main(String[] args) {
//创建内部类对象
Example.Inner inner = new Example.Inner();
//调用内部类的方法
inner.innerMethod();
}
- 调用静态内部类内部的静态方法
//外部类名.内部类名.方法()
public class Example {
//静态内部类
public static class Inner {
//静态内部类的静态方法
public static void innerMethod() {
System.out.print("静态内部类的静态方法");
}
}
}
public static void main(String[] args) {
//类名调用
Example.Inner.innerMethod();
}
-静态内部类调用外部类的非静态方法
public class Example {
//外部类的非静态方法
public void exampleMethod() {
System.out.print("外部类的非静态方法");
}
//静态内部类
public static class Inner {
//静态内部类的非静态方法
public void innerMethod() {
//必须先创建外部类的对象
new Example().exampleMethod();
}
}
}
public static void main(String[] args) {
Example.Inner inner = new Example.Inner();
inner.innerMethod();
}
注意事项:
- 内部类中如果有静态方法,那么内部类就必须也是静态的
- 内部类是静态的,并不意味着内部类中的方法都是静态的,只是说明我们可以绕过外部类对象直接找到内部类来使用
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。
局部内部类在访问它所在方法中的局部变量必须用final修饰——因为当调用这个方法时,局部变量如果没有用final修饰,它的生命周期和方法的生命周期是一样的,当这个方法出栈之后,这个局部变量也会消失,那么如果局部变量类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法出栈,常量池的常量还在,也可以继续使用(jdk1.8取消了这个定义,其实不是取消,是设置为了隐式的)
public static void main(String[] args) {
//局部内部类使用局部变量必须是final的
final String name = "小红";
int age = 18;
//局部内部类
class Inner {
public void method() {
System.out.println(age);
age = 20; //报错
}
public String method2() {
return name + "我爱你";
}
}
Inner inner = new Inner();
inner.method();
System.out.println(inner.method2());
}
匿名内部类
匿名内部类应该是平时我们编写代码时用的最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。
public void method() {
//匿名内部类的位置在方法内
//匿名内部类必须要有个父类
//匿名内部类就是类使用时的最简形式
//多用在这个类只使用一次的情况下
new 父类名或者接口 {
}
//只有大括号是匿名内部类
}
// new的是什么,就可以使用用父类或者接口来调用该匿名内部类中的成员