OnJava8笔记5 -- 内部类
2020-04-19 本文已影响0人
给点阳光我就灿烂_ab56
内部类
一个定义在另一个类中的类,叫作内部类。
创建内部类
public class Parcel {
class Contents {
private int i = 11;
public int value() { return i; }
}
}
-
在Parcel之外的类中想要创建Contents对象,需要 Parcel.Contents ( OuterClassName.InnerClassName )
-
内部类自动拥有对其外围类所有成员和方法的访问权,即使是 private 的也可以。这是因为当内部类对象被创建时,一个外部类对象的引用被传递给这个内部类对象了。
-
普通内部类不能有 static 字段和方法
内部类中的 .this 和 .new
.this
- 在内部类中, *OuterClassName.this *(DotThis.this) 代表的是外部类对象的引用,单纯的 this 就是内部类对象的引用
.new
-
外部类对象.new 用于创建内部类对象
public class DotNew { public class Inner {} public static void main(String[] args) { DotNew dn = new DotNew(); DotNew.Inner dni = dn.new Inner(); } }
方法和作用域中的内部类
public class Parcel6 {
private void internalTracking(boolean b) {
if(b) {
class TrackingSlip {
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip() { return id; }
}
TrackingSlip ts = new TrackingSlip("slip");
String s = ts.getSlip();
}
// Can't use it here! Out of scope:
//- TrackingSlip ts = new TrackingSlip("x");
}
}
内部类只能在自己的作用域中能被使用
- 方法和作用域中的内部类使用的外部变量必须是final的
匿名内部类
public interface Contents {
int value();
}
public class Parcel7 {
public Contents contents() {
return new Contents() { // Insert class definition
private int i = 11;
@Override
public int value() { return i; }
}; // Semicolon required
}
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Contents c = p.contents();
}
}
在创建 Contents 对象代码之后插入一个类的声明,这个插入的类就是匿名类(没有具体名字)
- 这里可以看成创建了一个继承自 Contents 的匿名类对象,然后通过前面的 new 表达式将匿名类对象向上转型成 Contents 对象
- 匿名内部类中使用的外部变量必须是final 的
- 匿名内部类,因为是匿名的,不能显式声明构造函数
匿名内部类中的参数初始化
public class Parcel9 {
// Argument must be final or "effectively final"
// to use within the anonymous inner class:
public Destination destination(final String dest) {
return new Destination() {
private String label = dest;
@Override
public String readLabel() { return label; }
};
}
public static void main(String[] args) {
Parcel9 p = new Parcel9();
Destination d = p.destination("Tasmania");
}
}
可以看到第6行用到的外部变量是final的(jdk8之后不用明确写final了,但还是不能被改变)
为什么必须是final的? 参考知乎 胖君 的回答:https://www.zhihu.com/question/21395848
嵌套类
static类型的内部类叫做嵌套类。嵌套类对象没有指向外部创建他的类的对象引用
- 要创建嵌套类对象,不需要外部类对象
- 不能从嵌套类的对象中访问非静态外部类的对象
- 嵌套类可以包含 static 字段和方法
- 接口中的内部类自动是 public 和 static 的
为什么要使用内部类
-
最重要的原因是可以间接实现类的多继承
我们知道java中的类只能单继承,内部类可以间接实现多继承:
public class Demo1 { public String name() { return "BWH_Steven"; } } public class Demo2 { public String email() { return "xxx.@163.com"; } } public class MyDemo { private class test1 extends Demo1 { public String name() { return super.name(); } } private class test2 extends Demo2 { public String email() { return super.email(); } } public String name() { return new test1().name(); } public String email() { return new test2().email(); } public static void main(String args[]) { MyDemo md = new MyDemo(); System.out.println("我的姓名:" + md.name()); System.out.println("我的邮箱:" + md.email()); } }
在MyDemo类中书写了两个内部类,test1和test2 两者分别继承了Demo1和Demo2类,这样MyDemo中就间接的实现了多继承
-
使用匿名内部类实现回调功能(jdk8之后可以使用lambda表达式)
当有这么个需求,一个方法的参数是接口对象,因为接口不能生成对象,而单独写一个类来实现接口又太浪费(因为这个方法可能只会被使用一次),这时匿名内部类很容易实现这一需求interface Demo { void interfaceMethod(); } public class NiMingInnerClass { public void test(Demo demo) { demo.interfaceMethod(); } public static void main(String[] args) { NiMingInnerClass innerClass = new NiMingInnerClass(); innerClass.test(new Demo() { @Override public void interfaceMethod() { System.out.println("接口方法被调用了"); } }); } }
-
父类和接口中存在同名方法,而直接Override这个方法会导致只能保留一个方法,想要既保留继承自父类的实现,又保留接口中的方法,这时选择内部类很容易达到需求
interface Demo2 { void test(); } abstract class SupClass { public void test() { System.out.println("SupClass test()"); } } public class SameNameMethod extends SupClass { @Override public void test() { super.test(); System.out.println("SameNameMethod test()"); } private class InnerClass implements Demo2{ @Override public void test() { System.out.println("Demo2 test()"); } } public InnerClass getInner() { return new InnerClass(); } public static void main(String[] args) { SameNameMethod test = new SameNameMethod(); test.test(); test.getInner().test(); } }