目录
一.内部类概述:
二.内部类可以分为四种:
2.1成员内部类
2.1.1如何编写一个成员内部类呢?
2.1.2该如何创建内部类的对象?
2.1.3在内部类中该如何访问外部类中的成员呢?
2.2静态内部类
2.2.1如何来创建静态内部类?
2.3局部内部类
2.4匿名内部类(重点)
2.4.1如何定义匿名内部类?
2.4.2匿名内部类的特点包括:
2.4.3对匿名内部类进行小结:
是类的五大成分之一(成员变量,成员方法,构造器,内部类,代码块),如果在一个类内部定义一个类,这就是内部类。当一个类的内部,包含完整的事务,而这个事务又没有必要单独设计,就可以在内部定义一个类。比如,内部类是车的发动机,外部类是一整辆车,发动机可以在车的内部是一个完整的事务,但又没有必要单独设计出来。
代码如下:
public class InnerClass {
public static void main(String[] args) {
}
}
//外部类
class Outer{
//内部类
public class Inner{
}
}
成员内部类我们就可以直接简单的理解为是类中的成员的一种,类似成员变量,成员方法一样。
代码如下:
public class InnerClass {
public static void main(String[] args) {
Outer outer = new Outer();
outer.fun();
Outer.Inner inner = new Outer().new Inner();
inner.fun();
}
}
//外部类
class Outer{
public void fun(){
System.out.println("调用外部类的方法");
}
//内部类
public class Inner{
public void fun(){
System.out.println("调用内部类的方法");
}
}
}
在内部类中去访问外部类的成员就像类中的方法如何取访问的方式是一样的,直接去访问就行了。
代码如下:
public class InnerClass {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.fun();
}
}
//外部类
class Outer{
public String name = "lisi";
public void fun(){
System.out.println("调用外部类的方法");
}
//内部类
public class Inner{
public void fun(){
System.out.println(name);
System.out.println("调用内部类的方法");
}
}
}
如果在内部类中的成员变量与外部类的成员变量的名字一样的时候,内部类去输出这个变量那肯定是优先内部类的变量的值,因为就近原则嘛.
代码如下:
public class InnerClass {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.fun();
}
}
//外部类
class Outer{
public int age = 11;
public void fun(){
System.out.println("调用外部类的方法");
}
//内部类
public class Inner{
public int age = 14;
public void fun(){
System.out.println(age);
System.out.println("调用内部类的方法");
}
}
}
运行结果如下:
如果非得在这种情况下,访问外部类的成员变量呢?就可以在前面加上外部类名字.this.该变量名就可以访问到外部类的成员变量了。
代码如下:
public class InnerClass {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.fun();
}
}
//外部类
class Outer{
public int age = 11;
public void fun(){
System.out.println("调用外部类的方法");
}
//内部类
public class Inner{
public int age = 14;
public void fun(){
System.out.println(Outer.this.age);
System.out.println("调用内部类的方法");
}
}
}
运行结果:
同理成员方法道理也是一样的,如果内外类都没有相同名称的方法的前提下,就直接可以在内部类去调用外部类的方法。
代码如下:
public class InnerClass {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.fun();
}
}
//外部类
class Outer{
public int age = 11;
public void fun1(){
System.out.println("调用外部类的方法");
}
//内部类
public class Inner{
public int age = 14;
public void fun(){
System.out.println(Outer.this.age);
fun1();
System.out.println("调用内部类的方法");
}
}
}
如果内外类都有相同名称的方法的前提下,就可以在内部类用外部类名称.this.方法名,去调用外部类的方法。
代码如下:
public class InnerClass {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.fun();
}
}
//外部类
class Outer{
public int age = 11;
public void fun(){
System.out.println("调用外部类的方法");
}
//内部类
public class Inner{
public int age = 14;
public void fun(){
System.out.println(Outer.this.age);
Outer.this.fun();
System.out.println("调用内部类的方法");
}
}
}
运行结果如下:
在成员内部类的类名前面加上static修饰,静态内部类可以理解成静态方法,属于类的内部类,在计算机中只有一份,是公开的,共享的。可以直接访问外部类中的静态成员变量、静态方法。
代码如下:
public class InnerClass {
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner();
inner.fun();
}
}
class Outer{
public int age = 11;
public static String name = "lisi";
public static void fun1(){
System.out.println("调用外部类的方法");
}
//内部类
static public class Inner{
public int age = 14;
public void fun(){
System.out.println(name);
fun1();
System.out.println("调用内部类的方法");
}
}
}
以上代码的运行结果:
在静态内部类中可以直接去访问静态成员、静态方法,不能去访问实例成员变量、实例成员方法,还有我们在介绍成员内部类是可以访问在内部类与外部类出项相同名称的成员方法或者成员变量,通过外部类.this. 去访问外部类的成员,这没有问题。但是在静态内部类中根本不存在通过外部类.this. 去访问外部类的成员,想想嘛,内部类这是直接由类去访问的,没有通过创建实例对象去访问。
对于这个局部内部类简单了解就好了,局部内部类在定义在方法中、代码块中、构造器中等执行体中。
代码如下:
public class InnerClass {
public static void main(String[] args) {
class A{
public void fun(){
System.out.println("局部内部类");
}
}
A a = new A();
a.fun();
}
代码如下:
这个局部内部类看看就好,这个用得不多,就不多详解了。
为了更好的了解这个匿名内部类,在介绍匿名内部类之前,先设定一个情景,先定义一个接口Animal,有一个run()方法,再定义两个子类Dog,Cat分别重写接口的run方法,再用一个函数输出这两个重写的方法。
具体代码如下:
package AnonymousInnerClasses;
public class Text {
public static void main(String[] args) {
Animal animal1 = new Dog();
go(animal1);
Animal animal2 = new Cat();
go(animal2);
}
public static void go(Animal animal){
animal.run();
}
}
其实类似这段代码,我们并不陌生了吧,这段代码完完全全解释了多态的特性。我们是创建了两个对象,再把这两个对象被接口引用。接下来,介绍一下匿名内部类这个作用就是对以上代码的简化。特别是在需要实现某个接口或继承某个父类的情况下,可以直接在创建对象的地方实现相关的方法,避免了显式定义一个新的类。
通过new 接口名或者父类名 (){重写方法 } 方式来创建了一个类,且new了一个子类出来,用接口名或者父类名 自定义名字 = new 接口名或者父类名 (){重写方法 } 。总结,new 接口名或者父类名 (){重写方法 } 方式 一共干了两件事,一.创建了子类。二.new了一个子类的对象。
运用匿名内部类简化以上代码:
package AnonymousInnerClasses;
public class Text {
public static void main(String[] args) {
Animal animal1 = new Animal() {
@Override
public void run() {
System.out.println("狂狂地乱跑");
}
};
Animal animal2 = new Animal() {
@Override
public void run() {
System.out.println("优雅地走");
}
};
go(animal1);
go(animal2);
}
public static void go(Animal animal){
animal.run();
}
}
运行结果如下:
这个结果跟之前没有简化的结果是一样的,优点,减少了两个新类的定义了,但是通过new 接口名或者父类名 (){重写方法 } 方式是创建了一个类,可以反汇编看看这个类。
想来看看这个.class文件,一般来说一个类就会有一个.class文件。
这里“多出了”两个类吧,分别是Text$1.class Text$2.class,这就是通过new 接口名或者父类名 (){重写方法 } 方式是创建出来的。
再来具体看看里面的代码如下:
这是其中的一个.class文件的反汇编代码,怎么样?这是不是一个接口被类去实现了。所以,其实说那么多,就是为了知道通过new 接口名或者父类名 (){重写方法 } 这个方式是创建一个匿名类。
小结一下:匿名内部类是一种特殊的局部内部类,它没有显式的类名,只能在创建对象的时候定义并实现。匿名内部类通常用于创建一个只需要使用一次的类的实例,避免了显式定义一个新的类。