Java 内部类
一、概述
java类除了我们常见的,直接定义在java文件中的之外,还有一种定义在类内部的类被称为内部类。内部类包括四种:成员内部类、局部内部类、匿名内部类和静态内部类。
二、成员内部类
成员内部类是最普通的内部类,其定义在另一个类的内部。成员内部类可以定义费静态的属性和方法,不可以定义静态属性和方法,也不可以定义静态代码块,但可以定义static final类型的属性。内部类是外部类的成员,只有当外部类初始化的时候,内部类才会初始化。
内部类的创建
不可以直接使用构造方法创建内部类,只能通过外部类的实例对象来创建内部类
Outer o = new Outer();
Inner i = o.new Inner();
内部类访问外部类
内部类可以直接访问外部类的数据,且不受访问控制符限制,访问时可以直接通过属性名访问,也可以通过外部类.this.属性访问
class Outer{
public String strOuter = "123";
class Inner{
public String strInner = "456"
public void print(){
System.Out.Println(strOuter);
System.Out.Println(Outer.this.strOuter);
}
}
}
外部类访问内部类
外部类不可以直接访问内部类的成员,必须先创建一个内部类的实例才能访问,通过创建一个实例,外部类也能访问内部类的私有属性。外部类可以通过内部类的类名直接访问内部类的常量
//外部类的方法
public void printInner(){
System.out.println(new Inner().strInner);
}
内部类与外部类的冲突
内部类可以拥有与外部类同样的属性名与方法名,当内部类的属性和外部类重名时,内部类可以直接访问自己的属性,但访问外部类的属性则需要使用外部类.this.属性名(或方法)
成员内部类实例
public class Test<T> {
public static void main(String[] args) {
Outer o = new Outer();
Outer.Inner i = o.new Inner();
o.printInner();
i.printOuter();
}
}
class Outer{
public String strOuter = "123";
public String str = "abc";
public void printInner(){
System.out.println("Outer.printInner");
System.out.println(str);
System.out.println(new Inner().str);
System.out.println(new Inner().strInner);
}
public class Inner{
public String strInner = "456";
public String str = "def";
public void printOuter(){
System.out.println("Inner.printOuter");
System.out.println(str);
System.out.println(Outer.this.str);
System.out.println(strOuter);
}
}
}
运行结果:
Outer.printInner
abc
def
456
Inner.printOuter
def
abc
123
三、局部内部类
局部内部类简单点说就是在一个外部类的成员方法中定义的类。局部内部类不允许使用任何访问修饰符修饰,只在方法体中有效,在外部类中也不能创建一个局部内部类的实例,也不能访问局部内部类,只能在定义内部类的方法体中访问。局部内部类中不能包含static成员,但可以包含final static成员。局部内部类可以嵌套。
局部内部类访问外部类
局部内部类可以访问外部类中的所有成员,不受访问控制符的限制。
class Outer{
String id = "Outer";
public void fun(){
class Inner{
String outer = id;
public void fun2(){
System.out.println(outer);
}
}
Inner inner = new Inner();
inner.fun2();
}
}
调用fun后输出为Outer
命名冲突
如果内部类的成员或方法与外部类的同名,那么在内部类中直接使用该属性时默认访问内部类的属性,若需要访问外部类的属性则须使用外部类.this.属性名
class Outer{
String id = "Outer";
public void fun(){
class Inner{
String id = "Inner";
public void print(){
System.out.println(id);
System.out.println(Outer.this.id);
}
}
Inner inner = new Inner();
System.out.println(id);
System.out.println(inner.id);
inner.print();
}
}
Outer
Inner
Inner
Outer
四、匿名内部类
简单说匿名内部类就是没有名字的类,既然没有名称,也就意味着不能再其他地方引用,不能实例化,没有构造器,因而只能使用一次。匿名内部类的属性和方法都不能是static匿名内部类可以访问外部类的成员变量和方法。在写事件监听器的时候经常会使用匿名内部类
匿名内部类创建与使用
匿名内部类必须在存在继承或实现的情况下使用。
//继承于抽象类的匿名内部类
abstract class person{
String career;
}
class Outer{
public void fun(){
new person(){
public void printCareer(){
career = "学生";
System.out.println(career);
}
}.printCareer();
}
}
interface person{public void printCareer();}
class Outer{
public void fun(){
new person(){
public void printCareer(){
String career = "学生";
System.out.println(career);
}
}.printCareer();
}
}
这是最简单的只有一个方法的匿名内部类,那么如果我们要调用匿名内部类的多个方法呢?第一种方法时利用多态,但是必须要保证父类或接口中已经声明了要调用的方法
abstract class person{
String career;
public abstract void setCareer();
public abstract void printCareer();
}
class Outer{
public void fun(){
person student = new person(){
public void setCareer(){
career = "学生";
}
public void printCareer(){
System.out.println(career);
}
};
student.setCareer();
student.printCareer();
}
}
第二种方法是将父类的方法返回类型改为this,这样就可以直接调用多个方法
abstract class person{
String career;
public abstract person setCareer();
public abstract person printCareer();
}
class Outer{
public void fun(){
new person(){
public person setCareer(){
career = "学生";
return this;
}
public person printCareer(){
System.out.println(career);
return this;
}
}.setCareer().printCareer();
}
}
五、静态内部类
用static关键词修饰的内部类即为静态内部类,其和类属性一样,属于外部类本身,而不属于外部类的任何一个对象。静态内部类中可以包含静态成员也可以包含费静态成员,但在非静态内部类中不可以声明静态成员。静态内部类只可以访问外部类的类属性,不可以访问外部类的实例属性。外部类不可以为静态类。
静态内部类的创建与使用
public class Test<T> {
public static void main(String[] args) {
Outer.inner inner = new Outer.inner();
inner.print();
}
}
class Outer{
public static class inner{
String id = "Inner";
public void print(){
System.out.println(id);
}
}
}
输出Inner
六、内部类的优点
1、每个内部类都都可以独立实现一个接口,因此无论外部类是否实现了某个接口,都不影响内部类对接口的实现,使得多继承的解决方案变得完整
2、便于将存在一定关系的类组织在一起,且能对外界隐藏实现
3、便于事件驱动程序的实现
4、便于多线程的编写