package InnerClass;
public class InnerClassTest { //主类
public static void main(String[] args) {
OuterClass outer = new OuterClass(true);
}
}
package InnerClass;
public class OuterClass { //外部类
private boolean a;
OuterClass(boolean a){
this.a = a;
System.out.println("我是外部类!");
InnerClass inner = new InnerClass();
}
public class InnerClass{ //内部类
InnerClass(){
if(a) {
System.out.println("我是内部类!a:"+a);
}
}
}
}
1. 内部类的特殊语法规则:↓
外部类引用的正确语法:OuterClass.this
例如:
if(OuterClass.this.a) {
System.out.println("我是内部类!a:"+a);
}
反过来,也可以new内部类的构造器
正确语法:outerObject.new InnerClass();
例如:
OuterClass(boolean a){
this.a = a;
System.out.println("我是外部类!");
InnerClass inner = new InnerClass(); //←这里
}
外部类作用域外这样引用内部类:OuterClass.InnerClass
例如:
OuterClass.InnerClass inner = outer.new InnerClass();
2. 内部类是否有用、必要和安全
内部类是一种编译现象,虚拟机无关。编译器将会把内部类翻译成$(美元符号)分隔外部类名与内部类名的常规类文件。
3. 局部内部类
仔细看最上面的代码会发现InnerClass这个类只在OuterClass构造器中引用了一次
这种情况可以在一个构造函数(方法也可以)中定义一个局部类
例如:
OuterClass(boolean a){
this.a = a;
System.out.println("我是外部类!");
InnerClass inner = new InnerClass();
class LocalClass{
LocalClass(){
System.out.println("我是局部内部类");
}
}
LocalClass local = new LocalClass();
}
4. 外部方法访问变量
与其他类相比较,局部类还有一个优点。它不仅能访问包含它们的外部类,还能访问局部变量。不过那些局部变量都必须事实上为Final。这说明它们一旦赋值就不会改变。
这个一个b()方法:
public void b(boolean a) {
class LocalClass{
LocalClass(){
System.out.println("我是局部内部类"+**a**);
}
}
a = true;
LocalClass local = new LocalClass();
}
这个方法看着没什么问题,但是是错误的,局部类在访问a参数时提示了一个错误:
Local variable a defined in an enclosing scope must be final or effectively final
谷歌翻译:在封闭范围中定义的局部变量a必须是最终的或有效的最终
提示说局部变量a要是最终的或有效的最终,也就是变量a(其实a是b()方法的参数)不能改变,这也就说明了局部内部类访问的变量(参数)要设置为final。
正确的代码:
public void b(final boolean a) {
class LocalClass{
LocalClass(){
System.out.println("我是局部内部类"+a);
}
}
// a = true; a参数设置为final就不能有这句代码
LocalClass local = new LocalClass();
}
5. 匿名内部类
假如只创建这个类的一个对象,就不必命名了。这种类被称为匿名内部类(anonymous inner class)。
interface AnonymousInnerClass { //定义一个接口
void anonymous();
}
public void anonymousInnerClass() { //方法
AnonymousInnerClass a = new AnonymousInnerClass() { //方法中的匿名内部类
@Override
public void anonymous() {
System.out.println("匿名内部类");
}
};
a.anonymous();
}
通常格式为:
new SuperType(construction parameters){
inner class methods data
}
Supertype可以是一个接口也可以是一个类,于是内部类就要扩展它
由于构造器名必须与类名一致,而匿名内部类没有类名,所以匿名内部类没有构造函数。
取而代之的是,将构造器参数传递给超类构造器,尤其是在内部了实现接口时候,不能有任何构造参数。
多年来,java程序员习惯的做法是用匿名内部类实现事件监听和其他回调。如今最好还是用Lambdab表达式。
技巧:
双括号初始化,利用内部类语法
假如需要构造一个泛型类数组列表,并且传递到一份方法
ArrayList list = new ArrayList();
list.add("Hello");
list.add("World");
invite(list);
如果不在需要这个数组列表,最好让它作为一个匿名列表。
方法如下:
invite(new ArrayList() {{add("Hello");add("World");}});
6. 静态内部类
有时候,使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外部类对象。为此,可以将内部类声明为static,以便取消产生的引用。
静态内部类-比较两个数的大小:
package InnerClass;
public class StaticInnerClass {
public static void main(String[] args) {
ArrayAlg.minMax(15, 6);
}
}
class ArrayAlg{
public static class Pair{
Pair(int a,int b){
System.out.println("Max:"+(a>b?a:b));
System.out.println("Min:"+(a