Java内部类和匿名内部类的用法

Posted 小布丁value

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java内部类和匿名内部类的用法相关的知识,希望对你有一定的参考价值。

Java内部类和匿名内部类的用法
思考?内部类如何使用?静态内部类相比于实例内部类的开销2222222222
一、内部类:
为什么会有内部类?
1.若内部类无同名方法可以直接调用外部类的方法。
2. 如果内部类有同名方法必须使用"OuterClass.this.MethodName()格式调用(**其中OuterClass与MethodName换成实际外部类名及其方法;this为关键字,表示对外部类的引用);
3. 但外围类无法直接调用内部类的private方法,外部类同样无法直接调用其它类的private方法。注意:内部类直接使用外部类的方法与该方法的权限与是否static无关,它取决于内部类是否有同名方法。

public class OuterClass {
        private void outerMethod() {
            System.out.println("It's Method of OuterClass");
        }
        public static void main(String[] args) {
            OuterClass t = new OuterClass();
            OuterClass.Innerclass in = t.new Innerclass();
            in.innerMethod();
        }
        class Innerclass {
            public void innerMethod() {
                OuterClass.this.outerMethod();// 内部类成员方法与外部类成员方法同名时,使用this调用外部类的方法
                outerMethod();// 内部类没有同名方法时执行外部类的方法
            }
            private void outerMethod() {
                System.out.println("It's Method of Innerclass");
            }
        }
    }

运行结果:
It’s Method of OuterClass
It’s Method of Innerclass
(2)内部类访问外部类的变量必须声明为final

  1. 方法中的局部变量,方法结束后这个变量就要释放掉,final保证这个变量始终指向一个对象。
  2. 首先,内部类和外部类其实是处于同一个级别,内部类不会因为定义在方法中就会随着方法的执行完毕而跟随者被销毁.
  3. 问题就来了如果外部类的方法中的变量不定义final那么当外部类方法执行完毕的时候,这个局部变量肯定也就被GC了,然而内部类的某个方法还没有执行完,这个时候他所引用的外部变量已经找不到了。
  4. 如果定义为final,java会将这个变量复制一份作为成员变量内置于内部类中,这样的话,由于final所修饰的值始终无法改变,所以这个变量所指向的内存区域就不会变。
 public class OuterClass {
	int num1 = 0;// 成员变量
    private void outerMethod() {
		int num2 = 0;// 方法内的局部变量
		class Innerclass_1 {
			public void innerMethod() {
				System.out.println(num1);// 方法中内部类的方法,可以正常访问外部类的成员变量
				System.out.println(num2);// JDK1.8以前,方法中内部类的方法,不能直接访问外部类的方法的局部变量,必须声明为final
			}
		}
	}
}

如果使用JDK1.8以前的版本,Eclipse会出现如下错误提示:
在这里插入图片描述
(3)内部类的实例化
内部类实例化不同于普通类,普通类可以在任意需要的时候实例化,而内部类必须在外层类实例化以后方可实例化,并与外部类建立关系
因此在外部类中的非static方法中,是可以实例化内部类对象

	private void outerMethod() {
		System.out.println("It's Method of OuterClass");
		Innerclass in = new Innerclass();//在外部类的outerMethod方法中实例化内部类是可以啊
	}

但在static方法中,就要注意啦!!!! 不能在static方法中直接new内部类,否则出现错误:
No enclosing instance of type OuterClass is accessible. Must qualify the allocation with an enclosing instance of type OuterClass (e.g. x.new A() where x is an instance of OuterClass).
这是因为静态方法是在类实例化之前就可以使用的,通过类名调用,这时动态内部类都还没实例化呢,怎么用,总不能调用一个不存在的东西吧。
如果想在Static方法中new内部类,可以把内部类声明为Static

public class OuterClass {
	private void outerMethod() {
		System.out.println("It's Method of OuterClass");
	}
 
	public static void main(String[] args) {
		Innerclass in = new Innerclass();
		in.innerMethod();
	}
 
	static class Innerclass {//把内部类声明为static
		public void innerMethod() {
			System.out.println("It's Method of innerMethod");
 
		}
	}
 
}

当然,一般不使用static的方式,而是推荐这种方法:x.new A() ,其中 x是外部类OuterClass的实例,A是内部类Innerclass

package innerclass;
public class OuterClass {
	private void outerMethod() {
		System.out.println("It's Method of OuterClass");
	}
	public static void main(String[] args) {
		OuterClass.Innerclass in = new OuterClass().new Innerclass();//使用x.new A()的方式
		in.innerMethod();
	}
	class Innerclass {
		public void innerMethod() {
			System.out.println("It's Method of innerMethod");
		}
	}
}

x.new A() ,其中 x是外部类OuterClass的实例,A是类部类Innerclass,当然可以拆分如下,这样就显然很明白啦:

public static void main(String[] args) {
  OuterClass out = new OuterClass();//外部实例
  OuterClass.Innerclass in = out.new Innerclass();//外部实例.new 外部类
  in.innerMethod();
}

4)什么情况下使用内部类
1.内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外层类的对象。所以你可以认为内部类提供了某种进
入其外层类的窗口。
2.使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外层类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。
(5)在静态方法中实例化内部类例子:(内部类放在静态方法中

package javatest2;
public class JavaTest2 {
	public static void main(String[] args) {
		class Boy implements Person {
			public void say() {// 匿名内部类自定义的方法say
				System.out.println("say方法调用");
			}
			@Override
			public void speak() {// 实现接口的的方法speak
				System.out.println("speak方法调用");
			}
		}
		Person per = new Boy();
		per.speak();// 可调用
		per.say();// 不能调用
	}
}
interface Person {
	public void speak();
}

font color=per.speak()可调用,而per.say()不能调用,这时因为per是Person对象,要想调用子类的方法,可以强制向下转型为:((Boy) per).say();或者直接改为Boy per = new Boy();。 从中可发现,要想调用内部类的自定义的方法,必须通过内部类的对象来调用。那么,匿名内部类连名字都没有,怎么调用内部类自定义的方法?
(二)匿名内部类
1, 匿名内部类也就是没有名字的内部类正因为没有名字
2.所以匿名内部类只能使用一次,它通常用来简化代码编写,但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口,但最多只能继承一个父类,或实现一个接口。
关于匿名内部类还有如下两条规则:
1)匿名内部类不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建内部类的对象。因此不允许将匿名内部类定义成抽象类。
2)匿名内部类不等定义构造器(构造方法),因为匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以定义实例初始化块
怎样判断一个匿名类的存在啊?看不见名字,感觉只是父类new出一个对象而已`,没有匿名类的名字。
先看段伪代码


class SonOne extends Father{
  ...       //这里的代码和上面匿名内部类,大括号中的代码是一样的
}
public class Test{
   Father f1 = new SonOne() ;
}

先看一个例子,体会一下匿名内部类的用法:在这里插入图片描述运行结果:eat something
可以看到,我们直接将抽象类Person中的方法在大括号中实现了,这样便可以省略一个类的书写。并且,匿名内部类还能用于接口上

public class JavaTest2 {
	public static void main(String[] args) {
		Person per = new Person() {
			public void say() {// 匿名内部类自定义的方法say
				System.out.println("say方法调用");
			}
			@Override
			public void speak() {// 实现接口的的方法speak
				System.out.println("speak方法调用");
			}
		};
		per.speak();// 可调用
		per.say();// 出错,不能调用
	}
}
 
interface Person {
	public void speak();
}

这里per.speak()是可以正常调用的,但per.say()不能调用,为什么呢?注意Person per = new Person()创建的是Person的对象,而非匿名内部类的对象。其实匿名内部类连名字都没有,你咋实例对象去调用它的方法呢?但继承父类的方法和实现的方法是可以正常调用的,本例子中,匿名内部类实现了接口Person的speak方法,因此可以借助Person的对象去调用。
若你确实想调用匿名内部类的自定义的方法say(),当然也有方法:
(1)类似于speak方法的使用,先在Person接口中声明say()方法,再在匿名内部类中覆写此方法。
(2)其实匿名内部类中隐含一个匿名对象,通过该方法可以直接调用say()和speak()方法;代码修改如下:


public class JavaTest2 {
	public static void main(String[] args) {
		new Person() {
			public void say() {// 匿名内部类自定义的方法say
				System.out.println("say方法调用");
			}
 
			@Override
			public void speak() {// 实现接口的的方法speak
				System.out.println("speak方法调用");
			}
		}.say();// 直接调用匿名内部类的方法
	}
}
interface Person {
	public void speak();
}

https://blog.csdn.net/guyuealian/article/details/51981163

以上是关于Java内部类和匿名内部类的用法的主要内容,如果未能解决你的问题,请参考以下文章

java内部类的匿名内部类

Java语言中四种内部类(成员内部类,局部内部类,静态内部类,匿名内部类)在实际使用中有啥好处?

java内部类与匿名内部类作用分别是啥?

Java匿名内部类和Lambda表达式

该如何理解匿名内部类的功能?

java匿名内部类