内部类
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
一、成员内部类
- 定义格式
修饰符 class 外部类名称{
修饰符 class 内部类名称{
//...
}
//...
}
- 成员内部类的使用
间接方式:在外部类的方法中使用内类,需要新建一个内部类对象
public class Body { //外部类
public class Heart { //成员内部类
//内部类的方法
public void beat() {
System.out.println("心脏跳动");
System.out.println("我叫:" + name);
}
}
//外部类的成员变量
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//外部类的方法
public void methodBody() {
System.out.println("外部类的方法");
new Heart().beat();
}
}
直接方式:外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
public static void main(String[] args) {
Body body = new Body();
//通过外部类的对象,调用外部类的方法,里面间接在使用内部类Heart
body.methodBody();
//直接方式
Body.Heart heart = new Body().new Heart();
heart.beat();
}
- 注意事项
1、当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
public class Outer {
int num = 10;
public class Inner{
int num = 20;
public void methodInner(){
int num = 30;
System.out.println(num); //局部变量,就近原则
System.out.println(this.num);//内部类的成员变量
System.out.println(Outer.this.num);//外部类的成员变量
}
}
}
2、内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上面的例子,如果成员内部类Inner用private修饰,则只能在外部类的内部访问,如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。
二、局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
- 格式:
修饰符 class 外部类名称{
修饰符 返回值类型 外部类方法名称(参数列表){
class 局部内部类名称{
//...
}
}
}
- 使用局部内部类
public class Outer {
public void methodOuter() {
class Inner {
int num = 10;
public void methodInner() {
System.out.println(num);
}
}
new Inner().methodInner();
}
}
- 注意事项
局部内部类访问的局部变量必须是【有效final的】,从JDK1.8开始,局内内部类访问局部变量可以省略final修饰符。
原因:用final修饰实际上就是为了保护数据的一致性。如果不使用final的话,局部变量的值可以发生改变,一旦发生改变,匿名内部类是不知道的,因为他只是拷贝了局部变量的值(可以通过反编译看到,其实局部内部类可以访问局部变量是因为在底层他的构造方法中会传局部变量的值,也就是说局部变量会成为该内部类的一个数据成员),并不是直接使用的局部变量。
三、匿名内部类
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,那么这种情况下就可以省略该类的定义,改为匿名内部类
- 格式
接口名称 对象名 = new 接口名称(){
//覆盖重写接口中所有抽象方法
};
- 匿名内部类的使用
public interface MyInterface {
void method();
void methodB();
}
public class MyInterfaceImpl implements MyInterface {
@Override
public void method() {
System.out.println("实现类覆盖重写了方法");
}
@Override
public void methodB() {
System.out.println("匿名内部类实现类方法222");
}
}
public static void main(String[] args) {
//使用匿名内部类
MyInterface obj = new MyInterface() {
@Override
public void method() {
System.out.println("匿名内部类实现类方法");
}
@Override
public void methodB() {
System.out.println("匿名内部类实现类方法222");
}
};
obj.method();
obj.methodB();
System.out.println("======================================");
new MyInterface() {
@Override
public void method() {
System.out.println("1111");
}
@Override
public void methodB() {
System.out.println("2222");
}
}.methodB();//因为匿名对象无法调用第二次方法,所以需要再创建一个匿名内部类的匿名对象
}
四、静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}
五、内部类的好处
1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整。
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序。
4.方便编写线程代码。
内部类关于信息的隐藏:
从这段代码里面我只知道OuterClass的getInner()方法能返回一个InnerInterface接口实例但我并不知道这个实例是这么实现的。
而且由于InnerClass是private的,所以我们如果不看代码的话根本看不到这个具体类的名字,所以说它可以很好的实现隐藏。
public interface InnerInterface {
void innerMethod();
}
/**
* 实现信息隐藏
*/
public class OuterClass {
/**
* private修饰内部类,实现信息隐藏
*/
private class InnerClass implements InnerInterface {
@Override
public void innerMethod() {
System.out.println("实现内部类隐藏");
}
}
public InnerInterface getInner() {
return new InnerClass();
}
}
public class Test {
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
InnerInterface inner = outerClass.getInner();
inner.innerMethod();
}
}
参考博文:
https://www.cnblogs.com/dolphin0520/p/3811445.html
https://blog.youkuaiyun.com/u013728021/article/details/87358517