内部类是指在一个外部类的内部再定义一个类。
内部类的作用:
1). 内部类可以很好的实现隐藏,也就是封装性。一般的非内部类,是不允许有 private 与protected权限的,但内部类可以
2). 内部类可以直接访问外部类的所有属性和方法,即使是private修饰的
3). 可以实现多重继承
4). 可以不修改接口而实现同一个类中有两个同名方法
一、成员内部类(外部类的成员变量)
说明:编译之后,内部类字节码文件是:Outer$Inner.class
1)内部类可以直接访问外部类中的私有属性。实际上内部类已经破坏了一个类的基本结构,因为类是由属性及方法组成的,这是内部类的缺点;内部类可以直接访问外部类中的私有属性,这是其最大的优点
package com.wbf.test1;
class Outer{
private String info = "hello world!!!";//外部类的私有属性
class Inner{
public void print(){
System.out.println(info);//直接访问外部类的私有属性
}
};
public void fun(){
new Inner().print();//内部类的实例化对象调用自身的方法
}
};
public class InnerClassDemo01 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.fun();
}
}
2)一个内部类除了可以通过外部类访问,也可以直接在其他类中进行调用
package com.wbf.test3;
class Outer{
private String info = "hello world!!!";//外部类的私有属性
class Inner{
public void print(){
System.out.println(info);//直接访问外部类的私有属性
}
};
};
public class InnerClassDemo03 {
public static void main(String[] args) {
/*
Outer.Inner in = new Outer.Inner();//error, No enclosing instance of type Outer is accessible, 必须先有Outer类的实例
in.print();
*/
Outer out = new Outer();
Outer.Inner in = out.new Inner();
in.print();
}
}
一个内部类除了可以通过外部类访问,也可以直接在其他类中进行调用
格式:外部类.内部类 内部类对象 = 外部类实例.new 内部类();
以上的格式中,首先要找到外部类的实例化对象之后,才可以通过外部类的实例化对象去实例化内部类的对象
注意:此时的Inner类非static
如果Inner类用static修饰,那么在类加载的之后,对于Outer类来说,即使没有Outer类的实例化对象,Inner这个成员变量已经存在
反之,Inner类没有用static修饰,那么在没有Outer类实例化对象的情况下,对于Outer类来说,Inner这个成员变量根本就不存在,此时要直接实例化Inner,肯定是不行的
所以在一般情况下,当先有外部类的实例化对象之后,再通过外部类的对象去实例化内部类
三、静态内部类(用static声明内部类)
说明:静态内部类和普通的内部类一个区别:普通内部类不能有static方法和static属性,也不能包含静态内部类,但静态内部类可以。而静态内部类不能声明为private,一般声明为public,方便调用。编译之后,内部类字节码文件是:Outer$Inner.class
package com.wbf.test2;
class Outer{
private static String info = "hello world!!!";//外部类的私有属性
static class Inner{
public void print(){
System.out.println(info);//直接访问外部类的私有属性,同时这里info属性用static修饰
}
};
};
public class InnerClassDemo02 {
public static void main(String[] args) {
new Outer.Inner().print();//通过new Outer.Inner()来实例化内部类,同时调用内部类的方法
/*
Outer.Inner in = new Outer.Inner();
in.print();
*/
}
}
static可以声明属性或方法,而是用static也可以声明内部类
用static声明的内部类成为外部类,但是用static声明的内部类不能访问外部类的非static属性
四、局部内部类(在方法中定义内部类)
说明:编译之后,内部类字节码文件是:Outer$1Inner.class
package com.wbf.test4;
class Outer{
private String info = "hello world!!!";//外部类的私有属性
public void fun(final int temp){
class Inner{
public void print(){
System.out.println("方法中的参数: " + temp);//访问方法中的final参数
System.out.println("类中的属性: " + info);//直接访问外部类的私有属性
}
};
new Inner().print();
}
};
public class InnerClassDemo04 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.fun(20);
}
}
可以在一个方法中定义一个内部类,但是在方法中定义的内部类不能够直接访问方法中的参数;如果方法中的参数要想被内部类所访问,则参数前必须加上final关键字
五、匿名内部类
说明:编译之后,内部类字节码文件是:X$1.class
1)未使用匿名内部类
package com.wbf.test5;
interface A {
public void printInfo();
}
class B implements A {
public void printInfo(){
System.out.println("hello world!!!");
}
}
class X {
public void fun1(){
this.fun2(new B());
}
public void fun2(A a){
a.printInfo();
}
}
public class AnonymousInnerClassDemo {
public static void main(String[] args) {
new X().fun1();
}
}
但是现在如果接口的实现类B只使用一次,那么还有必要单独定义一个子类B吗?很明显没有必要,所以此时就要使用匿名内部类完成
2)使用匿名内部类
package com.wbf.test6;
interface A {
public void printInfo();
}
class X {
public void fun1(){
this.fun2(new A(){//匿名内部类
public void printInfo(){//实现接口中的抽象方法
System.out.println("hello world!!!");
}
});
}
public void fun2(A a){
a.printInfo();
}
}
public class AnonymousInnerClassDemo {
public static void main(String[] args) {
new X().fun1();
}
}
六、Java通过内部类变相实现多重继承
package com.wbf.test7;
abstract class Father{
public abstract void run();
};
abstract class Mother{
public abstract void say();
};
class Son extends Father{
public void run(){
System.out.println("running...");
}
Mother getMother(){
return new Mother(){
public void say(){
System.out.println("saying...");
}
};
}
};
public class DuplicateExtendsDemo {
public static void main(String[] args) {
Son s = new Son();
s.run();
s.getMother().say();
}
}